cmux.c 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019
  1. /*
  2. * Copyright (c) 2006-2020, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2020-04-15 xiangxistu the first version
  9. */
  10. #include <cmux.h>
  11. #include <rtthread.h>
  12. #include <rthw.h>
  13. // bits: Poll/final, Command/Response, Extension
  14. #define CMUX_CONTROL_PF 16
  15. #define CMUX_ADDRESS_CR 2
  16. #define CMUX_ADDRESS_EA 1
  17. // the types of the frames
  18. #define CMUX_FRAME_SABM 47
  19. #define CMUX_FRAME_UA 99
  20. #define CMUX_FRAME_DM 15
  21. #define CMUX_FRAME_DISC 67
  22. #define CMUX_FRAME_UIH 239
  23. #define CMUX_FRAME_UI 3
  24. // the types of the control channel commands
  25. #define CMUX_C_CLD 193
  26. #define CMUX_C_TEST 33
  27. #define CMUX_C_MSC 225
  28. #define CMUX_C_NSC 17
  29. // basic mode flag for frame start and end
  30. #define CMUX_HEAD_FLAG (unsigned char)0xF9
  31. #define CMUX_DHCL_MASK 63 /* DLCI number is port number, 63 is the mask of DLCI; C/R bit is 1 when we send data */
  32. #define CMUX_DATA_MASK 127 /* when data length is out of 127( 0111 1111 ), we must use two bytes to describe data length in the cmux frame */
  33. #define CMUX_HIGH_DATA_MASK 32640 /* 32640 (‭ 0111 1111 1000 0000 ‬), the mask of high data bits */
  34. #define CMUX_COMMAND_IS(command, type) ((type & ~CMUX_ADDRESS_CR) == command)
  35. #define CMUX_PF_ISSET(frame) ((frame->control & CMUX_CONTROL_PF) == CMUX_CONTROL_PF)
  36. #define CMUX_FRAME_IS(type, frame) ((frame->control & ~CMUX_CONTROL_PF) == type)
  37. #define min(a, b) ((a) <= (b) ? (a) : (b))
  38. /* increases buffer pointer by one and wraps around if necessary */
  39. #define INC_BUF_POINTER(buf, p) \
  40. (p)++; \
  41. if ((p) == (buf)->end_point) \
  42. (p) = (buf)->data;
  43. /* Tells, how many chars are saved into the buffer */
  44. #define cmux_buffer_length(buff) (((buff)->read_point > (buff)->write_point) ? (CMUX_BUFFER_SIZE - ((buff)->read_point - (buff)->write_point)) : ((buff)->write_point - (buff)->read_point))
  45. /* Tells, how much free space there is in the buffer */
  46. #define cmux_buffer_free(buff) (((buff)->read_point > (buff)->write_point) ? ((buff)->read_point - (buff)->write_point) : (CMUX_BUFFER_SIZE - ((buff)->write_point - (buff)->read_point)))
  47. #define CMUX_THREAD_STACK_SIZE (CMUX_RECV_READ_MAX + 1536)
  48. #define CMUX_THREAD_PRIORITY 8
  49. #define CMUX_RECIEVE_RESET 0
  50. #define CMUX_RECIEVE_BEGIN 1
  51. #define CMUX_RECIEVE_PROCESS 2
  52. #define CMUX_RECIEVE_END 3
  53. #define CMUX_EVENT_RX_NOTIFY 1 /* serial incoming a byte */
  54. #define CMUX_EVENT_CHANNEL_OPEN 2
  55. #define CMUX_EVENT_CHANNEL_CLOSE 4
  56. #define CMUX_EVENT_CHANNEL_OPEN_REQ 8
  57. #define CMUX_EVENT_CHANNEL_CLOSE_REQ 16
  58. #define CMUX_EVENT_FUNCTION_EXIT 32
  59. #define DBG_TAG "cmux"
  60. #ifdef CMUX_DEBUG
  61. #define DBG_LVL DBG_LOG
  62. #else
  63. #define DBG_LVL DBG_INFO
  64. #endif
  65. #include <rtdbg.h>
  66. static rt_size_t cmux_send_data(struct rt_device *dev, int port, rt_uint8_t type, const char *data, int length);
  67. static rt_slist_t cmux_list = RT_SLIST_OBJECT_INIT(cmux_list);
  68. /* only one cmux object can be created */
  69. static struct cmux *_g_cmux = RT_NULL;
  70. /**
  71. * Get the cmux object that your used device.
  72. *
  73. * @param name the name of your select device.
  74. *
  75. * @return struct cmux object point
  76. */
  77. struct cmux *cmux_object_find(const char *name)
  78. {
  79. struct cmux *cmux = RT_NULL;
  80. struct rt_slist_node *node = RT_NULL;
  81. rt_base_t level;
  82. level = rt_hw_interrupt_disable();
  83. rt_slist_for_each(node, &cmux_list)
  84. {
  85. cmux = rt_slist_entry(node, struct cmux, list);
  86. if (rt_strncmp(cmux->dev->parent.name, name, RT_NAME_MAX) == 0)
  87. {
  88. rt_hw_interrupt_enable(level);
  89. return cmux;
  90. }
  91. };
  92. rt_hw_interrupt_enable(level);
  93. return RT_NULL;
  94. }
  95. /**
  96. * Receive callback function , send CMUX_EVENT_RX_NOTIFY event when uart acquire data
  97. *
  98. * @param dev the point of device driver structure, uart structure
  99. * @param size the indication callback function need this parameter
  100. *
  101. * @return RT_EOK
  102. */
  103. static rt_err_t cmux_rx_ind(rt_device_t dev, rt_size_t size)
  104. {
  105. RT_ASSERT(dev != RT_NULL);
  106. struct cmux *cmux = RT_NULL;
  107. cmux = _g_cmux;
  108. /* when receive data from uart , send event to wake up receive thread */
  109. rt_event_send(cmux->event, CMUX_EVENT_RX_NOTIFY);
  110. return RT_EOK;
  111. }
  112. /**
  113. * invoke callback function
  114. *
  115. * @param cmux cmux object
  116. * @param port the number of virtual channel
  117. * @param size the size of we receive from cmux
  118. *
  119. * @return the point of rt_device_write fucntion or RT_NULL
  120. */
  121. void cmux_vcom_isr(struct cmux *cmux, rt_uint8_t port, rt_size_t size)
  122. {
  123. /* when receive data, we should notify user immediately. */
  124. if (cmux->vcoms[port].device.rx_indicate != RT_NULL)
  125. {
  126. cmux->vcoms[port].device.rx_indicate(&cmux->vcoms[port].device, size);
  127. }
  128. else
  129. {
  130. LOG_W("channel[%02d] haven appended data, please set rx_indicate and clear receive data.", port);
  131. }
  132. }
  133. /**
  134. * allocate buffer for cmux object receive
  135. *
  136. * @param RT_NULL
  137. *
  138. * @return the point of struct cmux_buffer
  139. */
  140. static struct cmux_buffer *cmux_buffer_init()
  141. {
  142. struct cmux_buffer *buff = RT_NULL;
  143. buff = rt_malloc(sizeof(struct cmux_buffer));
  144. if (buff == RT_NULL)
  145. {
  146. return RT_NULL;
  147. }
  148. rt_memset(buff, 0, sizeof(struct cmux_buffer));
  149. buff->read_point = buff->data;
  150. buff->write_point = buff->data;
  151. buff->end_point = buff->data + CMUX_BUFFER_SIZE;
  152. return buff;
  153. }
  154. /**
  155. * destroy buffer for cmux object receive
  156. *
  157. * @param frame the point of cmux_frame
  158. *
  159. * @return RT_NULL
  160. */
  161. static void cmux_frame_destroy(struct cmux_frame *frame)
  162. {
  163. if ((frame->data_length > 0) && frame->data)
  164. {
  165. rt_free(frame->data);
  166. }
  167. if (frame)
  168. {
  169. rt_free(frame);
  170. }
  171. }
  172. /**
  173. * initial virtual serial for different channel, initial slist for channel
  174. *
  175. * @param cmux cmux object
  176. * @param channel the number of virtual serial
  177. *
  178. * @return RT_NULL
  179. */
  180. static void vcoms_cmux_frame_init(struct cmux *cmux, int channel)
  181. {
  182. rt_base_t level;
  183. level = rt_hw_interrupt_disable();
  184. rt_slist_init(&cmux->vcoms[channel].flist);
  185. rt_hw_interrupt_enable(level);
  186. cmux->vcoms[channel].frame_index = 0;
  187. LOG_D("init cmux data channel(%d) list.", channel);
  188. }
  189. /**
  190. * push cmux frame data into slist for different channel virtual serial
  191. *
  192. * @param cmux cmux object
  193. * @param channel the number of virtual serial
  194. * @param frame the point of frame data
  195. *
  196. * @return RT_EOK successful
  197. * RT_ENOMEM allocate memory failed
  198. */
  199. static rt_err_t cmux_frame_push(struct cmux *cmux, int channel, struct cmux_frame *frame)
  200. {
  201. rt_base_t level;
  202. struct frame *frame_new = RT_NULL;
  203. rt_uint16_t frame_len = cmux->vcoms[channel].frame_index;
  204. if (frame_len <= CMUX_MAX_FRAME_LIST_LEN)
  205. {
  206. frame_new = rt_malloc(sizeof(struct frame));
  207. if (frame_new == RT_NULL)
  208. {
  209. LOG_E("can't malloc <struct frame> to record data address.");
  210. return -RT_ENOMEM;
  211. }
  212. else
  213. {
  214. rt_memset(frame_new, 0, sizeof(struct frame));
  215. frame_new->frame = frame;
  216. rt_slist_init(&frame_new->frame_list);
  217. }
  218. level = rt_hw_interrupt_disable();
  219. rt_slist_append(&cmux->vcoms[channel].flist, &frame_new->frame_list);
  220. rt_hw_interrupt_enable(level);
  221. #ifdef CMUX_DEBUG
  222. LOG_HEX("CMUX_RX", 32, frame->data, frame->data_length);
  223. #endif
  224. LOG_D("new message (len:%d) for channel (%d) is append, Message total: %d.", frame_new->frame->data_length, channel, ++cmux->vcoms[channel].frame_index);
  225. return RT_EOK;
  226. }
  227. LOG_E("malloc failed, the message for channel(%d) is long than CMUX_MAX_FRAME_LIST_LEN(%d).", channel, CMUX_MAX_FRAME_LIST_LEN);
  228. return -RT_ENOMEM;
  229. }
  230. /**
  231. * pop cmux frame data from slist for different channel virtual serial
  232. *
  233. * @param cmux cmux object
  234. * @param channel the number of virtual serial
  235. *
  236. * @return frame_data successful
  237. * RT_NULL no message on the slist
  238. */
  239. static struct cmux_frame *cmux_frame_pop(struct cmux *cmux, int channel)
  240. {
  241. rt_base_t level;
  242. struct frame *frame = RT_NULL;
  243. struct cmux_frame *frame_data = RT_NULL;
  244. struct rt_slist_node *frame_list_find = RT_NULL;
  245. rt_slist_t *frame_list = RT_NULL;
  246. frame_list = &cmux->vcoms[channel].flist;
  247. frame_list_find = rt_slist_first(frame_list);
  248. if (frame_list_find != RT_NULL)
  249. {
  250. frame = rt_container_of(frame_list_find, struct frame, frame_list);
  251. frame_data = frame->frame;
  252. level = rt_hw_interrupt_disable();
  253. rt_slist_remove(frame_list, frame_list_find);
  254. rt_hw_interrupt_enable(level);
  255. LOG_D("A message (len:%d) for channel (%d) has been used, Message remain: %d.", frame_data->data_length, channel, --cmux->vcoms[channel].frame_index);
  256. rt_free(frame);
  257. }
  258. return frame_data;
  259. }
  260. /**
  261. * write data into cmux buffer
  262. *
  263. * @param buff the buffer of cmux object
  264. * @param input the point of data
  265. * @param count the length of data
  266. *
  267. * @return length the length of write into cmux buffer
  268. *
  269. */
  270. rt_size_t cmux_buffer_write(struct cmux_buffer *buff, rt_uint8_t *input, rt_size_t count)
  271. {
  272. int c = buff->end_point - buff->write_point;
  273. count = min(count, cmux_buffer_free(buff));
  274. if (count > c)
  275. {
  276. rt_memcpy(buff->write_point, input, c);
  277. rt_memcpy(buff->data, input + c, count - c);
  278. buff->write_point = buff->data + (count - c);
  279. }
  280. else
  281. {
  282. rt_memcpy(buff->write_point, input, count);
  283. buff->write_point += count;
  284. if (buff->write_point == buff->end_point)
  285. buff->write_point = buff->data;
  286. }
  287. return count;
  288. }
  289. /**
  290. * parse buffer for searching cmux frame
  291. *
  292. * @param buffer the cmux buffer for cmux object
  293. *
  294. * @return frame successful
  295. * RT_NULL no frame in the buffer
  296. */
  297. static struct cmux_frame *cmux_frame_parse(struct cmux_buffer *buffer)
  298. {
  299. int end;
  300. int length_needed = 5; /* channel, type, length, fcs, flag */
  301. rt_uint8_t *data = RT_NULL;
  302. rt_uint8_t fcs = 0xFF;
  303. struct cmux_frame *frame = RT_NULL;
  304. extern rt_uint8_t cmux_crctable[256];
  305. /* Find start flag */
  306. while (!buffer->flag_found && cmux_buffer_length(buffer) > 0)
  307. {
  308. if (*buffer->read_point == CMUX_HEAD_FLAG)
  309. buffer->flag_found = 1;
  310. INC_BUF_POINTER(buffer, buffer->read_point);
  311. }
  312. if (!buffer->flag_found) /* no frame started */
  313. return RT_NULL;
  314. /* skip empty frames (this causes troubles if we're using DLC 62) */
  315. while (cmux_buffer_length(buffer) > 0 && (*buffer->read_point == CMUX_HEAD_FLAG))
  316. {
  317. INC_BUF_POINTER(buffer, buffer->read_point);
  318. }
  319. if (cmux_buffer_length(buffer) >= length_needed)
  320. {
  321. data = buffer->read_point;
  322. frame = (struct cmux_frame *)rt_malloc(sizeof(struct cmux_frame));
  323. frame->data = RT_NULL;
  324. frame->channel = ((*data & 0xFC) >> 2);
  325. fcs = cmux_crctable[fcs ^ *data];
  326. INC_BUF_POINTER(buffer, data);
  327. frame->control = *data;
  328. fcs = cmux_crctable[fcs ^ *data];
  329. INC_BUF_POINTER(buffer, data);
  330. frame->data_length = (*data & 254) >> 1;
  331. fcs = cmux_crctable[fcs ^ *data];
  332. /* frame data length more than 127 bytes */
  333. if ((*data & 1) == 0)
  334. {
  335. INC_BUF_POINTER(buffer,data);
  336. frame->data_length += (*data*128);
  337. fcs = cmux_crctable[fcs^*data];
  338. length_needed++;
  339. LOG_D("len_need: %d, frame_data_len: %d.", length_needed, frame->data_length);
  340. }
  341. length_needed += frame->data_length;
  342. if (cmux_buffer_length(buffer) < length_needed)
  343. {
  344. cmux_frame_destroy(frame);
  345. return RT_NULL;
  346. }
  347. INC_BUF_POINTER(buffer, data);
  348. /* extract data */
  349. if (frame->data_length > 0)
  350. {
  351. frame->data = (unsigned char *)rt_malloc(frame->data_length);
  352. if (frame->data != RT_NULL)
  353. {
  354. end = buffer->end_point - data;
  355. if (frame->data_length > end)
  356. {
  357. rt_memcpy(frame->data, data, end);
  358. rt_memcpy(frame->data + end, buffer->data, frame->data_length - end);
  359. data = buffer->data + (frame->data_length - end);
  360. }
  361. else
  362. {
  363. rt_memcpy(frame->data, data, frame->data_length);
  364. data += frame->data_length;
  365. if (data == buffer->end_point)
  366. data = buffer->data;
  367. }
  368. if (CMUX_FRAME_IS(CMUX_FRAME_UI, frame))
  369. {
  370. for (end = 0; end < frame->data_length; end++)
  371. fcs = cmux_crctable[fcs ^ (frame->data[end])];
  372. }
  373. }
  374. else
  375. {
  376. LOG_E("Out of memory, when allocating space for frame data.");
  377. frame->data_length = 0;
  378. }
  379. }
  380. /* check FCS */
  381. if (cmux_crctable[fcs ^ (*data)] != 0xCF)
  382. {
  383. LOG_W("Dropping frame: FCS doesn't match.");
  384. cmux_frame_destroy(frame);
  385. buffer->flag_found = 0;
  386. buffer->read_point = data;
  387. return cmux_frame_parse(buffer);
  388. }
  389. else
  390. {
  391. /* check end flag */
  392. INC_BUF_POINTER(buffer, data);
  393. if (*data != CMUX_HEAD_FLAG)
  394. {
  395. LOG_W("Dropping frame: End flag not found. Instead: %d.", *data);
  396. cmux_frame_destroy(frame);
  397. buffer->flag_found = 0;
  398. buffer->read_point = data;
  399. return cmux_frame_parse(buffer);
  400. }
  401. else
  402. {
  403. }
  404. INC_BUF_POINTER(buffer, data);
  405. }
  406. buffer->read_point = data;
  407. }
  408. return frame;
  409. }
  410. /**
  411. * save data from serial, push frame into slist and invoke callback function
  412. *
  413. * @param device the point of device driver structure, ppp_device structure
  414. * @param buf the address of receive data from uart
  415. * @param len the length of receive data
  416. */
  417. static void cmux_recv_processdata(struct cmux *cmux, rt_uint8_t *buf, rt_size_t len)
  418. {
  419. rt_size_t count = len;
  420. struct cmux_frame *frame = RT_NULL;
  421. cmux_buffer_write(cmux->buffer, buf, count);
  422. while ((frame = cmux_frame_parse(cmux->buffer)) != RT_NULL)
  423. {
  424. /* distribute different data */
  425. if ((CMUX_FRAME_IS(CMUX_FRAME_UI, frame) || CMUX_FRAME_IS(CMUX_FRAME_UIH, frame)))
  426. {
  427. LOG_D("this is UI or UIH frame from channel(%d).", frame->channel);
  428. if (frame->channel > 0)
  429. {
  430. /* receive data from logical channel, distribution them */
  431. cmux_frame_push(cmux, frame->channel, frame);
  432. cmux_vcom_isr(cmux, frame->channel, frame->data_length);
  433. }
  434. else
  435. {
  436. /* control channel command */
  437. LOG_W("control channel command haven't support.");
  438. cmux_frame_destroy(frame);
  439. }
  440. }
  441. else
  442. {
  443. switch ((frame->control & ~CMUX_CONTROL_PF))
  444. {
  445. case CMUX_FRAME_UA:
  446. LOG_D("This is UA frame for channel(%d).", frame->channel);
  447. break;
  448. case CMUX_FRAME_DM:
  449. LOG_D("This is DM frame for channel(%d).", frame->channel);
  450. break;
  451. case CMUX_FRAME_SABM:
  452. LOG_D("This is SABM frame for channel(%d).", frame->channel);
  453. break;
  454. case CMUX_FRAME_DISC:
  455. LOG_D("This is DISC frame for channel(%d).", frame->channel);
  456. break;
  457. }
  458. cmux_frame_destroy(frame);
  459. }
  460. }
  461. }
  462. /**
  463. * assemble general data in the format of cmux
  464. *
  465. * @param dev actual serial device
  466. * @param port the number of virtual serial
  467. * @param type the format of cmux frame
  468. * @param data general data
  469. * @param length the length of general data
  470. *
  471. * @return length
  472. */
  473. static rt_size_t cmux_send_data(struct rt_device *dev, int port, rt_uint8_t type, const char *data, int length)
  474. {
  475. /* flag, EA=1 C port, frame type, data_length 1-2 */
  476. rt_uint8_t prefix[5] = {CMUX_HEAD_FLAG, CMUX_ADDRESS_EA | CMUX_ADDRESS_CR, 0, 0, 0};
  477. rt_uint8_t postfix[2] = {0xFF, CMUX_HEAD_FLAG};
  478. int c, prefix_length = 4;
  479. /* EA=1, Command, let's add address */
  480. prefix[1] = prefix[1] | ((CMUX_DHCL_MASK & port) << 2);
  481. /* cmux control field */
  482. prefix[2] = type;
  483. if (length > CMUX_DATA_MASK)
  484. {
  485. prefix_length = 5;
  486. prefix[3] = ((CMUX_DATA_MASK & length) << 1);
  487. prefix[4] = (CMUX_HIGH_DATA_MASK & length) >> 7;
  488. }
  489. else
  490. {
  491. prefix[3] = 1 | (length << 1);
  492. }
  493. /* CRC checksum */
  494. postfix[0] = cmux_frame_check(prefix + 1, prefix_length - 1);
  495. c = rt_device_write(dev, 0, prefix, prefix_length);
  496. if (c != prefix_length)
  497. {
  498. LOG_E("Couldn't write the whole prefix to the serial port for the virtual port %d. Wrote only %d bytes.", port, c);
  499. return 0;
  500. }
  501. if (length > 0)
  502. {
  503. c = rt_device_write(dev, 0, data, length);
  504. if (length != c)
  505. {
  506. LOG_E("Couldn't write all data to the serial port from the virtual port %d. Wrote only %d bytes.", port, c);
  507. return 0;
  508. }
  509. }
  510. c = rt_device_write(dev, 0, postfix, 2);
  511. if (c != 2)
  512. {
  513. LOG_E("Couldn't write the whole postfix to the serial port for the virtual port %d. Wrote only %d bytes.", port, c);
  514. return 0;
  515. }
  516. #ifdef CMUX_DEBUG
  517. LOG_HEX("CMUX_TX", 32, (const rt_uint8_t *)data, length);
  518. #endif
  519. return length;
  520. }
  521. /**
  522. * Receive thread , store serial data
  523. *
  524. * @param cmux the point of cmux object structure
  525. *
  526. * @return RT_EOK we shouldn't let the receive thread return data, receive thread need keep alive all the time
  527. */
  528. static int cmux_recv_thread(struct cmux *cmux)
  529. {
  530. rt_uint32_t event;
  531. rt_size_t len;
  532. rt_uint8_t buffer[CMUX_RECV_READ_MAX];
  533. rt_event_control(cmux->event, RT_IPC_CMD_RESET, RT_NULL);
  534. while (1)
  535. {
  536. rt_event_recv(cmux->event, CMUX_EVENT_RX_NOTIFY, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &event);
  537. if (event & CMUX_EVENT_RX_NOTIFY)
  538. {
  539. do
  540. {
  541. len = rt_device_read(cmux->dev, 0, buffer, CMUX_RECV_READ_MAX);
  542. if (len)
  543. {
  544. cmux_recv_processdata(cmux, buffer, len);
  545. }
  546. } while (len);
  547. }
  548. }
  549. return RT_EOK;
  550. }
  551. /**
  552. * cmux object init function
  553. *
  554. * @param object the point of cmux object
  555. * @param name the actual serial name
  556. * @param vcom_num the channel of virtual channel
  557. * @param user_data private data
  558. *
  559. * @return RT_EOK successful
  560. * RT_ENOMEM allocate memory failed
  561. */
  562. rt_err_t cmux_init(struct cmux *object, const char *name, rt_uint8_t vcom_num, void *user_data)
  563. {
  564. static rt_uint8_t count = 1;
  565. char tmp_name[RT_NAME_MAX] = {0};
  566. rt_base_t level;
  567. if (_g_cmux == RT_NULL)
  568. {
  569. _g_cmux = object;
  570. }
  571. else
  572. {
  573. RT_ASSERT(!_g_cmux);
  574. }
  575. object->dev = rt_device_find(name);
  576. if (object->dev == RT_NULL)
  577. {
  578. LOG_E("cmux can't find %s.", name);
  579. return RT_EOK;
  580. }
  581. object->vcom_num = vcom_num;
  582. object->vcoms = rt_malloc(vcom_num * sizeof(struct cmux_vcoms));
  583. rt_memset(object->vcoms, 0, vcom_num * sizeof(struct cmux_vcoms));
  584. if (object->vcoms == RT_NULL)
  585. {
  586. LOG_E("cmux vcoms malloc failed.");
  587. return -RT_ENOMEM;
  588. }
  589. object->buffer = cmux_buffer_init();
  590. if (object->buffer == RT_NULL)
  591. {
  592. LOG_E("cmux buffer malloc failed.");
  593. return -RT_ENOMEM;
  594. }
  595. rt_snprintf(tmp_name, sizeof(tmp_name), "cmux%d", count);
  596. object->event = rt_event_create(tmp_name, RT_IPC_FLAG_FIFO);
  597. if (object->event == RT_NULL)
  598. {
  599. LOG_E("cmux event malloc failed.");
  600. return -RT_ENOMEM;
  601. }
  602. object->user_data = user_data;
  603. level = rt_hw_interrupt_disable();
  604. rt_slist_init(&object->list);
  605. rt_slist_append(&cmux_list, &object->list);
  606. rt_hw_interrupt_enable(level);
  607. rt_snprintf(tmp_name, sizeof(tmp_name), "cmux%d", count);
  608. object->recv_tid = rt_thread_create(tmp_name,
  609. (void (*)(void *parameter))cmux_recv_thread,
  610. object,
  611. CMUX_THREAD_STACK_SIZE,
  612. CMUX_THREAD_PRIORITY,
  613. 20);
  614. if (object->recv_tid == RT_NULL)
  615. {
  616. LOG_E("cmux receive thread create failed.");
  617. return -RT_ERROR;
  618. }
  619. LOG_I("cmux rely on (%s) init successful.", name);
  620. return RT_EOK;
  621. }
  622. /**
  623. * start cmux function
  624. *
  625. * @param object the point of cmux object
  626. *
  627. * @return the result
  628. */
  629. rt_err_t cmux_start(struct cmux *object)
  630. {
  631. rt_err_t result = 0;
  632. struct rt_device *device = RT_NULL;
  633. /* uart transfer into cmux */
  634. rt_device_set_rx_indicate(object->dev, cmux_rx_ind);
  635. if (object->ops->start != RT_NULL)
  636. {
  637. result = object->ops->start(object);
  638. if (result != RT_EOK)
  639. return result;
  640. }
  641. if (object->recv_tid != RT_NULL)
  642. {
  643. result = rt_thread_startup(object->recv_tid);
  644. if (result != RT_EOK)
  645. {
  646. LOG_D("cmux receive thread startup failed.");
  647. return result;
  648. }
  649. }
  650. /* attach cmux control channel into rt-thread device */
  651. cmux_attach(object, 0, "cmux_ctl", RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX, RT_NULL);
  652. device = rt_device_find("cmux_ctl");
  653. result = rt_device_open(device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX);
  654. if (result != RT_EOK)
  655. {
  656. LOG_E("cmux control channel open failed.");
  657. }
  658. return result;
  659. }
  660. /**
  661. * stop cmux function
  662. *
  663. * @param object the point of cmux object
  664. *
  665. * @return the result
  666. */
  667. rt_err_t cmux_stop(struct cmux *object)
  668. {
  669. if (object->ops->stop != RT_NULL)
  670. {
  671. object->ops->stop(object);
  672. }
  673. /* we should send CMUX_FRAME_DM frame, close cmux control connect channel */
  674. cmux_send_data(object->dev, 0, CMUX_FRAME_DISC | CMUX_CONTROL_PF, RT_NULL, 0);
  675. return RT_EOK;
  676. }
  677. /**
  678. * control cmux function
  679. *
  680. * @param object the point of cmux object
  681. *
  682. * @return RT_ENOSYS haven't support control function
  683. */
  684. rt_err_t cmux_control(struct cmux *object, int cmd, void *args)
  685. {
  686. RT_ASSERT(object != RT_NULL);
  687. return -RT_ENOSYS;
  688. }
  689. /**
  690. * initialize virtual channel, and open it
  691. *
  692. * @param dev the point of virtual device
  693. * @param oflag the open flag of rt_device
  694. *
  695. * @return the result
  696. */
  697. static rt_err_t cmux_vcom_open(rt_device_t dev, rt_uint16_t oflag)
  698. {
  699. rt_err_t result = RT_EOK;
  700. struct cmux *object = RT_NULL;
  701. struct cmux_vcoms *vcom = (struct cmux_vcoms *)dev;
  702. RT_ASSERT(dev != RT_NULL);
  703. object = _g_cmux;
  704. /* establish virtual connect channel */
  705. cmux_send_data(object->dev, (int)vcom->link_port, CMUX_FRAME_SABM | CMUX_CONTROL_PF, RT_NULL, 0);
  706. return result;
  707. }
  708. /**
  709. * close virtual channel
  710. *
  711. * @param dev the point of virtual device
  712. *
  713. * @return the result
  714. */
  715. static rt_err_t cmux_vcom_close(rt_device_t dev)
  716. {
  717. rt_err_t result = RT_EOK;
  718. struct cmux *object = RT_NULL;
  719. struct cmux_vcoms *vcom = (struct cmux_vcoms *)dev;
  720. object = _g_cmux;
  721. cmux_send_data(object->dev, (int)vcom->link_port, CMUX_FRAME_DISC | CMUX_CONTROL_PF, RT_NULL, 0);
  722. return result;
  723. }
  724. /**
  725. * write data into virtual channel
  726. *
  727. * @param dev the point of virtual device
  728. * @param pos offset
  729. * @param buffer the data you want to send
  730. * @param size the length of buffer
  731. *
  732. * @return the result
  733. */
  734. static rt_size_t cmux_vcom_write(struct rt_device *dev,
  735. rt_off_t pos,
  736. const void *buffer,
  737. rt_size_t size)
  738. {
  739. struct cmux *cmux = RT_NULL;
  740. struct cmux_vcoms *vcom = (struct cmux_vcoms *)dev;
  741. rt_size_t len;
  742. cmux = _g_cmux;
  743. /* use virtual serial, we can write data into actual serial directly. */
  744. len = cmux_send_data(cmux->dev, (int)vcom->link_port, CMUX_FRAME_UIH, buffer, size);
  745. return len;
  746. }
  747. /**
  748. * write data into virtual channel
  749. *
  750. * @param dev the point of virtual device
  751. * @param pos offset
  752. * @param buffer the buffer you want to store
  753. * @param size the length of buffer
  754. *
  755. * @return the result
  756. */
  757. static rt_size_t cmux_vcom_read(struct rt_device *dev,
  758. rt_off_t pos,
  759. void *buffer,
  760. rt_size_t size)
  761. {
  762. struct cmux_vcoms *vcom = (struct cmux_vcoms *)dev;
  763. struct cmux *cmux = RT_NULL;
  764. rt_bool_t using_status = 0;
  765. cmux = _g_cmux;
  766. using_status = vcom->frame_using_status;
  767. /* The previous frame has been transmitted finish. */
  768. if (!using_status)
  769. {
  770. /* support fifo, we using the first frame */
  771. vcom->frame = cmux_frame_pop(cmux, (int)vcom->link_port);
  772. vcom->length = 0;
  773. vcom->data = RT_NULL;
  774. /* can't find frame */
  775. if (vcom->frame == RT_NULL)
  776. {
  777. return 0;
  778. }
  779. if (size >= vcom->frame->data_length)
  780. {
  781. int data_len = vcom->frame->data_length;
  782. rt_memcpy(buffer, vcom->frame->data, data_len);
  783. cmux_frame_destroy(vcom->frame);
  784. return data_len;
  785. }
  786. else
  787. {
  788. vcom->data = vcom->frame->data;
  789. vcom->frame_using_status = 1;
  790. rt_memcpy(buffer, vcom->data, size);
  791. vcom->data = vcom->data + size;
  792. vcom->length = vcom->length + size;
  793. return size;
  794. }
  795. }
  796. else
  797. {
  798. /* transmit the rest of frame */
  799. if (vcom->length + size >= vcom->frame->data_length)
  800. {
  801. size_t read_len;
  802. rt_memcpy(buffer, vcom->data, vcom->frame->data_length - vcom->length);
  803. vcom->frame_using_status = 0;
  804. if (vcom->frame->data_length - vcom->length >= 0) {
  805. read_len = vcom->frame->data_length - vcom->length;
  806. }
  807. cmux_frame_destroy(vcom->frame);
  808. return read_len;
  809. }
  810. else
  811. {
  812. rt_memcpy(buffer, vcom->data, size);
  813. vcom->data = vcom->data + size;
  814. vcom->length = vcom->length + size;
  815. return size;
  816. }
  817. }
  818. }
  819. /* virtual serial ops */
  820. #ifdef RT_USING_DEVICE_OPS
  821. const struct rt_device_ops cmux_device_ops =
  822. {
  823. RT_NULL,
  824. cmux_vcom_open,
  825. cmux_vcom_close,
  826. cmux_vcom_read,
  827. cmux_vcom_write,
  828. RT_NULL,
  829. };
  830. #endif
  831. /**
  832. * attach cmux into cmux object
  833. *
  834. * @param object the point of cmux object
  835. * @param link_port the channel of virtual serial
  836. * @param alias_name the name of virtual name
  837. * @param flag the type of virtual serial
  838. * @param user_data private data
  839. *
  840. * @return RT_EOK execute successful
  841. *
  842. */
  843. rt_err_t cmux_attach(struct cmux *object, int link_port, const char *alias_name, rt_uint16_t flags, void *user_data)
  844. {
  845. RT_ASSERT(object != RT_NULL);
  846. struct rt_device *device = RT_NULL;
  847. if(link_port >= object->vcom_num)
  848. {
  849. LOG_E("PORT[%02d] attach failed, please increase CMUX_PORT_NUMBER in the env.", link_port);
  850. return -RT_EINVAL;
  851. }
  852. device = &object->vcoms[link_port].device;
  853. device->type = RT_Device_Class_Char;
  854. device->rx_indicate = RT_NULL;
  855. device->tx_complete = RT_NULL;
  856. #ifdef RT_USING_DEVICE_OPS
  857. device->ops = &cmux_device_ops;
  858. #else
  859. device->init = RT_NULL;
  860. device->open = cmux_vcom_open;
  861. device->close = cmux_vcom_close;
  862. device->read = cmux_vcom_read;
  863. device->write = cmux_vcom_write;
  864. device->control = RT_NULL;
  865. #endif
  866. object->vcoms[link_port].link_port = (rt_uint8_t)link_port;
  867. vcoms_cmux_frame_init(object, link_port);
  868. /* interrupt mode or dma mode is meaningless, because we don't have buffer for vcom */
  869. if (flags & RT_DEVICE_FLAG_INT_RX)
  870. rt_device_register(device, alias_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_INT_RX);
  871. else
  872. rt_device_register(device, alias_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_DMA_RX);
  873. return RT_EOK;
  874. }
  875. /**
  876. * detach cmux from object
  877. *
  878. * @param object the point of cmux object
  879. * @param alias_name the name of virtual name
  880. *
  881. * @return RT_EOK execute successful
  882. * -RT_ERROR error
  883. */
  884. rt_err_t cmux_detach(struct cmux *object, const char *alias_name)
  885. {
  886. rt_device_t device = RT_NULL;
  887. device = rt_device_find(alias_name);
  888. if (device->open_flag & RT_DEVICE_OFLAG_OPEN)
  889. {
  890. LOG_E("You should close vcom (%s) firstly.", device->parent.name);
  891. return -RT_ERROR;
  892. }
  893. cmux_vcom_close(device);
  894. return RT_EOK;
  895. }