AP_UAVCAN_SLCAN.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. /*
  2. * This file is free software: you can redistribute it and/or modify it
  3. * under the terms of the GNU General Public License as published by the
  4. * Free Software Foundation, either version 3 of the License, or
  5. * (at your option) any later version.
  6. *
  7. * This file is distributed in the hope that it will be useful, but
  8. * WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. * See the GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License along
  13. * with this program. If not, see <http://www.gnu.org/licenses/>.
  14. *
  15. * Author: Siddharth Bharat Purohit
  16. * Referenced from implementation by Pavel Kirienko <pavel.kirienko@zubax.com>
  17. * for Zubax Babel
  18. */
  19. #include <AP_HAL/AP_HAL.h>
  20. #if AP_UAVCAN_SLCAN_ENABLED
  21. #include "AP_UAVCAN_SLCAN.h"
  22. #include <AP_SerialManager/AP_SerialManager.h>
  23. #include <AP_HAL_ChibiOS/CANSerialRouter.h>
  24. extern const AP_HAL::HAL& hal;
  25. static uint8_t nibble2hex(uint8_t x)
  26. {
  27. // Allocating in RAM because it's faster
  28. static uint8_t ConversionTable[] = {
  29. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
  30. };
  31. return ConversionTable[x & 0x0F];
  32. }
  33. static bool hex2nibble_error;
  34. static uint8_t hex2nibble(char c)
  35. {
  36. // Must go into RAM, not flash, because flash is slow
  37. static uint8_t NumConversionTable[] = {
  38. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
  39. };
  40. static uint8_t AlphaConversionTable[] = {
  41. 10, 11, 12, 13, 14, 15
  42. };
  43. uint8_t out = 255;
  44. if (c >= '0' && c <= '9') {
  45. out = NumConversionTable[int(c) - int('0')];
  46. }
  47. else if (c >= 'a' && c <= 'f') {
  48. out = AlphaConversionTable[int(c) - int('a')];
  49. }
  50. else if (c >= 'A' && c <= 'F') {
  51. out = AlphaConversionTable[int(c) - int('A')];
  52. }
  53. if (out == 255) {
  54. hex2nibble_error = true;
  55. }
  56. return out;
  57. }
  58. bool SLCAN::CAN::push_Frame(uavcan::CanFrame &frame)
  59. {
  60. SLCAN::CanRxItem frm;
  61. frm.frame = frame;
  62. frm.flags = 0;
  63. frm.utc_usec = AP_HAL::micros64();
  64. ChibiOS_CAN::CanIface::slcan_router().route_frame_to_can(frm.frame, frm.utc_usec);
  65. return rx_queue_.push(frm);
  66. }
  67. /**
  68. * General frame format:
  69. * <type> <id> <dlc> <data>
  70. * The emitting functions below are highly optimized for speed.
  71. */
  72. bool SLCAN::CAN::handle_FrameDataExt(const char* cmd)
  73. {
  74. uavcan::CanFrame f;
  75. hex2nibble_error = false;
  76. f.id = f.FlagEFF |
  77. (hex2nibble(cmd[1]) << 28) |
  78. (hex2nibble(cmd[2]) << 24) |
  79. (hex2nibble(cmd[3]) << 20) |
  80. (hex2nibble(cmd[4]) << 16) |
  81. (hex2nibble(cmd[5]) << 12) |
  82. (hex2nibble(cmd[6]) << 8) |
  83. (hex2nibble(cmd[7]) << 4) |
  84. (hex2nibble(cmd[8]) << 0);
  85. if (cmd[9] < '0' || cmd[9] > ('0' + uavcan::CanFrame::MaxDataLen)) {
  86. return false;
  87. }
  88. f.dlc = cmd[9] - '0';
  89. if (f.dlc > uavcan::CanFrame::MaxDataLen) {
  90. return false;
  91. }
  92. {
  93. const char* p = &cmd[10];
  94. for (unsigned i = 0; i < f.dlc; i++) {
  95. f.data[i] = (hex2nibble(*p) << 4) | hex2nibble(*(p + 1));
  96. p += 2;
  97. }
  98. }
  99. if (hex2nibble_error) {
  100. return false;
  101. }
  102. return push_Frame(f);
  103. }
  104. bool SLCAN::CAN::handle_FrameDataStd(const char* cmd)
  105. {
  106. uavcan::CanFrame f;
  107. hex2nibble_error = false;
  108. f.id = (hex2nibble(cmd[1]) << 8) |
  109. (hex2nibble(cmd[2]) << 4) |
  110. (hex2nibble(cmd[3]) << 0);
  111. if (cmd[4] < '0' || cmd[4] > ('0' + uavcan::CanFrame::MaxDataLen)) {
  112. return false;
  113. }
  114. f.dlc = cmd[4] - '0';
  115. if (f.dlc > uavcan::CanFrame::MaxDataLen) {
  116. return false;
  117. }
  118. {
  119. const char* p = &cmd[5];
  120. for (unsigned i = 0; i < f.dlc; i++) {
  121. f.data[i] = (hex2nibble(*p) << 4) | hex2nibble(*(p + 1));
  122. p += 2;
  123. }
  124. }
  125. if (hex2nibble_error) {
  126. return false;
  127. }
  128. return push_Frame(f);
  129. }
  130. bool SLCAN::CAN::handle_FrameRTRExt(const char* cmd)
  131. {
  132. uavcan::CanFrame f;
  133. hex2nibble_error = false;
  134. f.id = f.FlagEFF | f.FlagRTR |
  135. (hex2nibble(cmd[1]) << 28) |
  136. (hex2nibble(cmd[2]) << 24) |
  137. (hex2nibble(cmd[3]) << 20) |
  138. (hex2nibble(cmd[4]) << 16) |
  139. (hex2nibble(cmd[5]) << 12) |
  140. (hex2nibble(cmd[6]) << 8) |
  141. (hex2nibble(cmd[7]) << 4) |
  142. (hex2nibble(cmd[8]) << 0);
  143. if (cmd[9] < '0' || cmd[9] > ('0' + uavcan::CanFrame::MaxDataLen)) {
  144. return false;
  145. }
  146. f.dlc = cmd[9] - '0';
  147. if (f.dlc > uavcan::CanFrame::MaxDataLen) {
  148. return false;
  149. }
  150. if (hex2nibble_error) {
  151. return false;
  152. }
  153. return push_Frame(f);
  154. }
  155. bool SLCAN::CAN::handle_FrameRTRStd(const char* cmd)
  156. {
  157. uavcan::CanFrame f;
  158. hex2nibble_error = false;
  159. f.id = f.FlagRTR |
  160. (hex2nibble(cmd[1]) << 8) |
  161. (hex2nibble(cmd[2]) << 4) |
  162. (hex2nibble(cmd[3]) << 0);
  163. if (cmd[4] < '0' || cmd[4] > ('0' + uavcan::CanFrame::MaxDataLen)) {
  164. return false;
  165. }
  166. f.dlc = cmd[4] - '0';
  167. if (f.dlc <= uavcan::CanFrame::MaxDataLen) {
  168. return false;
  169. }
  170. if (hex2nibble_error) {
  171. return false;
  172. }
  173. return push_Frame(f);
  174. }
  175. static inline const char* getASCIIStatusCode(bool status)
  176. {
  177. return status ? "\r" : "\a";
  178. }
  179. bool SLCAN::CANManager::begin(uint32_t bitrate, uint8_t can_number)
  180. {
  181. if (driver_.init(bitrate, SLCAN::CAN::NormalMode, nullptr) < 0) {
  182. return false;
  183. }
  184. if (!hal.scheduler->thread_create(FUNCTOR_BIND_MEMBER(&SLCAN::CANManager::reader_trampoline, void), "SLCAN", 4096, AP_HAL::Scheduler::PRIORITY_CAN, -1)) {
  185. return false;
  186. }
  187. initialized(true);
  188. return true;
  189. }
  190. bool SLCAN::CANManager::is_initialized()
  191. {
  192. return initialized_;
  193. }
  194. void SLCAN::CANManager::initialized(bool val)
  195. {
  196. initialized_ = val;
  197. }
  198. int SLCAN::CAN::init(const uint32_t bitrate, const OperatingMode mode, AP_HAL::UARTDriver* port)
  199. {
  200. if (port == nullptr) {
  201. return -1;
  202. }
  203. _port = port;
  204. initialized_ = true;
  205. return 0;
  206. }
  207. /**
  208. * General frame format:
  209. * <type> <id> <dlc> <data> [timestamp msec] [flags]
  210. * Types:
  211. * R - RTR extended
  212. * r - RTR standard
  213. * T - Data extended
  214. * t - Data standard
  215. * Flags:
  216. * L - this frame is a loopback frame; timestamp field contains TX timestamp
  217. */
  218. int16_t SLCAN::CAN::reportFrame(const uavcan::CanFrame& frame, bool loopback, uint64_t timestamp_usec)
  219. {
  220. constexpr unsigned SLCANMaxFrameSize = 40;
  221. uint8_t buffer[SLCANMaxFrameSize] = {'\0'};
  222. uint8_t* p = &buffer[0];
  223. /*
  224. * Frame type
  225. */
  226. if (frame.isRemoteTransmissionRequest()) {
  227. *p++ = frame.isExtended() ? 'R' : 'r';
  228. }
  229. else if (frame.isErrorFrame()) {
  230. return -1; // Not supported
  231. }
  232. else {
  233. *p++ = frame.isExtended() ? 'T' : 't';
  234. }
  235. /*
  236. * ID
  237. */
  238. {
  239. const uint32_t id = frame.id & frame.MaskExtID;
  240. if (frame.isExtended()) {
  241. *p++ = nibble2hex(id >> 28);
  242. *p++ = nibble2hex(id >> 24);
  243. *p++ = nibble2hex(id >> 20);
  244. *p++ = nibble2hex(id >> 16);
  245. *p++ = nibble2hex(id >> 12);
  246. }
  247. *p++ = nibble2hex(id >> 8);
  248. *p++ = nibble2hex(id >> 4);
  249. *p++ = nibble2hex(id >> 0);
  250. }
  251. /*
  252. * DLC
  253. */
  254. *p++ = char('0' + frame.dlc);
  255. /*
  256. * Data
  257. */
  258. for (unsigned i = 0; i < frame.dlc; i++) {
  259. const uint8_t byte = frame.data[i];
  260. *p++ = nibble2hex(byte >> 4);
  261. *p++ = nibble2hex(byte);
  262. }
  263. /*
  264. * Timestamp
  265. */
  266. //if (param_cache.timestamping_on)
  267. {
  268. // SLCAN format - [0, 60000) milliseconds
  269. const auto slcan_timestamp = uint16_t(timestamp_usec / 1000U);
  270. *p++ = nibble2hex(slcan_timestamp >> 12);
  271. *p++ = nibble2hex(slcan_timestamp >> 8);
  272. *p++ = nibble2hex(slcan_timestamp >> 4);
  273. *p++ = nibble2hex(slcan_timestamp >> 0);
  274. }
  275. /*
  276. * Flags
  277. */
  278. //if (param_cache.flags_on)
  279. {
  280. if (loopback) {
  281. *p++ = 'L';
  282. }
  283. }
  284. /*
  285. * Finalization
  286. */
  287. *p++ = '\r';
  288. const auto frame_size = unsigned(p - &buffer[0]);
  289. if (_port->txspace() < _pending_frame_size) {
  290. _pending_frame_size = frame_size;
  291. return 0;
  292. }
  293. //Write to Serial
  294. if (!_port->write_locked(&buffer[0], frame_size, _serial_lock_key)) {
  295. return 0;
  296. }
  297. return 1;
  298. }
  299. /**
  300. * Accepts command string, returns response string or nullptr if no response is needed.
  301. */
  302. const char* SLCAN::CAN::processCommand(char* cmd)
  303. {
  304. /*
  305. * High-traffic SLCAN commands go first
  306. */
  307. if (cmd[0] == 'T') {
  308. return handle_FrameDataExt(cmd) ? "Z\r" : "\a";
  309. }
  310. else if (cmd[0] == 't') {
  311. return handle_FrameDataStd(cmd) ? "z\r" : "\a";
  312. }
  313. else if (cmd[0] == 'R') {
  314. return handle_FrameRTRExt(cmd) ? "Z\r" : "\a";
  315. }
  316. else if (cmd[0] == 'r' && cmd[1] <= '9') { // The second condition is needed to avoid greedy matching
  317. // See long commands below
  318. return handle_FrameRTRStd(cmd) ? "z\r" : "\a";
  319. }
  320. /*
  321. * Regular SLCAN commands
  322. */
  323. switch (cmd[0]) {
  324. case 'S': // Set CAN bitrate
  325. case 'O': // Open CAN in normal mode
  326. case 'L': // Open CAN in listen-only mode
  327. case 'l': { // Open CAN with loopback enabled
  328. _close = false;
  329. return getASCIIStatusCode(true); // Returning success for compatibility reasons
  330. }
  331. case 'C': { // Close CAN
  332. _close = true;
  333. return getASCIIStatusCode(true); // Returning success for compatibility reasons
  334. }
  335. case 'M': // Set CAN acceptance filter ID
  336. case 'm': // Set CAN acceptance filter mask
  337. case 'U': // Set UART baud rate, see http://www.can232.com/docs/can232_v3.pdf
  338. case 'Z': { // Enable/disable RX and loopback timestamping
  339. return getASCIIStatusCode(true); // Returning success for compatibility reasons
  340. }
  341. case 'F': { // Get status flags
  342. _port->printf("F%02X\r", unsigned(0)); // Returning success for compatibility reasons
  343. return nullptr;
  344. }
  345. case 'V': { // HW/SW version
  346. _port->printf("V%x%x%x%x\r", AP_UAVCAN_HW_VERS_MAJOR, AP_UAVCAN_HW_VERS_MINOR, AP_UAVCAN_SW_VERS_MAJOR, AP_UAVCAN_SW_VERS_MINOR);
  347. return nullptr;
  348. }
  349. case 'N': { // Serial number
  350. uavcan::protocol::HardwareVersion hw_version; // Standard type uavcan.protocol.HardwareVersion
  351. const uint8_t uid_buf_len = hw_version.unique_id.capacity();
  352. uint8_t uid_len = uid_buf_len;
  353. uint8_t unique_id[uid_buf_len];
  354. char buf[uid_buf_len * 2 + 1] = {'\0'};
  355. char* pos = &buf[0];
  356. if (hal.util->get_system_id_unformatted(unique_id, uid_len)) {
  357. for (uint8_t i = 0; i < uid_buf_len; i++) {
  358. *pos++ = nibble2hex(unique_id[i] >> 4);
  359. *pos++ = nibble2hex(unique_id[i]);
  360. }
  361. }
  362. *pos++ = '\0';
  363. _port->printf("N%s\r", &buf[0]);
  364. return nullptr;
  365. }
  366. default: {
  367. break;
  368. }
  369. }
  370. return getASCIIStatusCode(false);
  371. }
  372. /**
  373. * Please keep in mind that this function is strongly optimized for speed.
  374. */
  375. inline void SLCAN::CAN::addByte(const uint8_t byte)
  376. {
  377. if ((byte >= 32 && byte <= 126)) { // Normal printable ASCII character
  378. if (pos_ < SLCAN_BUFFER_SIZE) {
  379. buf_[pos_] = char(byte);
  380. pos_ += 1;
  381. }
  382. else {
  383. reset(); // Buffer overrun; silently drop the data
  384. }
  385. }
  386. else if (byte == '\r') { // End of command (SLCAN)
  387. // Processing the command
  388. buf_[pos_] = '\0';
  389. const char* const response = processCommand(reinterpret_cast<char*>(&buf_[0]));
  390. reset();
  391. // Sending the response if provided
  392. if (response != nullptr) {
  393. _port->write_locked(reinterpret_cast<const uint8_t*>(response),
  394. strlen(response), _serial_lock_key);
  395. }
  396. }
  397. else if (byte == 8 || byte == 127) { // DEL or BS (backspace)
  398. if (pos_ > 0) {
  399. pos_ -= 1;
  400. }
  401. }
  402. else { // This also includes Ctrl+C, Ctrl+D
  403. reset(); // Invalid byte - drop the current command
  404. }
  405. }
  406. void SLCAN::CAN::reset()
  407. {
  408. pos_ = 0;
  409. }
  410. void SLCAN::CAN::reader()
  411. {
  412. if (_port == nullptr) {
  413. return;
  414. }
  415. if (!_port_initialised) {
  416. //_port->begin(bitrate_);
  417. _port_initialised = true;
  418. }
  419. _port->lock_port(_serial_lock_key, _serial_lock_key);
  420. if (!_port->wait_timeout(1,1)) {
  421. int16_t data = _port->read_locked(_serial_lock_key);
  422. while (data > 0) {
  423. addByte(data);
  424. data = _port->read_locked(_serial_lock_key);
  425. }
  426. }
  427. }
  428. int16_t SLCAN::CAN::send(const uavcan::CanFrame& frame, uavcan::MonotonicTime tx_deadline, uavcan::CanIOFlags flags)
  429. {
  430. if (frame.isErrorFrame() || frame.dlc > 8) {
  431. return -ErrUnsupportedFrame;
  432. }
  433. return reportFrame(frame, flags & uavcan::CanIOFlagLoopback, AP_HAL::micros64());
  434. }
  435. int16_t SLCAN::CAN::receive(uavcan::CanFrame& out_frame, uavcan::MonotonicTime& out_ts_monotonic,
  436. uavcan::UtcTime& out_ts_utc, uavcan::CanIOFlags& out_flags)
  437. {
  438. out_ts_monotonic = uavcan::MonotonicTime::fromUSec(AP_HAL::micros64());; // High precision is not required for monotonic timestamps
  439. uint64_t utc_usec;
  440. CanRxItem frm;
  441. rx_queue_.pop(frm);
  442. out_frame = frm.frame;
  443. utc_usec = frm.utc_usec;
  444. out_flags = frm.flags;
  445. out_ts_utc = uavcan::UtcTime::fromUSec(utc_usec);
  446. return 1;
  447. }
  448. bool SLCAN::CAN::pending_frame_sent()
  449. {
  450. if (_pending_frame_size == 0) {
  451. return false;
  452. }
  453. else if (_port->txspace() >= _pending_frame_size) {
  454. _pending_frame_size = 0;
  455. return true;
  456. }
  457. return false;
  458. }
  459. bool SLCAN::CAN::isRxBufferEmpty()
  460. {
  461. return rx_queue_.available() == 0;
  462. }
  463. bool SLCAN::CAN::canAcceptNewTxFrame() const
  464. {
  465. constexpr unsigned SLCANMaxFrameSize = 40;
  466. if (_port->txspace() >= SLCANMaxFrameSize) {
  467. return true;
  468. }
  469. return false;
  470. }
  471. uavcan::CanSelectMasks SLCAN::CANManager::makeSelectMasks(const uavcan::CanFrame* (&pending_tx)[uavcan::MaxCanIfaces])
  472. {
  473. uavcan::CanSelectMasks msk;
  474. for (uint8_t i = 0; i < _ifaces_num; i++) {
  475. if (!driver_.is_initialized()) {
  476. continue;
  477. }
  478. if (!driver_.isRxBufferEmpty()) {
  479. msk.read |= 1 << i;
  480. }
  481. if (pending_tx[i] != nullptr) {
  482. if (driver_.canAcceptNewTxFrame()) {
  483. msk.write |= 1 << i;
  484. }
  485. }
  486. }
  487. return msk;
  488. }
  489. int16_t SLCAN::CANManager::select(uavcan::CanSelectMasks& inout_masks,
  490. const uavcan::CanFrame* (&pending_tx)[uavcan::MaxCanIfaces], uavcan::MonotonicTime blocking_deadline)
  491. {
  492. const uavcan::CanSelectMasks in_masks = inout_masks;
  493. const uavcan::MonotonicTime time = uavcan::MonotonicTime::fromUSec(AP_HAL::micros64());
  494. inout_masks = makeSelectMasks(pending_tx); // Check if we already have some of the requested events
  495. if ((inout_masks.read & in_masks.read) != 0 || (inout_masks.write & in_masks.write) != 0) {
  496. return 1;
  497. }
  498. _irq_handler_ctx = chThdGetSelfX();
  499. if (blocking_deadline.toUSec()) {
  500. chEvtWaitAnyTimeout(ALL_EVENTS, chTimeUS2I((blocking_deadline - time).toUSec())); // Block until timeout expires or any iface updates
  501. }
  502. inout_masks = makeSelectMasks(pending_tx); // Return what we got even if none of the requested events are set
  503. return 1; // Return value doesn't matter as long as it is non-negative
  504. }
  505. void SLCAN::CANManager::reader_trampoline(void)
  506. {
  507. while (true) {
  508. driver_.reader();
  509. if ((driver_.pending_frame_sent() || !driver_.isRxBufferEmpty()) && _irq_handler_ctx) {
  510. chEvtSignalI(_irq_handler_ctx, EVENT_MASK(0));
  511. }
  512. }
  513. }
  514. #endif // AP_UAVCAN_SLCAN_ENABLED