srxl.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. /*
  2. This program is free software: you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation, either version 3 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program. If not, see <http://www.gnu.org/licenses/>.
  12. */
  13. /*
  14. SRXL protocol decoder, tested against AR7700 SRXL port
  15. Andrew Tridgell, September 2016
  16. Co author: Roman Kirchner, September 2016
  17. - 2016.10.23: SRXL variant V1 sucessfully (Testbench and Pixhawk/MissionPlanner) tested with RX-9-DR M-LINK (SW v1.26)
  18. */
  19. #include "srxl.h"
  20. #include <AP_Math/crc.h>
  21. #include <stdio.h>
  22. #include <stdint.h>
  23. #include <string.h>
  24. /* SRXL datastream characteristics for all variants */
  25. #define SRXL_MIN_FRAMESPACE_US 8000U /* Minumum space between srxl frames in us (applies to all variants) */
  26. #define SRXL_MAX_CHANNELS 20U /* Maximum number of channels from srxl datastream */
  27. /* decode progress states */
  28. #define STATE_IDLE 0x00U /* do nothing */
  29. #define STATE_NEW 0x01U /* get header of frame + prepare for frame reception + begin new crc cycle */
  30. #define STATE_COLLECT 0x02U /* collect RC channel data from frame + concurrently calc crc over payload data + extract channel information */
  31. /* Variant specific SRXL datastream characteristics */
  32. /* Framelength in byte */
  33. #define SRXL_FRAMELEN_V1 27U /* Framelength with header in byte for: Mpx SRXLv1 or XBUS Mode B */
  34. #define SRXL_FRAMELEN_V2 35U /* Framelength with header in byte for: Mpx SRXLv2 */
  35. #define SRXL_FRAMELEN_V5 18U /* Framelength with header in byte for Spk AR7700 etc. */
  36. #define SRXL_FRAMELEN_MAX 35U /* maximum possible framelengh */
  37. /* Headerbyte */
  38. #define SRXL_HEADER_V1 0xA1U /* Headerbyte for: Mpx SRXLv1 or XBUS Mode B */
  39. #define SRXL_HEADER_V2 0xA2U /* Headerbyte for: Mpx SRXLv2 */
  40. #define SRXL_HEADER_V5 0xA5U /* Headerbyte for: Spk AR7700 etc. */
  41. #define SRXL_HEADER_NOT_IMPL 0xFFU /* Headerbyte for non impemented srxl header*/
  42. static uint8_t buffer[SRXL_FRAMELEN_MAX]; /* buffer for raw srxl frame data in correct order --> buffer[0]=byte0 buffer[1]=byte1 */
  43. static uint8_t buflen; /* length in number of bytes of received srxl dataframe in buffer */
  44. static uint64_t last_data_us; /* timespan since last received data in us */
  45. static uint16_t channels[SRXL_MAX_CHANNELS]; /* buffer for extracted RC channel data as pulsewidth in microseconds */
  46. static uint8_t frame_header = 0U; /* Frame header from SRXL datastream */
  47. static uint8_t frame_len_full = 0U; /* Length in number of bytes of full srxl datastream */
  48. static uint8_t decode_state = STATE_IDLE; /* Current state of SRXL frame decoding */
  49. static uint8_t decode_state_next = STATE_IDLE; /* State of frame decoding thatwill be applied when the next byte from dataframe drops in */
  50. static uint16_t crc_fmu = 0U; /* CRC calculated over payload from srxl datastream on this machine */
  51. static uint16_t crc_receiver = 0U; /* CRC extracted from srxl datastream */
  52. static uint16_t max_channels;
  53. /**
  54. * Get RC channel information as microsecond pulsewidth representation from srxl version 1 and 2
  55. *
  56. * This function extracts RC channel information from srxl dataframe. The function expects the whole dataframe
  57. * in correct order in static array "buffer[SRXL_FRAMELEN_MAX]". After extracting all RC channel information, the data
  58. * is transferred to "values" array from parameter list. If the pixhawk does not support all channels from srxl datastream,
  59. * only supported number of channels will be refreshed.
  60. *
  61. * IMPORTANT SAFETY NOTICE: This function shall only be used after CRC has been successful.
  62. *
  63. * Structure of SRXL v1 dataframe --> 12 channels, 12 Bit per channel
  64. * Byte0: Header 0xA1
  65. * Byte1: Bits7-4:Empty Bits3-0:Channel1 MSB
  66. * Byte2: Bits7-0: Channel1 LSB
  67. * (....)
  68. * Byte23: Bits7-4:Empty Bits3-0:Channel12 MSB
  69. * Byte24: Bits7-0: Channel12 LSB
  70. * Byte25: CRC16 MSB
  71. * Byte26: CRC16 LSB
  72. *
  73. * Structure of SRXL v2 dataframe --> 16 channels, 12 Bit per channel
  74. * Byte0: Header 0xA2
  75. * Byte1: Bits7-4:Empty Bits3-0:Channel1 MSB
  76. * Byte2: Bits7-0: Channel1 LSB
  77. * (....)
  78. * Byte31: Bits7-4:Empty Bits3-0:Channel16 MSB
  79. * Byte32: Bits7-0: Channel16 LSB
  80. * Byte33: CRC16 MSB
  81. * Byte34: CRC16 LSB
  82. *
  83. * @param[in] max_values - maximum number of values supported by the pixhawk
  84. * @param[out] num_values - number of RC channels extracted from srxl frame
  85. * @param[out] values - array of RC channels with refreshed information as pulsewidth in microseconds Range: 800us - 2200us
  86. * @param[out] failsafe_state - true: RC-receiver is in failsafe state, false: RC-receiver is not in failsafe state
  87. * @retval 0 success
  88. */
  89. static int srxl_channels_get_v1v2(uint16_t max_values, uint8_t *num_values, uint16_t *values, bool *failsafe_state)
  90. {
  91. uint8_t loop;
  92. uint32_t channel_raw_value;
  93. *num_values = (uint8_t)((frame_len_full - 3U)/2U);
  94. *failsafe_state = 0U; /* this protocol version does not support failsafe information */
  95. /* get data channel data from frame */
  96. for (loop=0U; loop < *num_values; loop++) {
  97. channel_raw_value = ((((uint32_t)buffer[loop*2U+1U])& 0x0000000FU) << 8U) | ((uint32_t)(buffer[loop*2U+2U])); /* get 12bit channel raw value from srxl datastream (mask out unused bits with 0x0000000F) */
  98. channels[loop] = (uint16_t)(((channel_raw_value * (uint32_t)1400U) >> 12U) + (uint32_t)800U); /* convert raw value to servo/esc signal pulsewidth in us */
  99. }
  100. /* provide channel data to FMU */
  101. if ( (uint16_t)*num_values > max_values) {
  102. *num_values = (uint8_t)max_values;
  103. }
  104. memcpy(values, channels, (*num_values)*2);
  105. return 0; /* for srxl protocol version 1 and 2 it is not expected, that any error happen during decode process */
  106. }
  107. /**
  108. * Get RC channel information as microsecond pulsewidth representation from srxl version 5
  109. *
  110. * This function extracts RC channel information from srxl dataframe. The function expects the whole dataframe
  111. * in correct order in static array "buffer[SRXL_FRAMELEN_MAX]". After extracting all RC channel information, the data
  112. * is transferred to "values" array from parameter list. If the pixhawk does not support all channels from srxl datastream,
  113. * only supported number of channels will be refreshed.
  114. *
  115. * IMPORTANT SAFETY NOTICE: This function shall only be used after CRC has been successful.
  116. *
  117. * Structure of SRXL v5 dataframe
  118. * Byte0: Header 0xA5
  119. * Byte1 - Byte16: Payload
  120. * Byte17: CRC16 MSB
  121. * Byte18: CRC16 LSB
  122. *
  123. * @param[in] max_values - maximum number of values supported by the pixhawk
  124. * @param[out] num_values - number of RC channels extracted from srxl frame
  125. * @param[out] values - array of RC channels with refreshed information as pulsewidth in microseconds Range: 800us - 2200us
  126. * @param[out] failsafe_state - true: RC-receiver is in failsafe state, false: RC-receiver is not in failsafe state
  127. * @retval 0 success
  128. */
  129. static int srxl_channels_get_v5(uint16_t max_values, uint8_t *num_values, uint16_t *values, bool *failsafe_state)
  130. {
  131. // up to 7 channel values per packet. Each channel value is 16
  132. // bits, with 11 bits of data and 4 bits of channel number. The
  133. // top bit indicates a special X-Plus channel
  134. for (uint8_t i=0; i<7; i++) {
  135. uint16_t b = buffer[i*2+2] << 8 | buffer[i*2+3];
  136. uint16_t c = b >> 11; // channel number
  137. int32_t v = b & 0x7FF;
  138. if (b & 0x8000) {
  139. continue;
  140. }
  141. if (c == 12) {
  142. // special handling for channel 12
  143. // see http://www.deviationtx.com/forum/protocol-development/2088-18-channels-for-dsm2-dsmx?start=40
  144. //printf("c12: 0x%x %02x %02x\n", (unsigned)(b>>9), (unsigned)buffer[0], (unsigned)buffer[1]);
  145. v = (b & 0x1FF) << 2;
  146. c = 10 + ((b >> 9) & 0x7);
  147. if (buffer[1] & 1) {
  148. c += 4;
  149. }
  150. #if 0
  151. printf("b=0x%04x v=%u c=%u b[1]=0x%02x\n",
  152. (unsigned)b, (unsigned)v, (unsigned)c, (unsigned)buffer[1]);
  153. #endif
  154. } else if (c > 12) {
  155. // invalid
  156. v = 0;
  157. }
  158. // if channel number if greater than 16 then it is a X-Plus
  159. // channel. We don't yet know how to decode those. There is some information here:
  160. // http://www.deviationtx.com/forum/protocol-development/2088-18-channels-for-dsm2-dsmx?start=40
  161. // but we really need some sample data to confirm
  162. if (c < SRXL_MAX_CHANNELS) {
  163. v = (((v - 0x400) * 500) / 876) + 1500;
  164. channels[c] = v;
  165. if (c >= max_channels) {
  166. max_channels = c+1;
  167. }
  168. }
  169. //printf("%u:%u ", (unsigned)c, (unsigned)v);
  170. }
  171. //printf("\n");
  172. *num_values = max_channels;
  173. if (*num_values > max_values) {
  174. *num_values = max_values;
  175. }
  176. memcpy(values, channels, (*num_values)*2);
  177. // check failsafe bit, this goes low when connection to the
  178. // transmitter is lost
  179. *failsafe_state = ((buffer[1] & 2) == 0);
  180. // success
  181. return 0;
  182. }
  183. /**
  184. * Decode SRXL frames
  185. *
  186. *
  187. * Structure of all SRXL frames
  188. * Byte[0]: Header 0xA<VARIANT> --> Variant specific header. Variant is encoded in bits 3-0 of header byte.
  189. * Byte[1] - Byte[N-2]: SRXL variant specific payload
  190. * Byte[N-1] - Byte[N]: CRC16 over payload and header
  191. *
  192. * @param[in] timestamp_us - timestamp in microseconds
  193. * @param[in] received byte in microseconds
  194. * @param[out] num_values - number of RC channels extracted from srxl frame
  195. * @param[out] values - array of RC channels with refreshed information as pulsewidth in microseconds Range: 800us - 2200us
  196. * @param[in] maximum number of values supported by pixhawk
  197. * @param[out] failsafe_state - true: RC-receiver is in failsafe state, false: RC-receiver is not in failsafe state
  198. * @retval 0 success (a decoded packet)
  199. * @retval 1 no packet yet (accumulating)
  200. * @retval 2 unknown packet
  201. * @retval 4 checksum error
  202. */
  203. int srxl_decode(uint64_t timestamp_us, uint8_t byte, uint8_t *num_values, uint16_t *values, uint16_t max_values, bool *failsafe_state)
  204. {
  205. int ret = 1;
  206. /*----------------------------------------distinguish different srxl variants at the beginning of each frame---------------------------------------------- */
  207. /* Check if we have a new begin of a frame --> indicators: Time gap in datastream + SRXL header 0xA<VARIANT>*/
  208. if ( (timestamp_us - last_data_us) >= SRXL_MIN_FRAMESPACE_US) {
  209. /* Now detect SRXL variant based on header */
  210. switch(byte) {
  211. case SRXL_HEADER_V1:
  212. frame_len_full = SRXL_FRAMELEN_V1;
  213. frame_header = SRXL_HEADER_V1;
  214. decode_state = STATE_NEW;
  215. break;
  216. case SRXL_HEADER_V2:
  217. frame_len_full = SRXL_FRAMELEN_V2;
  218. frame_header = SRXL_HEADER_V2;
  219. decode_state = STATE_NEW;
  220. break;
  221. case SRXL_HEADER_V5:
  222. frame_len_full = SRXL_FRAMELEN_V5;
  223. frame_header = SRXL_HEADER_V5;
  224. decode_state = STATE_NEW;
  225. break;
  226. default:
  227. frame_len_full = 0U;
  228. frame_header = SRXL_HEADER_NOT_IMPL;
  229. decode_state = STATE_IDLE;
  230. buflen = 0;
  231. return 2; /* protocol version not implemented --> no channel data --> unknown packet */
  232. }
  233. }
  234. /*--------------------------------------------collect all data from stream and decode-------------------------------------------------------*/
  235. switch (decode_state) {
  236. case STATE_NEW: /* buffer header byte and prepare for frame reception and decoding */
  237. buffer[0U]=byte;
  238. crc_fmu = crc_xmodem_update(0U,byte);
  239. buflen = 1U;
  240. decode_state_next = STATE_COLLECT;
  241. break;
  242. case STATE_COLLECT: /* receive all bytes. After reception decode frame and provide rc channel information to FMU */
  243. if (buflen >= frame_len_full) {
  244. // a logic bug in the state machine, this shouldn't happen
  245. decode_state = STATE_IDLE;
  246. buflen = 0;
  247. frame_len_full = 0;
  248. frame_header = SRXL_HEADER_NOT_IMPL;
  249. return 2;
  250. }
  251. buffer[buflen] = byte;
  252. buflen++;
  253. /* CRC not over last 2 frame bytes as these bytes inhabitate the crc */
  254. if (buflen <= (frame_len_full-2)) {
  255. crc_fmu = crc_xmodem_update(crc_fmu,byte);
  256. }
  257. if( buflen == frame_len_full ) {
  258. /* CRC check here */
  259. crc_receiver = ((uint16_t)buffer[buflen-2] << 8U) | ((uint16_t)buffer[buflen-1]);
  260. if (crc_receiver == crc_fmu) {
  261. /* at this point buffer contains all frame data and crc is valid --> extract channel info according to SRXL variant */
  262. switch (frame_header) {
  263. case SRXL_HEADER_V1:
  264. ret = srxl_channels_get_v1v2(max_values, num_values, values, failsafe_state);
  265. break;
  266. case SRXL_HEADER_V2:
  267. ret = srxl_channels_get_v1v2(max_values, num_values, values, failsafe_state);
  268. break;
  269. case SRXL_HEADER_V5:
  270. ret = srxl_channels_get_v5(max_values, num_values, values, failsafe_state);
  271. break;
  272. default:
  273. ret = 2; /* protocol version not implemented --> no channel data */
  274. break;
  275. }
  276. }
  277. else {
  278. ret = 4; /* CRC fail --> no channel data */
  279. }
  280. decode_state_next = STATE_IDLE; /* frame data buffering and decoding finished --> statemachine not in use until new header drops is */
  281. }
  282. else {
  283. /* frame not completely received --> frame data buffering still ongoing */
  284. decode_state_next = STATE_COLLECT;
  285. }
  286. break;
  287. default:
  288. ret = 1; /* STATE_IDLE --> do nothing */
  289. break;
  290. } /* switch (decode_state) */
  291. decode_state = decode_state_next;
  292. last_data_us = timestamp_us;
  293. return ret;
  294. }
  295. #ifdef TEST_MAIN_PROGRAM
  296. /*
  297. test harness for use under Linux with USB serial adapter
  298. */
  299. #include <sys/types.h>
  300. #include <sys/stat.h>
  301. #include <fcntl.h>
  302. #include <time.h>
  303. #include <unistd.h>
  304. #include <stdlib.h>
  305. #include <termios.h>
  306. static uint64_t micros64(void)
  307. {
  308. struct timespec ts;
  309. clock_gettime(CLOCK_MONOTONIC, &ts);
  310. return 1.0e6*((ts.tv_sec + (ts.tv_nsec*1.0e-9)));
  311. }
  312. int main(int argc, const char *argv[])
  313. {
  314. int fd = open(argv[1], O_RDONLY|O_CLOEXEC);
  315. if (fd == -1) {
  316. perror(argv[1]);
  317. exit(1);
  318. }
  319. struct termios options;
  320. tcgetattr(fd, &options);
  321. cfsetispeed(&options, B115200);
  322. cfsetospeed(&options, B115200);
  323. options.c_cflag &= ~(PARENB|CSTOPB|CSIZE);
  324. options.c_cflag |= CS8;
  325. options.c_lflag &= ~(ICANON|ECHO|ECHOE|ISIG);
  326. options.c_iflag &= ~(IXON|IXOFF|IXANY);
  327. options.c_oflag &= ~OPOST;
  328. if (tcsetattr(fd, TCSANOW, &options) != 0) {
  329. perror("tcsetattr");
  330. exit(1);
  331. }
  332. tcflush(fd, TCIOFLUSH);
  333. while (true) {
  334. uint8_t b;
  335. uint8_t num_values = 0;
  336. uint16_t values[20];
  337. bool failsafe_state;
  338. fd_set fds;
  339. struct timeval tv;
  340. FD_ZERO(&fds);
  341. FD_SET(fd, &fds);
  342. tv.tv_sec = 1;
  343. tv.tv_usec = 0;
  344. // check if any bytes are available
  345. if (select(fd+1, &fds, NULL, NULL, &tv) != 1) {
  346. break;
  347. }
  348. if (read(fd, &b, 1) != 1) {
  349. break;
  350. }
  351. if (srxl_decode(micros64(), b, &num_values, values, sizeof(values)/sizeof(values[0]), &failsafe_state) == 0) {
  352. #if 1
  353. printf("%u: ", num_values);
  354. for (uint8_t i=0; i<num_values; i++) {
  355. printf("%u:%4u ", i+1, values[i]);
  356. }
  357. printf("%s\n", failsafe_state?"FAIL":"OK");
  358. #endif
  359. }
  360. }
  361. }
  362. #endif
  363. #ifdef TEST_BIN_PROGRAM
  364. /*
  365. test harness for use under Linux with hex dump in a file
  366. */
  367. #include <sys/types.h>
  368. #include <sys/stat.h>
  369. #include <fcntl.h>
  370. #include <time.h>
  371. #include <unistd.h>
  372. #include <stdlib.h>
  373. #include <termios.h>
  374. int main(int argc, const char *argv[])
  375. {
  376. FILE *f = fopen(argv[1], "r");
  377. if (!f) {
  378. perror(argv[1]);
  379. exit(1);
  380. }
  381. uint64_t t=0;
  382. while (true) {
  383. uint8_t b;
  384. uint8_t num_values = 0;
  385. uint16_t values[20];
  386. bool failsafe_state;
  387. uint8_t header;
  388. if (fread(&header, 1, 1, f) != 1) {
  389. break;
  390. }
  391. uint8_t frame_size = 0;
  392. switch (header) {
  393. case SRXL_HEADER_V1:
  394. frame_size = SRXL_FRAMELEN_V1;
  395. break;
  396. case SRXL_HEADER_V2:
  397. frame_size = SRXL_FRAMELEN_V2;
  398. break;
  399. case SRXL_HEADER_V5:
  400. frame_size = SRXL_FRAMELEN_V5;
  401. break;
  402. }
  403. if (frame_size == 0) {
  404. continue;
  405. }
  406. uint8_t u[frame_size];
  407. u[0] = header;
  408. if (fread(&u[1], 1, sizeof(u)-1, f) != sizeof(u)-1) {
  409. break;
  410. }
  411. t += 11000;
  412. for (uint8_t i=0; i<sizeof(u); i++) {
  413. b = u[i];
  414. if (srxl_decode(t, b, &num_values, values, sizeof(values)/sizeof(values[0]), &failsafe_state) == 0) {
  415. printf("%u: ", num_values);
  416. for (uint8_t i=0; i<num_values; i++) {
  417. printf("%u:%4u ", i+1, values[i]);
  418. }
  419. printf("%s\n", failsafe_state?"FAIL":"OK");
  420. }
  421. }
  422. }
  423. fclose(f);
  424. }
  425. #endif