KDECAN_sniffer.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /*
  2. simple KDECAN network sniffer as an ArduPilot firmware
  3. */
  4. #include <AP_Common/AP_Common.h>
  5. #include <AP_HAL/AP_HAL.h>
  6. #if (CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS || CONFIG_HAL_BOARD == HAL_BOARD_LINUX) && HAL_WITH_UAVCAN
  7. #include <AP_HAL/CAN.h>
  8. #include <AP_HAL/Semaphores.h>
  9. #if CONFIG_HAL_BOARD == HAL_BOARD_LINUX
  10. #include <AP_HAL_Linux/CAN.h>
  11. #elif CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS
  12. #include <AP_HAL_ChibiOS/CAN.h>
  13. #endif
  14. #include <AP_HAL/utility/sparse-endian.h>
  15. #include <AP_Math/AP_Math.h>
  16. #include <cinttypes>
  17. void setup();
  18. void loop();
  19. const AP_HAL::HAL& hal = AP_HAL::get_HAL();
  20. #define debug_can(fmt, args...) do { hal.console->printf(fmt, ##args); } while (0)
  21. #define NUM_ESCS 8
  22. class KDECAN_sniffer {
  23. public:
  24. KDECAN_sniffer() {
  25. for (uint8_t i = 0; i < NUM_ESCS; i++) {
  26. _esc_info[i].mcu_id = 0xA5961824E7BD3C00 | i;
  27. }
  28. }
  29. void init(void);
  30. void loop(void);
  31. void print_stats(void);
  32. void send_enumeration(uint8_t num);
  33. private:
  34. uint8_t _driver_index = 0;
  35. uint8_t _interface = 0;
  36. uavcan::ICanDriver* _can_driver;
  37. uint8_t _mask_received_pwm = 0;
  38. struct esc_info {
  39. uint8_t node_id;
  40. uint64_t mcu_id;
  41. uint64_t enum_timeout;
  42. esc_info() : node_id(1), mcu_id(0), enum_timeout(0) {}
  43. } _esc_info[NUM_ESCS];
  44. uint8_t _max_node_id = 0;
  45. static const uint8_t BROADCAST_NODE_ID = 1;
  46. static const uint8_t ESC_INFO_OBJ_ADDR = 0;
  47. static const uint8_t SET_PWM_OBJ_ADDR = 1;
  48. static const uint8_t VOLTAGE_OBJ_ADDR = 2;
  49. static const uint8_t CURRENT_OBJ_ADDR = 3;
  50. static const uint8_t RPM_OBJ_ADDR = 4;
  51. static const uint8_t TEMPERATURE_OBJ_ADDR = 5;
  52. static const uint8_t GET_PWM_INPUT_OBJ_ADDR = 6;
  53. static const uint8_t GET_PWM_OUTPUT_OBJ_ADDR = 7;
  54. static const uint8_t MCU_ID_OBJ_ADDR = 8;
  55. static const uint8_t UPDATE_NODE_ID_OBJ_ADDR = 9;
  56. static const uint8_t START_ENUM_OBJ_ADDR = 10;
  57. static const uint8_t TELEMETRY_OBJ_ADDR = 11;
  58. };
  59. static struct {
  60. uint32_t frame_id;
  61. uint32_t count;
  62. } counters[100];
  63. static void count_msg(uint32_t frame_id)
  64. {
  65. for (uint16_t i=0; i<ARRAY_SIZE(counters); i++) {
  66. if (counters[i].frame_id == frame_id) {
  67. counters[i].count++;
  68. break;
  69. }
  70. if (counters[i].frame_id == 0) {
  71. counters[i].frame_id = frame_id;
  72. counters[i].count++;
  73. break;
  74. }
  75. }
  76. }
  77. void KDECAN_sniffer::init(void)
  78. {
  79. #if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS
  80. AP_HAL::CANManager* can_mgr = new ChibiOS::CANManager;
  81. #elif CONFIG_HAL_BOARD == HAL_BOARD_LINUX
  82. AP_HAL::CANManager* can_mgr = new Linux::CANManager;
  83. #endif
  84. if (can_mgr == nullptr) {
  85. AP_HAL::panic("Couldn't allocate CANManager, something is very wrong");
  86. }
  87. const_cast <AP_HAL::HAL&> (hal).can_mgr[_driver_index] = can_mgr;
  88. can_mgr->begin(1000000, _interface);
  89. can_mgr->initialized(true);
  90. if (!can_mgr->is_initialized()) {
  91. debug_can("Can not initialised\n");
  92. return;
  93. }
  94. _can_driver = can_mgr->get_driver();
  95. if (_can_driver == nullptr) {
  96. debug_can("KDECAN: no CAN driver\n\r");
  97. return;
  98. }
  99. debug_can("KDECAN: init done\n\r");
  100. }
  101. void KDECAN_sniffer::loop(void)
  102. {
  103. if (_can_driver == nullptr) {
  104. return;
  105. }
  106. uavcan::CanFrame empty_frame { (0 | uavcan::CanFrame::FlagEFF), nullptr, 0 };
  107. const uavcan::CanFrame* select_frames[uavcan::MaxCanIfaces] { &empty_frame };
  108. uavcan::MonotonicTime timeout = uavcan::MonotonicTime::fromMSec(AP_HAL::millis() + 1);
  109. uavcan::CanSelectMasks inout_mask;
  110. inout_mask.read = 1 << _interface;
  111. uavcan::CanSelectMasks in_mask = inout_mask;
  112. _can_driver->select(inout_mask, select_frames, timeout);
  113. if (in_mask.read & inout_mask.read) {
  114. uavcan::CanFrame frame;
  115. uavcan::MonotonicTime time;
  116. uavcan::UtcTime utc_time;
  117. uavcan::CanIOFlags flags {};
  118. int16_t res = _can_driver->getIface(_interface)->receive(frame, time, utc_time, flags);
  119. if (res == 1) {
  120. uint32_t id = frame.id & uavcan::CanFrame::MaskExtID;
  121. uint8_t object_address = id & 0xFF;
  122. uint8_t esc_num = uint8_t((id >> 8) & 0xFF);
  123. count_msg(id);
  124. uint8_t i = 0;
  125. uint8_t n = NUM_ESCS;
  126. if (esc_num != BROADCAST_NODE_ID) {
  127. for (; i < NUM_ESCS; i++) {
  128. if (object_address == UPDATE_NODE_ID_OBJ_ADDR) {
  129. if (_esc_info[i].mcu_id == be64toh(*((be64_t*) &(frame.data[0])))) {
  130. n = i + 1;
  131. break;
  132. }
  133. } else if (_esc_info[i].node_id == esc_num) {
  134. n = i + 1;
  135. break;
  136. }
  137. }
  138. }
  139. while (i < n) {
  140. uavcan::CanFrame res_frame;
  141. switch (object_address) {
  142. case ESC_INFO_OBJ_ADDR: {
  143. uint8_t info[5] { 1, 2, 3, 4, 0 };
  144. res_frame.dlc = 5;
  145. memcpy(res_frame.data, info, 5);
  146. break;
  147. }
  148. case SET_PWM_OBJ_ADDR: {
  149. if ((1 << (esc_num - 2) & _mask_received_pwm) && _mask_received_pwm != ((1 << _max_node_id) - 1)) {
  150. count_msg(0xFFFFFFF0);
  151. _mask_received_pwm = 0;
  152. }
  153. _mask_received_pwm |= 1 << (esc_num - 2);
  154. if (_mask_received_pwm == ((1 << _max_node_id) - 1)) {
  155. count_msg(0xFFFFFFFF);
  156. _mask_received_pwm = 0;
  157. }
  158. res_frame.dlc = 0;
  159. break;
  160. }
  161. case UPDATE_NODE_ID_OBJ_ADDR: {
  162. if (_esc_info[i].enum_timeout != 0 && _esc_info[i].enum_timeout >= AP_HAL::micros64()) {
  163. _esc_info[i].node_id = esc_num;
  164. _max_node_id = MAX(_max_node_id, esc_num - 2 + 1);
  165. hal.console->printf("Set node ID %d for ESC %d\n", esc_num, i);
  166. }
  167. _esc_info[i].enum_timeout = 0;
  168. res_frame.dlc = 1;
  169. memcpy(res_frame.data, &(_esc_info[i].node_id), 1);
  170. break;
  171. }
  172. case START_ENUM_OBJ_ADDR: {
  173. _esc_info[i].enum_timeout = AP_HAL::micros64() + be16toh(*((be16_t*) &(frame.data[0]))) * 1000;
  174. hal.console->printf("Starting enumeration for ESC %d, timeout %" PRIu64 "\n", i, _esc_info[i].enum_timeout);
  175. i++;
  176. continue;
  177. }
  178. case TELEMETRY_OBJ_ADDR: {
  179. uint8_t data[7] {};
  180. *((be16_t*) &data[0]) = htobe16(get_random16());
  181. *((be16_t*) &data[2]) = htobe16(get_random16());
  182. *((be16_t*) &data[4]) = htobe16(get_random16());
  183. data[6] = uint8_t(float(rand()) / RAND_MAX * 40.0f + 15);
  184. res_frame.dlc = 7;
  185. memcpy(res_frame.data, data, 7);
  186. break;
  187. }
  188. case VOLTAGE_OBJ_ADDR:
  189. case CURRENT_OBJ_ADDR:
  190. case RPM_OBJ_ADDR:
  191. case TEMPERATURE_OBJ_ADDR:
  192. case GET_PWM_INPUT_OBJ_ADDR:
  193. case GET_PWM_OUTPUT_OBJ_ADDR:
  194. case MCU_ID_OBJ_ADDR:
  195. default:
  196. // discard frame
  197. return;
  198. }
  199. res_frame.id = (_esc_info[i].node_id << 16) | object_address | uavcan::CanFrame::FlagEFF;
  200. timeout = uavcan::MonotonicTime::fromUSec(AP_HAL::millis() + 500);
  201. int16_t res2 = _can_driver->getIface(_interface)->send(res_frame, timeout, 0);
  202. if (res2 == 1) {
  203. i++;
  204. }
  205. }
  206. }
  207. }
  208. }
  209. void KDECAN_sniffer::print_stats(void)
  210. {
  211. hal.console->printf("%lu\n", AP_HAL::micros());
  212. for (uint16_t i=0;i<100;i++) {
  213. if (counters[i].frame_id == 0) {
  214. break;
  215. }
  216. hal.console->printf("0x%08" PRIX32 ": %" PRIu32 "\n", counters[i].frame_id, counters[i].count);
  217. counters[i].count = 0;
  218. }
  219. hal.console->printf("\n");
  220. }
  221. void KDECAN_sniffer::send_enumeration(uint8_t num)
  222. {
  223. if (_esc_info[num].enum_timeout == 0 || AP_HAL::micros64() > _esc_info[num].enum_timeout) {
  224. _esc_info[num].enum_timeout = 0;
  225. hal.console->printf("Not running enumeration for ESC %d\n", num);
  226. return;
  227. }
  228. while (true) {
  229. uint8_t mcu[8] {};
  230. *((be64_t*) mcu) = htobe64(_esc_info[num].mcu_id);
  231. uavcan::CanFrame res_frame { (_esc_info[num].node_id << 16) | START_ENUM_OBJ_ADDR | uavcan::CanFrame::FlagEFF,
  232. mcu,
  233. 8 };
  234. uavcan::MonotonicTime timeout = uavcan::MonotonicTime::fromMSec(AP_HAL::millis() + 1);
  235. int16_t res = _can_driver->getIface(_interface)->send(res_frame, timeout, 0);
  236. if (res == 1) {
  237. return;
  238. }
  239. }
  240. }
  241. static KDECAN_sniffer sniffer;
  242. void setup(void)
  243. {
  244. hal.scheduler->delay(2000);
  245. hal.console->printf("Starting KDECAN sniffer\n");
  246. sniffer.init();
  247. }
  248. void loop(void)
  249. {
  250. sniffer.loop();
  251. static uint32_t last_print_ms;
  252. uint32_t now = AP_HAL::millis();
  253. if (now - last_print_ms >= 1000) {
  254. last_print_ms = now;
  255. sniffer.print_stats();
  256. }
  257. if (hal.console->available() >= 3) {
  258. char c = hal.console->read();
  259. if (c == 'e') {
  260. c = hal.console->read();
  261. if (c == ' ') {
  262. c = hal.console->read();
  263. if (c >= '0' && c < '9') {
  264. uint8_t num = c - '0';
  265. sniffer.send_enumeration(num);
  266. }
  267. }
  268. } else if (c == 'r') {
  269. hal.console->printf("rebooting\n");
  270. hal.scheduler->reboot(false);
  271. }
  272. }
  273. // auto-reboot for --upload
  274. if (hal.console->available() > 50) {
  275. hal.console->printf("rebooting\n");
  276. hal.scheduler->reboot(false);
  277. }
  278. }
  279. AP_HAL_MAIN();
  280. #else
  281. #include <stdio.h>
  282. const AP_HAL::HAL& hal = AP_HAL::get_HAL();
  283. static void loop() { }
  284. static void setup()
  285. {
  286. printf("Board not currently supported\n");
  287. }
  288. AP_HAL_MAIN();
  289. #endif