pn_shm_tool.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /*********************************************************************
  2. * _ _ _
  3. * _ __ | |_ _ | | __ _ | |__ ___
  4. * | '__|| __|(_)| | / _` || '_ \ / __|
  5. * | | | |_ _ | || (_| || |_) |\__ \
  6. * |_| \__|(_)|_| \__,_||_.__/ |___/
  7. *
  8. * www.rt-labs.com
  9. * Copyright 2021 rt-labs AB, Sweden.
  10. *
  11. * This software is dual-licensed under GPLv3 and a commercial
  12. * license. See the file LICENSE.md distributed with this software for
  13. * full license information.
  14. ********************************************************************/
  15. /* Linux application intended to be used
  16. * to read and write shared memory areas supported
  17. * by the lan9662 sample application.
  18. * See show_usage() for a functional description.
  19. */
  20. #include <getopt.h>
  21. #include <semaphore.h>
  22. #include <sys/mman.h>
  23. #include <sys/stat.h>
  24. #include <errno.h>
  25. #include <fcntl.h>
  26. #include <stdint.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <unistd.h>
  31. #define MAX_FILE_NAME 200
  32. #define MAX_STDIO_BUFFER 10000
  33. #define DEBUG_LOG (1)
  34. #if DEBUG_LOG == 1
  35. #define LOG_ERR(...) \
  36. fprintf (stderr, "Line:%d ", __LINE__); \
  37. fprintf (stderr, __VA_ARGS__);
  38. #else
  39. #define LOG_ERR(...)
  40. #endif
  41. typedef struct app
  42. {
  43. enum
  44. {
  45. UNDEFINED = 0,
  46. READ,
  47. WRITE,
  48. CREATE,
  49. READ_BIT
  50. } mode;
  51. char name[MAX_FILE_NAME]; /* Shared memory file name*/
  52. int fd; /* Shared memory file descriptor */
  53. caddr_t mem_address; /* Address of mapped shared memory */
  54. sem_t * sem; /* Named semaphore */
  55. size_t shm_size; /* The size of an existing shared memory area */
  56. size_t create_size; /* Size argument used when creating a shared memory
  57. area*/
  58. uint32_t bitnumber; /* Bit number to read */
  59. uint8_t buffer[MAX_STDIO_BUFFER];
  60. } app_t;
  61. static void show_usage (void)
  62. {
  63. printf ("\nTool for accessing shared memory files\n");
  64. printf ("Intended to be used in combination with the \n"
  65. "pn_lan9662 sample application. \n");
  66. printf ("Arguments:\n");
  67. printf (" -h Show help and exit\n");
  68. printf (
  69. " -r <shm_name> Read shared memory and write content to stdout \n");
  70. printf (" -w <shm_name> Write content on stdin to shared memory \n");
  71. printf (" -c <shm_name> Create shared memory area\n");
  72. printf (" -s <size> Size of shared memory, only used with create\n");
  73. printf (" -b <shm_name> Read bit from shared memory. Write '1' or '0' "
  74. "to stdout\n");
  75. printf (
  76. " -n <bitnumber> Bit number, only used with read bit. Defaults to\n");
  77. printf (
  78. " bit number 0 (least significant bit in first byte)\n");
  79. printf (
  80. "Partial write is allowed. Offsets are not supported. If write data\n");
  81. printf ("is larger than shared memory, data is truncated.\n");
  82. printf ("\nExample usage:\n");
  83. printf ("Read slot and passing data to hexdump:\n");
  84. printf ("pn_shm_tool -r pnet-in-1-1-digital_input_1x8 | hexdump -C\n");
  85. printf ("Write slot:\n");
  86. printf ("echo -n -e \"\\x02\" | pn_shm_tool -w "
  87. "pnet-in-1-1-digital_input_1x8\n");
  88. printf ("Create 4 bytes shared memory area (for testing this tool):\n");
  89. printf ("pn_shm_tool -c test_shm -s 4\n");
  90. }
  91. /**
  92. * Open an existing shared memory area
  93. * figure out its size and map it.
  94. * @param app InOut: Application context
  95. * @return 0 on success, -1 on error
  96. */
  97. int open_shm (app_t * app)
  98. {
  99. struct stat st;
  100. if (app->mode == CREATE)
  101. {
  102. return -1;
  103. }
  104. app->fd = shm_open (app->name, O_RDWR, 0666);
  105. if (app->fd < 0)
  106. {
  107. LOG_ERR ("\nFailed to open %s %s\n", app->name, strerror (errno));
  108. return -1;
  109. }
  110. if (fstat (app->fd, &st))
  111. {
  112. LOG_ERR ("\nfstat error: [%s]\n", strerror (errno));
  113. close (app->fd);
  114. return -1;
  115. }
  116. app->shm_size = st.st_size;
  117. if (ftruncate (app->fd, app->shm_size) != 0)
  118. {
  119. return -1;
  120. }
  121. app->mem_address =
  122. mmap (NULL, app->shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, app->fd, 0);
  123. if (app->mem_address == MAP_FAILED)
  124. {
  125. LOG_ERR ("\nmmap error: [%s]\n", strerror (errno));
  126. return -1;
  127. }
  128. app->sem = sem_open (app->name, 0, 0644, 1);
  129. if (app->sem == NULL)
  130. {
  131. LOG_ERR ("\nFailed to open semaphore: [%s]\n", strerror (errno));
  132. return -1;
  133. }
  134. return 0;
  135. }
  136. /**
  137. * Create a new shared memory area
  138. * @param app InOut: Application context
  139. * @return 0 on success, -1 on error
  140. */
  141. int create_shm (app_t * app)
  142. {
  143. if (app->mode != CREATE)
  144. {
  145. return -1;
  146. }
  147. app->fd = shm_open (app->name, O_RDWR | O_CREAT, 0666);
  148. if (app->fd < 0)
  149. {
  150. LOG_ERR ("\nFailed to create %s %s\n", app->name, strerror (errno));
  151. return -1;
  152. }
  153. if (ftruncate (app->fd, app->create_size) != 0)
  154. {
  155. return -1;
  156. }
  157. app->mem_address = mmap (
  158. NULL,
  159. app->create_size,
  160. PROT_READ | PROT_WRITE,
  161. MAP_SHARED,
  162. app->fd,
  163. 0);
  164. if (app->mem_address == MAP_FAILED)
  165. {
  166. LOG_ERR ("\nmmap error: [%s]\n", strerror (errno));
  167. return -1;
  168. }
  169. app->sem = sem_open (app->name, O_CREAT, 0644, 1);
  170. if (app->sem == NULL)
  171. {
  172. LOG_ERR ("\nFailed to open semaphore: [%s]\n", strerror (errno));
  173. return -1;
  174. }
  175. return 0;
  176. }
  177. /**
  178. * Close a shared memory area and its
  179. * open resources.
  180. * @param app InOut: Application context
  181. * @return 0 always
  182. */
  183. int close_shm (app_t * app)
  184. {
  185. if (app->mem_address != 0)
  186. {
  187. munmap (app->mem_address, app->shm_size);
  188. app->mem_address = 0;
  189. }
  190. if (app->fd >= 0)
  191. {
  192. close (app->fd);
  193. app->fd = -1;
  194. }
  195. if (app->sem != NULL)
  196. {
  197. sem_close (app->sem);
  198. app->sem = NULL;
  199. }
  200. return 0;
  201. }
  202. /**
  203. * Read a shared memory area and print its content
  204. * to STDOUT.
  205. * @param app InOut: Application context
  206. * @return 0 on success, -1 on error
  207. */
  208. int read_shm (app_t * app)
  209. {
  210. int write_len;
  211. if (sem_wait (app->sem) != 0)
  212. {
  213. LOG_ERR ("\nFailed to take semaphore: [%s]\n", strerror (errno));
  214. return -1;
  215. }
  216. memcpy (app->buffer, app->mem_address, app->shm_size);
  217. if (sem_post (app->sem) != 0)
  218. {
  219. LOG_ERR ("\nFailed to release semaphore: [%s]\n", strerror (errno));
  220. return -1;
  221. }
  222. write_len = write (STDOUT_FILENO, app->buffer, app->shm_size);
  223. if (write_len != (int)app->shm_size)
  224. {
  225. LOG_ERR ("\nFailed to write stdout\n");
  226. return -1;
  227. }
  228. return 0;
  229. }
  230. /**
  231. * Read a bit from shared memory area and print "0" or "1" to STDOUT.
  232. * @param app InOut: Application context
  233. * @return 0 on success, -1 on error
  234. */
  235. int read_bit_shm (app_t * app)
  236. {
  237. int write_len = 0;
  238. uint32_t byte_number = 0;
  239. uint8_t bitnumber_in_byte = 0;
  240. uint8_t byte_value = 0;
  241. uint8_t bit_value = 0;
  242. if (app->shm_size == 0)
  243. {
  244. LOG_ERR ("\nShared memory size is zero\n");
  245. return -1;
  246. }
  247. if (app->bitnumber >= MAX_STDIO_BUFFER * 8)
  248. {
  249. LOG_ERR (
  250. "\nToo large bitnumber. Given: %u (Buffer size %u bytes)\n",
  251. app->bitnumber,
  252. MAX_STDIO_BUFFER);
  253. return -1;
  254. }
  255. if (app->bitnumber >= app->shm_size * 8)
  256. {
  257. LOG_ERR (
  258. "\nToo large bitnumber. Given: %u (Memory size %zu bytes)\n",
  259. app->bitnumber,
  260. app->shm_size);
  261. return -1;
  262. }
  263. if (sem_wait (app->sem) != 0)
  264. {
  265. LOG_ERR ("\nFailed to take semaphore: [%s]\n", strerror (errno));
  266. return -1;
  267. }
  268. memcpy (app->buffer, app->mem_address, app->shm_size);
  269. if (sem_post (app->sem) != 0)
  270. {
  271. LOG_ERR ("\nFailed to release semaphore: [%s]\n", strerror (errno));
  272. return -1;
  273. }
  274. byte_number = app->bitnumber / 8; /* byte_number 0 is first */
  275. byte_value = app->buffer[byte_number];
  276. bitnumber_in_byte = app->bitnumber % 8;
  277. bit_value = (byte_value >> bitnumber_in_byte) & 0x01;
  278. write_len = write (STDOUT_FILENO, bit_value ? "1\n" : "0\n", 2);
  279. if (write_len != 2)
  280. {
  281. LOG_ERR ("\nFailed to write stdout\n");
  282. return -1;
  283. }
  284. return 0;
  285. }
  286. /**
  287. * Read STDIN and copy the data to shared memory area.
  288. * @param app InOut: Application context
  289. * @return 0 on success, -1 on error
  290. */
  291. int write_shm (app_t * app)
  292. {
  293. int len = read (STDIN_FILENO, app->buffer, app->shm_size);
  294. if (len > (int)app->shm_size)
  295. {
  296. /* Truncate len of data to match shared memory */
  297. len = app->shm_size;
  298. }
  299. if (len <= 0)
  300. {
  301. LOG_ERR ("\nFailed to read stdin: [%s]\n", strerror (errno));
  302. return -1;
  303. }
  304. if (sem_wait (app->sem) != 0)
  305. {
  306. LOG_ERR ("\nFailed to take semaphore: [%s]\n", strerror (errno));
  307. return -1;
  308. }
  309. memcpy (app->mem_address, app->buffer, len);
  310. if (sem_post (app->sem) != 0)
  311. {
  312. LOG_ERR ("\nFailed to release semaphore: [%s]\n", strerror (errno));
  313. return -1;
  314. }
  315. return 0;
  316. }
  317. /**
  318. * Execute a command given the configuration
  319. * set in the app variable.
  320. * Creation, read and write of shared memory regions
  321. * are supported.
  322. * @param app InOut: Application context
  323. * @return 0 on success, -1 on error
  324. */
  325. static int run (app_t * app)
  326. {
  327. int error = 0;
  328. if (app->mode == CREATE)
  329. {
  330. error = create_shm (app);
  331. close_shm (app);
  332. return error;
  333. }
  334. error = open_shm (app);
  335. if (!error)
  336. {
  337. if (app->mode == READ)
  338. {
  339. error = read_shm (app);
  340. }
  341. else if (app->mode == READ_BIT)
  342. {
  343. error = read_bit_shm (app);
  344. }
  345. else if (app->mode == WRITE)
  346. {
  347. error = write_shm (app);
  348. }
  349. error |= close_shm (app);
  350. }
  351. return error;
  352. }
  353. /**
  354. * Parse command line arguments and execute selected command.
  355. * @param argc In: Number of args
  356. * @param argv In: Arguments
  357. * @return 0 on success, 1 on error
  358. */
  359. int main (int argc, char * argv[])
  360. {
  361. int error = 0;
  362. int option = 0;
  363. app_t app = {0};
  364. if (argc < 2)
  365. {
  366. show_usage();
  367. exit (EXIT_FAILURE);
  368. }
  369. while ((option = getopt (argc, argv, "hw:r:c:s:b:n:")) != -1)
  370. {
  371. switch (option)
  372. {
  373. case 'r':
  374. if (app.mode != UNDEFINED)
  375. {
  376. show_usage();
  377. printf ("\nOnly one operation allowed\n");
  378. exit (EXIT_FAILURE);
  379. }
  380. strncpy (app.name, optarg, MAX_FILE_NAME - 1);
  381. app.mode = READ;
  382. break;
  383. case 'b':
  384. if (app.mode != UNDEFINED)
  385. {
  386. show_usage();
  387. printf ("\nOnly one operation allowed\n");
  388. exit (EXIT_FAILURE);
  389. }
  390. strncpy (app.name, optarg, MAX_FILE_NAME - 1);
  391. app.mode = READ_BIT;
  392. break;
  393. case 'w':
  394. if (app.mode != UNDEFINED)
  395. {
  396. show_usage();
  397. printf ("\nOnly one operation allowed\n");
  398. exit (EXIT_FAILURE);
  399. }
  400. strncpy (app.name, optarg, MAX_FILE_NAME - 1);
  401. app.mode = WRITE;
  402. break;
  403. case 'c':
  404. if (app.mode != UNDEFINED)
  405. {
  406. show_usage();
  407. printf ("\nOnly one operation allowed\n");
  408. exit (EXIT_FAILURE);
  409. }
  410. strncpy (app.name, optarg, MAX_FILE_NAME - 1);
  411. app.mode = CREATE;
  412. break;
  413. case 's':
  414. app.create_size = atoi (optarg);
  415. break;
  416. case 'n':
  417. app.bitnumber = atoi (optarg);
  418. break;
  419. case 'h':
  420. show_usage();
  421. exit (EXIT_SUCCESS);
  422. default:
  423. show_usage();
  424. exit (EXIT_FAILURE);
  425. }
  426. }
  427. if (app.mode == CREATE)
  428. {
  429. if (app.create_size <= 0 || app.create_size > MAX_STDIO_BUFFER)
  430. {
  431. show_usage();
  432. printf ("\nSize must be set when creating shared mem area\n");
  433. printf ("Min size 1, Max size %d\n", MAX_STDIO_BUFFER);
  434. exit (EXIT_FAILURE);
  435. }
  436. }
  437. error = run (&app);
  438. if (error != 0)
  439. {
  440. fprintf (stderr, "Operation failed.\n");
  441. exit (EXIT_FAILURE);
  442. }
  443. exit (EXIT_SUCCESS);
  444. }