main.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. /* main.c
  2. *
  3. *
  4. * this is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * this is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
  17. */
  18. #include <stdio.h>
  19. #include "board.h"
  20. #include "net/ipv6/addr.h"
  21. #include "net/gnrc.h"
  22. #include "net/gnrc/netif.h"
  23. #include "shell.h"
  24. #include "periph/flashpage.h"
  25. #include "thread.h"
  26. #include "periph/uart.h"
  27. #include "periph/gpio.h"
  28. #include "xtimer.h"
  29. #include "ringbuffer.h"
  30. #include "roomba.h"
  31. #include "song.h"
  32. #include "mutex.h"
  33. #include "msg.h"
  34. #ifndef SHELL_BUFSIZE
  35. #define SHELL_BUFSIZE (128U)
  36. #endif
  37. #define DISPATCHER_PRIO (THREAD_PRIORITY_MAIN - 1)
  38. #define BT_PRIO (THREAD_PRIORITY_MAIN - 1)
  39. #define MSGQ_SIZE (4)
  40. #define GPIO_WAKEUP GPIO_PIN(1,11)
  41. #define SENSOR_BUFFER_SIZE (sizeof(struct sensors_code1) + sizeof(struct sensors_code2) + \
  42. sizeof(struct sensors_code3))
  43. #define MSG_SENSORS_OFF (0x4000)
  44. #define MSG_SENSORS_ON (0x4100)
  45. #define MSG_SENSORS_AVAILABLE (0x4200)
  46. #define MSG_SENSORS_TIMEOUT (0x4300)
  47. const char roomba_modstring[6][6] = {
  48. "OFF", "DRIVE", "FULL", "CLEAN", "SPOT", "DOCK"
  49. };
  50. extern const uint16_t song0[], song1[], song2[], song3[], song4[], song5[];
  51. // Types
  52. typedef struct {
  53. char rx_mem[SENSOR_BUFFER_SIZE];
  54. ringbuffer_t rx_buf;
  55. } uart_ctx_t;
  56. // Globals
  57. //
  58. static mutex_t roomba_mutex = MUTEX_INIT;
  59. static uart_ctx_t ctx[UART_NUMOF];
  60. static kernel_pid_t order66_pid, sensors_pid, gatt_srv_pid;
  61. static char order66_stack[THREAD_STACKSIZE_MAIN];
  62. static char sensors_stack[THREAD_STACKSIZE_MAIN];
  63. static char gatt_srv_stack[THREAD_STACKSIZE_MAIN];
  64. static msg_t sensors_msgq[MSGQ_SIZE];
  65. static msg_t gatt_srv_msgq[MSGQ_SIZE];
  66. static xtimer_t sensors_msg_timer;
  67. const uint16_t *songs[] = { song0, song1, song2, song3, song4, song5 };
  68. const uint32_t part_len[] = { 5000000, 5000000, 3200000, 2500000, 4200000, 4200000 };
  69. // Prototypes
  70. void *order66(void *arg);
  71. void *sensors_loop(void *arg);
  72. static void roomba_cmd(uint8_t cmd, uint8_t *payload, uint8_t len);
  73. void roomba_led(uint8_t status, uint8_t spot, uint8_t clean, uint8_t max, uint8_t power_c, uint8_t power_i);
  74. int song_len(const uint16_t *s)
  75. {
  76. int l = (s[0] & 0xFF00) >> 8;
  77. return l;
  78. }
  79. uint32_t load_song(int n)
  80. {
  81. uint8_t cmd = ROOMBA_SONG;
  82. int l = song_len(songs[n]);
  83. int i;
  84. mutex_lock(&roomba_mutex);
  85. uart_t dev = UART_DEV(0);
  86. uart_write(dev, &cmd, 1);
  87. uart_write(dev, (const uint8_t *)songs[n], 2 + (l << 1));
  88. mutex_unlock(&roomba_mutex);
  89. xtimer_usleep(100000);
  90. return part_len[n];
  91. }
  92. // Order 66
  93. void *order66(void *arg)
  94. {
  95. uint8_t x = 0;
  96. uint32_t st;
  97. st = load_song(0);
  98. roomba_cmd(ROOMBA_PLAY, &x, 1);
  99. xtimer_usleep(st);
  100. st = load_song(1);
  101. xtimer_usleep(20000);
  102. roomba_cmd(ROOMBA_PLAY, &x, 1);
  103. xtimer_usleep(st);
  104. st = load_song(2);
  105. xtimer_usleep(20000);
  106. roomba_cmd(ROOMBA_PLAY, &x, 1);
  107. xtimer_usleep(st);
  108. st = load_song(3);
  109. xtimer_usleep(20000);
  110. roomba_cmd(ROOMBA_PLAY, &x, 1);
  111. xtimer_usleep(st);
  112. st = load_song(4);
  113. xtimer_usleep(20000);
  114. roomba_cmd(ROOMBA_PLAY, &x, 1);
  115. xtimer_usleep(st);
  116. st = load_song(2);
  117. xtimer_usleep(20000);
  118. roomba_cmd(ROOMBA_PLAY, &x, 1);
  119. xtimer_usleep(st);
  120. st = load_song(3);
  121. xtimer_usleep(20000);
  122. roomba_cmd(ROOMBA_PLAY, &x, 1);
  123. xtimer_usleep(st);
  124. st = load_song(5);
  125. xtimer_usleep(20000);
  126. roomba_cmd(ROOMBA_PLAY, &x, 1);
  127. xtimer_usleep(st);
  128. return NULL;
  129. }
  130. static int roomba_mode = ROOMBA_MODE_OFF;
  131. static void roomba_stop(void)
  132. {
  133. uint8_t cmd = ROOMBA_POWER;
  134. uart_t dev = UART_DEV(0);
  135. mutex_lock(&roomba_mutex);
  136. uart_write(dev, &cmd, 1);
  137. mutex_unlock(&roomba_mutex);
  138. xtimer_usleep(200000);
  139. }
  140. static void roomba_start(void)
  141. {
  142. gpio_clear(GPIO_WAKEUP);
  143. xtimer_usleep(200000);
  144. gpio_set(GPIO_WAKEUP);
  145. uint8_t cmd = ROOMBA_START;
  146. uart_t dev = UART_DEV(0);
  147. mutex_lock(&roomba_mutex);
  148. uart_write(dev, &cmd, 1);
  149. xtimer_usleep(20000);
  150. mutex_unlock(&roomba_mutex);
  151. }
  152. static void roomba_safe_to_full(void)
  153. {
  154. uint8_t cmd = ROOMBA_FULL;
  155. uart_t dev = UART_DEV(0);
  156. mutex_lock(&roomba_mutex);
  157. uart_write(dev, &cmd, 1);
  158. xtimer_usleep(20000);
  159. mutex_unlock(&roomba_mutex);
  160. }
  161. static void roomba_full_to_safe(void)
  162. {
  163. uint8_t cmd = ROOMBA_SAFE;
  164. uart_t dev = UART_DEV(0);
  165. mutex_lock(&roomba_mutex);
  166. uart_write(dev, &cmd, 1);
  167. xtimer_usleep(20000);
  168. mutex_unlock(&roomba_mutex);
  169. }
  170. static void roomba_cmd(uint8_t cmd, uint8_t *payload, uint8_t len)
  171. {
  172. uart_t dev = UART_DEV(0);
  173. mutex_lock(&roomba_mutex);
  174. uart_write(dev, &cmd, 1);
  175. if(len && payload)
  176. uart_write(dev, payload, len);
  177. mutex_unlock(&roomba_mutex);
  178. }
  179. int switch_mode(int newmode)
  180. {
  181. msg_t msg;
  182. int oldmode = roomba_mode;
  183. if (roomba_mode != newmode) {
  184. if (roomba_mode == ROOMBA_MODE_OFF) {
  185. roomba_start();
  186. roomba_mode = ROOMBA_MODE_DRIVE;
  187. roomba_led(0x03, 0, 0, 0, 0x80, 0x80);
  188. }
  189. switch(newmode) {
  190. case ROOMBA_MODE_OFF:
  191. roomba_stop();
  192. roomba_led(0x00, 0, 0, 0, 0xF0, 0x20);
  193. break;
  194. case ROOMBA_MODE_DRIVE:
  195. if (roomba_mode == newmode)
  196. break;
  197. else if (roomba_mode == ROOMBA_MODE_FULL)
  198. roomba_full_to_safe();
  199. else {
  200. roomba_stop();
  201. roomba_start();
  202. }
  203. roomba_led(0x03, 0, 0, 0, 0x80, 0x80);
  204. break;
  205. case ROOMBA_MODE_FULL:
  206. if (roomba_mode == ROOMBA_MODE_DRIVE)
  207. roomba_safe_to_full();
  208. else {
  209. roomba_stop();
  210. roomba_start();
  211. roomba_safe_to_full();
  212. }
  213. roomba_led(0x01, 0, 0, 0, 0xF0, 0xFF);
  214. break;
  215. case ROOMBA_MODE_CLEAN:
  216. roomba_cmd(ROOMBA_CLEAN, NULL, 0);
  217. break;
  218. case ROOMBA_MODE_SPOT:
  219. roomba_cmd(ROOMBA_SPOT, NULL, 0);
  220. break;
  221. case ROOMBA_MODE_DOCK:
  222. roomba_cmd(ROOMBA_DOCK, NULL, 0);
  223. break;
  224. case 66:
  225. order66_pid = thread_create(order66_stack, sizeof(order66_stack),
  226. DISPATCHER_PRIO, 0, order66, NULL, "ORDER66");
  227. newmode = roomba_mode;
  228. break;
  229. }
  230. printf("Mode: %s\n", roomba_modstring[newmode]);
  231. roomba_mode = newmode;
  232. if (roomba_mode == ROOMBA_MODE_FULL) {
  233. msg.type = MSG_SENSORS_ON;
  234. msg_send(&msg, sensors_pid);
  235. }
  236. if (oldmode == ROOMBA_MODE_FULL) {
  237. msg.type = MSG_SENSORS_OFF;
  238. msg_send(&msg, sensors_pid);
  239. }
  240. }
  241. return 0;
  242. }
  243. uint8_t get_mode(void)
  244. {
  245. return roomba_mode;
  246. }
  247. static int cmd_info(int argc, char **argv)
  248. {
  249. (void)argc;
  250. (void)argv;
  251. puts("iRobot ROOMBA 500 powered by RIOT-OS");
  252. printf("You are running RIOT on %s.\n", RIOT_BOARD);
  253. printf("This board features a %s MCU.\n", RIOT_MCU);
  254. puts("\nUART INFO:");
  255. printf("Available devices: %i\n", UART_NUMOF);
  256. if (STDIO_UART_DEV != UART_UNDEF) {
  257. printf("UART used for STDIO (the shell): UART_DEV(%i)\n\n", STDIO_UART_DEV);
  258. }
  259. return 0;
  260. }
  261. int cmd_mode(int argc, char **argv)
  262. {
  263. int i;
  264. if (argc < 2) {
  265. printf("usage: %s <data (string)>\n", argv[0]);
  266. return 1;
  267. }
  268. for (i = 0; i < 6; i++) {
  269. if (strcmp(argv[1], roomba_modstring[i]) == 0) {
  270. switch_mode(i);
  271. return 0;
  272. }
  273. }
  274. if (strcmp(argv[1], "ORDER66") == 0) {
  275. order66_pid = thread_create(order66_stack, sizeof(order66_stack),
  276. DISPATCHER_PRIO, 0, order66, NULL, "ORDER66");
  277. return 0;
  278. }
  279. printf("Mode '%s' unknown\r\n", argv[1]);
  280. return 1;
  281. }
  282. static int cmd_play(int argc, char **argv)
  283. {
  284. uint8_t x = 0, z = 0;
  285. if ((argc != 2) || (strlen(argv[1]) != 1))
  286. {
  287. printf("usage: %s <song number>\n", argv[0]);
  288. return 1;
  289. }
  290. x = argv[1][0] - '0';
  291. load_song(x);
  292. roomba_cmd(ROOMBA_PLAY, &z, 1);
  293. return 0;
  294. }
  295. #define ALLSENSORS_CODE (0)
  296. #define ALLSENSORS_SIZE (26)
  297. #define QUICKSENSORS_CODE (1)
  298. #define QUICKSENSORS_SIZE (10)
  299. static volatile uint8_t sensors_expect_rx = 0;
  300. static volatile uint8_t sensors_data_rx = 0;
  301. static uint8_t raw_sensors_data[ALLSENSORS_SIZE];
  302. static void invalidate_sensors(void)
  303. {
  304. msg_t msg;
  305. memset(&raw_sensors_data, 0, sizeof(struct roomba_sensors_data));
  306. msg.type = MSG_SENSORS_AVAILABLE;
  307. msg_send(&msg, gatt_srv_pid);
  308. }
  309. static int read_sensors(uint8_t mode)
  310. {
  311. uint8_t cmd[2] = {ROOMBA_SENSORS, 0};
  312. int len = -1;
  313. msg_t msg;
  314. uart_t dev = UART_DEV(0);
  315. msg_t msg_timeout;
  316. msg_timeout.type = MSG_SENSORS_TIMEOUT;
  317. if (mode == ALLSENSORS_CODE)
  318. sensors_expect_rx = ALLSENSORS_SIZE;
  319. else
  320. sensors_expect_rx = QUICKSENSORS_SIZE;
  321. cmd[1] = mode;
  322. mutex_lock(&roomba_mutex);
  323. sensors_data_rx = 0;
  324. uart_write(dev, cmd, 1);
  325. uart_write(dev, cmd + 1, 1);
  326. xtimer_set_msg(&sensors_msg_timer, 500000, &msg_timeout, sensors_pid);
  327. if (msg_receive(&msg) >= 0) {
  328. if (msg.type == MSG_SENSORS_AVAILABLE) {
  329. len = sensors_expect_rx;
  330. } else if (msg.type == MSG_SENSORS_TIMEOUT) {
  331. printf("Timeout while reading sensors\n");
  332. invalidate_sensors();
  333. } else if (msg.type == MSG_SENSORS_OFF) {
  334. printf("Paused sensor task.\n");
  335. invalidate_sensors();
  336. } else {
  337. printf("Invalid message type %04x\n", msg.type);
  338. invalidate_sensors();
  339. }
  340. sensors_expect_rx = 0;
  341. }
  342. mutex_unlock(&roomba_mutex);
  343. return len;
  344. }
  345. // Rx callback
  346. static void rx_cb(void *arg, uint8_t data)
  347. {
  348. uart_t dev = (uart_t)arg;
  349. msg_t msg;
  350. //printf("RX: %02x\n", data);
  351. if (sensors_expect_rx > sensors_data_rx)
  352. raw_sensors_data[sensors_data_rx++] = data;
  353. if (sensors_expect_rx == sensors_data_rx)
  354. {
  355. msg.type = MSG_SENSORS_AVAILABLE;
  356. msg_send(&msg, sensors_pid);
  357. }
  358. }
  359. static struct roomba_sensors_data roomba_sensors_data = { };
  360. void print_sensors(void)
  361. {
  362. struct roomba_sensors_data *r = &roomba_sensors_data;
  363. printf("=== Sensors ===\n");
  364. printf("Valid : %s\n", r->valid?"yes":"no");
  365. if (r->valid) {
  366. printf("Drops : C:%d L:%d R:%d\n", r->drop_caster, r->drop_left, r->drop_right);
  367. printf("Bumps : L: %d R: %d\n", r->bump_left, r->bump_right);
  368. printf("Cliffs: FL:%d FR:%d \n", r->cliff_frontleft, r->cliff_frontright);
  369. printf(" L:%d R:%d \n", r->cliff_left, r->cliff_right);
  370. printf("OVC: %02x\n", r->ovc);
  371. }
  372. printf("==============\n\n");
  373. }
  374. void *sensors_loop(void *arg)
  375. {
  376. int ret = 0;
  377. msg_t msg;
  378. struct roomba_sensors_data tmp;
  379. while (1) {
  380. if (get_mode() != ROOMBA_MODE_FULL) {
  381. while (1) {
  382. if ((msg_receive(&msg) >= 0) && (msg.type == MSG_SENSORS_ON)) {
  383. printf("Sensors thread: resume.\n");
  384. break;
  385. }
  386. }
  387. }
  388. xtimer_usleep(250000);
  389. ret = read_sensors(ALLSENSORS_CODE);
  390. if (ret < 0) {
  391. xtimer_usleep(1000000);
  392. } else {
  393. /* Byte 0: Wheeldrops + Bumps */
  394. tmp.drop_caster = !!(raw_sensors_data[0] & (1 << SENSE_DROP_CASTER));
  395. tmp.drop_left = !!(raw_sensors_data[0] & (1 << SENSE_DROP_LEFT));
  396. tmp.drop_right = !!(raw_sensors_data[0] & (1 << SENSE_DROP_RIGHT));
  397. tmp.bump_left = !!(raw_sensors_data[0] & (1 << SENSE_BUMP_LEFT));
  398. tmp.bump_right = !!(raw_sensors_data[0] & (1 << SENSE_BUMP_RIGHT));
  399. /* Byte 1: Wall */
  400. tmp.wall = raw_sensors_data[1];
  401. /* Byte 2: Cliff L */
  402. tmp.cliff_left = raw_sensors_data[2];
  403. /* Byte 3: Cliff FL */
  404. tmp.cliff_frontleft = raw_sensors_data[3];
  405. /* Byte 4: Cliff FR */
  406. tmp.cliff_frontright = raw_sensors_data[4];
  407. /* Byte 5: Cliff R */
  408. tmp.cliff_right = raw_sensors_data[5];
  409. /* Byte 7: Overcurrents */
  410. tmp.ovc = raw_sensors_data[7];
  411. /* 'valid' flag */
  412. tmp.valid = 1;
  413. }
  414. if (memcmp(&roomba_sensors_data, &tmp, sizeof(struct roomba_sensors_data)) != 0) {
  415. msg_t msg;
  416. memcpy(&roomba_sensors_data, &tmp, sizeof(struct roomba_sensors_data));
  417. print_sensors();
  418. msg.type = MSG_SENSORS_AVAILABLE;
  419. msg_send(&msg, gatt_srv_pid);
  420. }
  421. }
  422. }
  423. struct roomba_sensors_data *roomba_sensors(void)
  424. {
  425. return &roomba_sensors_data;
  426. }
  427. void roomba_led(uint8_t status, uint8_t spot, uint8_t clean, uint8_t max, uint8_t power_c, uint8_t power_i)
  428. {
  429. uint8_t led_bytes[3];
  430. led_bytes[0] = ((status & 0x03) << 4) |
  431. ((spot & 0x01) << 3) |
  432. ((clean & 0x01) << 2) |
  433. ((max &0x01) << 1);
  434. led_bytes[1] = power_c;
  435. led_bytes[2] = power_i;
  436. roomba_cmd(ROOMBA_LEDS, led_bytes, 3);
  437. }
  438. void *gatt_srv(void*);
  439. static const shell_command_t shell_commands[] = {
  440. { "mode", "Switch mode", cmd_mode },
  441. { "play", "play song", cmd_play },
  442. { "info", "device info", cmd_info },
  443. { NULL, NULL, NULL }
  444. };
  445. int main(void)
  446. {
  447. /* initialize UART */
  448. char line_buf[SHELL_BUFSIZE];
  449. uart_init(UART_DEV(0), 115200, rx_cb, (void *)0);
  450. /* initialize ringbuffers */
  451. for (unsigned i = 0; i < UART_NUMOF; i++) {
  452. ringbuffer_init(&(ctx[i].rx_buf), ctx[i].rx_mem, SENSOR_BUFFER_SIZE);
  453. }
  454. /* initialize GPIO WAKEUP */
  455. gpio_init(GPIO_WAKEUP, GPIO_OUT);
  456. gpio_set(GPIO_WAKEUP);
  457. /* Gatt Server */
  458. gatt_srv_pid = thread_create(gatt_srv_stack, sizeof(gatt_srv_stack),
  459. DISPATCHER_PRIO - 1, 0, gatt_srv, NULL, "BLE_gatt");
  460. /* Create Sensors thread */
  461. msg_init_queue(sensors_msgq, MSGQ_SIZE);
  462. sensors_pid = thread_create(sensors_stack, sizeof(sensors_stack),
  463. DISPATCHER_PRIO, 0, sensors_loop, NULL, "sensors");
  464. /* run the shell */
  465. shell_run(shell_commands, line_buf, SHELL_BUFSIZE);
  466. return 0;
  467. }