RT_tunnel.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. #include "RT_tunnel.h"
  2. /* Error check macro: return -1 if pointer is NULL */
  3. #define ERROR_CHECK_PTR(ptr) \
  4. if ((ptr) == NULL) \
  5. { \
  6. LOG_ERROR("ptr is NULL"); \
  7. return PTR_ERROR_CODE; \
  8. }
  9. /* Error check macro: return 0 if tunnel operation state does not match */
  10. #define ERROR_CHECK_OPERATION(tunnel, op) \
  11. if ((tunnel->status & STATUS_OPERATION_Msk) != op) \
  12. { \
  13. LOG_ERROR("tunnel operation error"); \
  14. return OPERATION_ERROR_CODE; \
  15. }
  16. /* Error check macro: return 0 if tunnel is already in use */
  17. #define ERROR_CHECK_TUNNEL_USE(tunnel) \
  18. if ((tunnel->status & STATUS_USED_Msk) == STATUS_USED_BUSY) \
  19. { \
  20. return TUNNEL_BUSY_CODE; \
  21. }
  22. /* Atomic operation macro: set tunnel status to BUSY */
  23. #define TUNNEL_SET_BUSY(tunnel) \
  24. __atomic_or_fetch(&(tunnel->status), STATUS_USED_BUSY, __ATOMIC_SEQ_CST)
  25. /* Atomic operation macro: set tunnel status to IDLE */
  26. #define TUNNEL_SET_FREE(tunnel) \
  27. __atomic_and_fetch(&(tunnel->status), ~STATUS_USED_BUSY, __ATOMIC_SEQ_CST)
  28. /* Atomic operation macro: set tunnel buffer status to FULL */
  29. #define TUNNEL_BUFFER_FULL(tunnel) \
  30. __atomic_or_fetch(&(tunnel->status), STATUS_BUFFER_FULL, __ATOMIC_SEQ_CST)
  31. /* Atomic operation macro: set tunnel buffer status to AVAILABLE */
  32. #define TUNNEL_BUFFER_AVAILABLE(tunnel) \
  33. __atomic_and_fetch(&(tunnel->status), ~STATUS_BUFFER_FULL, __ATOMIC_SEQ_CST)
  34. /* Tunnel Control Block */
  35. RT_tunnel_CB RT_T_CB;
  36. /* Tunnel group instances */
  37. RT_tunnel tunnel_group[TUNNEL_NUM];
  38. /* Buffer pool for tunnel ringbuffers */
  39. uint8_t Buffer_pool[TUNNEL_NUM][TUNNEL_BUFFER_SIZE];
  40. /*****************************************************************************
  41. * @brief read data from tunnel buffer
  42. *
  43. * @param[in] tunnel tunnel instance
  44. * @param[out] buffer destination buffer pointer
  45. * @param[in] bytes number of bytes to read
  46. *
  47. * @retval int actual number of bytes read,
  48. * negative value on error
  49. *
  50. * @note lock will be taken and released internally
  51. *****************************************************************************/
  52. static int Read_Buffer(RT_tunnel_t tunnel, void *buffer, uint32_t bytes)
  53. {
  54. /* Error check */
  55. ERROR_CHECK_PTR(tunnel);
  56. ERROR_CHECK_PTR(buffer);
  57. ERROR_CHECK_OPERATION(tunnel, STATUS_OPERATION_READ);
  58. ERROR_CHECK_TUNNEL_USE(tunnel);
  59. TUNNEL_SET_BUSY(tunnel);
  60. uint32_t buffer_used = 0;
  61. uint32_t read_size = 0;
  62. /* check buffer usage */
  63. buffer_used = chry_ringbuffer_get_used(&tunnel->RB);
  64. if (buffer_used < bytes)
  65. {
  66. // LOG_WARN("Buffer usage is smaller than read size.");
  67. bytes = buffer_used;
  68. }
  69. /* read from ringbuffer */
  70. read_size = chry_ringbuffer_read(&tunnel->RB, buffer, bytes);
  71. if (read_size != bytes)
  72. {
  73. LOG_WARN("Fewer bytes were read than expected.");
  74. }
  75. TUNNEL_SET_FREE(tunnel);
  76. return read_size;
  77. }
  78. /*****************************************************************************
  79. * @brief write data into tunnel buffer
  80. *
  81. * @param[in] tunnel tunnel instance
  82. * @param[in] buffer source buffer pointer
  83. * @param[in] bytes number of bytes to write
  84. *
  85. * @retval int actual number of bytes written,
  86. * 0 if buffer not enough,
  87. * negative value on error
  88. *
  89. * @note lock will be taken and released internally
  90. *****************************************************************************/
  91. static int Write_Buffer(RT_tunnel_t tunnel, void *buffer, uint32_t bytes)
  92. {
  93. /* Error check */
  94. ERROR_CHECK_PTR(tunnel);
  95. ERROR_CHECK_PTR(buffer);
  96. ERROR_CHECK_OPERATION(tunnel, STATUS_OPERATION_WRITE);
  97. ERROR_CHECK_TUNNEL_USE(tunnel);
  98. /* Set tunnel busy flag */
  99. TUNNEL_SET_BUSY(tunnel);
  100. uint32_t buffer_free = 0;
  101. uint32_t write_size = 0;
  102. /* check free space */
  103. buffer_free = chry_ringbuffer_get_free(&tunnel->RB);
  104. if (buffer_free < bytes)
  105. {
  106. if ((tunnel->status & STATUS_BUFFER_Msk) == STATUS_BUFFER_AVAILABLE)
  107. {
  108. TUNNEL_BUFFER_FULL(tunnel);
  109. // LOG_ERROR("Write size exceeds buffer capacity.");
  110. }
  111. TUNNEL_SET_FREE(tunnel);
  112. return TUNNEL_FULL_CODE;
  113. }
  114. TUNNEL_BUFFER_AVAILABLE(tunnel);
  115. /* write into ringbuffer */
  116. write_size = chry_ringbuffer_write(&tunnel->RB, buffer, bytes);
  117. if (write_size != bytes)
  118. {
  119. LOG_ERROR("Write Buffer Error.");
  120. }
  121. TUNNEL_SET_FREE(tunnel);
  122. return write_size;
  123. }
  124. /*****************************************************************************
  125. * @brief get free byte count of tunnel buffer
  126. *
  127. * @param[in] tunnel tunnel instance
  128. *
  129. * @retval int number of free bytes in the tunnel buffer
  130. *****************************************************************************/
  131. int Get_Tunnel_Buffer_Free(RT_tunnel_t tunnel)
  132. {
  133. /* Error check */
  134. ERROR_CHECK_PTR(tunnel);
  135. return chry_ringbuffer_get_free(&tunnel->RB);
  136. }
  137. /*****************************************************************************
  138. * @brief get used byte count of tunnel buffer
  139. *
  140. * @param[in] tunnel tunnel instance
  141. *
  142. * @retval int number of used bytes in the tunnel buffer
  143. *****************************************************************************/
  144. int Get_Tunnel_Buffer_Used(RT_tunnel_t tunnel)
  145. {
  146. /* Error check */
  147. ERROR_CHECK_PTR(tunnel);
  148. return chry_ringbuffer_get_used(&tunnel->RB);
  149. }
  150. /*****************************************************************************
  151. * @brief get a free tunnel instance
  152. *
  153. * @retval RT_tunnel_t a free tunnel instance, or NULL if none available
  154. *****************************************************************************/
  155. RT_tunnel_t Get_Free_Tunnel(void)
  156. {
  157. for (uint32_t i = 0; i < TUNNEL_NUM; i++)
  158. {
  159. if ((RT_T_CB.tunnel_ptr[i]->status & STATUS_ACTIVE_Msk) == STATUS_UNACTIVE)
  160. {
  161. RT_T_CB.tunnel_ptr[i]->status |= STATUS_ACTIVE;
  162. return RT_T_CB.tunnel_ptr[i];
  163. }
  164. }
  165. return RT_NULL;
  166. }
  167. /*****************************************************************************
  168. * @brief set operation type for a tunnel
  169. *
  170. * @param[in] tunnel tunnel instance
  171. * @param[in] operation operation type to set
  172. *
  173. * @retval int 0 if success, negative value on error
  174. *****************************************************************************/
  175. int Set_Tunnel_Operation(RT_tunnel_t tunnel, tunnel_operation operation)
  176. {
  177. /* Error check */
  178. ERROR_CHECK_PTR(tunnel);
  179. if (operation == tunnel_read)
  180. {
  181. tunnel->status |= STATUS_OPERATION_READ;
  182. }
  183. else if (operation == tunnel_write)
  184. {
  185. tunnel->status |= STATUS_OPERATION_WRITE;
  186. }
  187. return 0;
  188. }
  189. /*****************************************************************************
  190. * @brief Set ID for a tunnel
  191. *
  192. * @param[in] tunnel Pointer to tunnel instance
  193. * @param[in] ID ID to assign to the tunnel
  194. *
  195. * @retval int 0 if success, negative value on error
  196. *****************************************************************************/
  197. int Set_Tunnel_ID(RT_tunnel_t tunnel, uint32_t ID)
  198. {
  199. /* Check if tunnel pointer is valid */
  200. ERROR_CHECK_PTR(tunnel);
  201. /* Assign ID to tunnel */
  202. tunnel->ID = ID;
  203. return 0;
  204. }
  205. /*****************************************************************************
  206. * @brief initialize tunnel system
  207. *
  208. * @note should be called before using any tunnel functions
  209. *****************************************************************************/
  210. int RT_Tunnel_Init(void)
  211. {
  212. /* init tunnel instances */
  213. for (uint32_t i = 0; i < TUNNEL_NUM; i++)
  214. {
  215. /* 1. init ID */
  216. tunnel_group[i].ID = TUNNEL_RESET_ID;
  217. /* 2. init status */
  218. tunnel_group[i].status = STATUS_UNACTIVE | STATUS_USED_FREE;
  219. /* 3. init ringbuffer */
  220. chry_ringbuffer_init(&tunnel_group[i].RB, Buffer_pool[i], TUNNEL_BUFFER_SIZE);
  221. /* 4. init operations */
  222. tunnel_group[i].read = Read_Buffer;
  223. tunnel_group[i].write = Write_Buffer;
  224. LOG_DEBUG("[Info][%d] Tunnel_group[i].ID:0x%08X", i, tunnel_group[i].ID);
  225. LOG_DEBUG("[Info][%d] Tunnel_group[i].status:0x%08X", i, tunnel_group[i].status);
  226. LOG_DEBUG("[Info][%d] Tunnel_group[i].status_address:0x%08X", i, &tunnel_group[i].status);
  227. LOG_DEBUG("[Info][%d] Tunnel_group[i].RB.in:0x%08X", i, tunnel_group[i].RB.in);
  228. LOG_DEBUG("[Info][%d] Tunnel_group[i].RB.in_address:0x%08X", i, &tunnel_group[i].RB.in);
  229. LOG_DEBUG("[Info][%d] Tunnel_group[i].RB.out:0x%08X", i, tunnel_group[i].RB.out);
  230. LOG_DEBUG("[Info][%d] Tunnel_group[i].RB.out_address:0x%08X", i, &tunnel_group[i].RB.out);
  231. LOG_DEBUG("[Info][%d] Tunnel_group[i].RB.mask:0x%08X", i, tunnel_group[i].RB.mask);
  232. LOG_DEBUG("[Info][%d] Tunnel_group[i].RB.pool:0x%08X\n", i, tunnel_group[i].RB.pool);
  233. }
  234. LOG_DEBUG("RT_T_CB Address:0x%08X", &RT_T_CB);
  235. /* init tunnel control block */
  236. RT_T_CB.tunnel_num = TUNNEL_NUM;
  237. LOG_DEBUG("RT_T_CB.tunnel_num Addr:0x%08X", &RT_T_CB.tunnel_num);
  238. rt_memcpy(RT_T_CB.ID, "RT_T_CB", sizeof("RT_T_CB"));
  239. for (uint32_t i = 0; i < TUNNEL_NUM; i++)
  240. {
  241. RT_T_CB.tunnel_ptr[i] = &tunnel_group[i];
  242. LOG_DEBUG("RT_T_CB.tunnel_ptr[%d]:0x%08X", i, RT_T_CB.tunnel_ptr[i]);
  243. }
  244. return 0;
  245. }
  246. INIT_COMPONENT_EXPORT(RT_Tunnel_Init);
  247. /*****************************************************************************
  248. * @brief print tunnel buffer content in hex format
  249. *
  250. * @param[in] argc argument count
  251. * @param[in] argv argument vector
  252. * argv[1] : tunnel index (0 ~ TUNNEL_NUM-1)
  253. *
  254. * @note This function is used as an RT-Thread shell command.
  255. * It reads all used bytes from the specified tunnel buffer
  256. * and prints them in hex format, 4 bytes per line.
  257. *
  258. * @retval int 0 on success, negative value on error
  259. *****************************************************************************/
  260. static int Tunnel_buffer_Print(int argc, char **argv)
  261. {
  262. if (argc < 2)
  263. {
  264. LOG_ERROR("too few argv");
  265. return -1;
  266. }
  267. /* Parse tunnel index from argv */
  268. uint32_t tunnel_num = (uint32_t)(*argv[1] - '0');
  269. if (tunnel_num >= TUNNEL_NUM)
  270. {
  271. LOG_ERROR("tunnel_num out of bounds");
  272. return -1;
  273. }
  274. RT_tunnel_t test_tunnel = &tunnel_group[tunnel_num];
  275. /* Get used size and allocate temporary buffer */
  276. uint32_t used = chry_ringbuffer_get_used(&test_tunnel->RB);
  277. uint8_t *buffer = rt_malloc(used);
  278. /* Check for allocation failure */
  279. if (buffer == NULL)
  280. {
  281. LOG_ERROR("rt_malloc failed: buffer is NULL");
  282. return -1;
  283. }
  284. /* Read buffer content */
  285. chry_ringbuffer_peek(&test_tunnel->RB, buffer, used);
  286. /* Print hex data, 4 bytes per line */
  287. for (uint32_t i = 0; i < used; i++)
  288. {
  289. if (((i % 4) == 0) && (i != 0))
  290. {
  291. rt_kprintf("\n");
  292. }
  293. rt_kprintf("[%04d]0x%02x\t", i, buffer[i]);
  294. }
  295. /* Free allocated buffer */
  296. rt_free(buffer);
  297. return 0;
  298. }
  299. MSH_CMD_EXPORT(Tunnel_buffer_Print, Tunnel_buffer_Print);
  300. void Tunnel_Info_Print(void)
  301. {
  302. for (uint32_t i = 0; i < TUNNEL_NUM; i++)
  303. {
  304. LOG_DEBUG("[Info][%d] Tunnel_group[i].ID:0x%08X", i, tunnel_group[i].ID);
  305. LOG_DEBUG("[Info][%d] Tunnel_group[i].status:0x%08X", i, tunnel_group[i].status);
  306. LOG_DEBUG("[Info][%d] Tunnel_group[i].status_address:0x%08X", i, &tunnel_group[i].status);
  307. LOG_DEBUG("[Info][%d] Tunnel_group[i].RB.in:0x%08X", i, tunnel_group[i].RB.in);
  308. LOG_DEBUG("[Info][%d] Tunnel_group[i].RB.in_address:0x%08X", i, &tunnel_group[i].RB.in);
  309. LOG_DEBUG("[Info][%d] Tunnel_group[i].RB.out:0x%08X", i, tunnel_group[i].RB.out);
  310. LOG_DEBUG("[Info][%d] Tunnel_group[i].RB.out_address:0x%08X", i, &tunnel_group[i].RB.out);
  311. LOG_DEBUG("[Info][%d] Tunnel_group[i].RB.mask:0x%08X", i, tunnel_group[i].RB.mask);
  312. LOG_DEBUG("[Info][%d] Tunnel_group[i].RB.pool:0x%08X\n", i, tunnel_group[i].RB.pool);
  313. }
  314. }
  315. MSH_CMD_EXPORT(Tunnel_Info_Print, Tunnel_Info_Print);