You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1180 lines
33KB

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stddef.h> /* offsetof */
  4. #include <unistd.h>
  5. #include <string.h>
  6. #include <sys/socket.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <fcntl.h>
  10. #include <termios.h>
  11. #include <sys/time.h>
  12. #include "chipinfo_avr.h"
  13. #include "multiboot.h"
  14. #include "optarg.h"
  15. #define FUNK_BRIDGE_DEBUG 0
  16. #define FUNK_PACKET_DEBUG 0
  17. /* *********************************************************************** */
  18. #define BRIDGE_CMD_TRANSMIT 'T'
  19. #define BRIDGE_CMD_RECEIVE 'R'
  20. #define BRIDGE_CMD_VERSION 'V'
  21. #define BRIDGE_CAUSE_SUCCESS 0x00
  22. #define BRIDGE_CAUSE_TIMEOUT 0x01
  23. #define BRIDGE_CAUSE_NOT_SUPPORTED 0xF0
  24. #define BRIDGE_CAUSE_INVALID_PARAMETER 0xF1
  25. #define BRIDGE_CAUSE_UNSPECIFIED_ERROR 0xFF
  26. /* *********************************************************************** */
  27. #define MSG_TYPE_REQUEST 0x00 /* master -> slave req */
  28. #define MSG_TYPE_CONFIRMATION 0x40 /* master -> slave rsp */
  29. #define MSG_TYPE_INDICATION 0x80 /* slave -> master req */
  30. #define MSG_TYPE_RESPONSE 0xC0 /* slave -> master rsp */
  31. #define MSG_TYPE_MASK 0xC0
  32. #define MSG_CMD_MASK 0x3F
  33. #define MSG_CMD_SWITCHAPP_REQUEST (MSG_TYPE_REQUEST | 0x20)
  34. #define MSG_CMD_SWITCHAPP_RESPONSE (MSG_TYPE_RESPONSE | 0x20)
  35. #define MSG_CMD_VERSION_REQUEST (MSG_TYPE_REQUEST | 0x21)
  36. #define MSG_CMD_VERSION_RESPONSE (MSG_TYPE_RESPONSE | 0x21)
  37. #define MSG_CMD_CHIPINFO_REQUEST (MSG_TYPE_REQUEST | 0x22)
  38. #define MSG_CMD_CHIPINFO_RESPONSE (MSG_TYPE_RESPONSE | 0x22)
  39. #define MSG_CMD_READ_REQUEST (MSG_TYPE_REQUEST | 0x23)
  40. #define MSG_CMD_READ_RESPONSE (MSG_TYPE_RESPONSE | 0x23)
  41. #define MSG_CMD_WRITE_REQUEST (MSG_TYPE_REQUEST | 0x24)
  42. #define MSG_CMD_WRITE_RESPONSE (MSG_TYPE_RESPONSE | 0x24)
  43. #define CAUSE_SUCCESS 0x00
  44. #define BOOTTYPE_BOOTLOADER 0x00
  45. #define BOOTTYPE_APPLICATION 0x80
  46. #define MEMTYPE_FLASH 0x01
  47. #define MEMTYPE_EEPROM 0x02
  48. /* *********************************************************************** */
  49. struct bootloader_msg
  50. {
  51. uint8_t command;
  52. uint8_t seqnum;
  53. uint8_t cause;
  54. union {
  55. struct {
  56. uint8_t app;
  57. } switchapp;
  58. struct {
  59. uint8_t data[16];
  60. } version;
  61. struct {
  62. uint8_t data[8];
  63. } chipinfo;
  64. struct {
  65. uint16_t address;
  66. uint8_t mem_type;
  67. uint8_t size;
  68. } read_req;
  69. struct {
  70. uint8_t data[32];
  71. } read_rsp;
  72. struct {
  73. uint16_t address;
  74. uint8_t mem_type;
  75. uint8_t size;
  76. uint8_t data[32];
  77. } write_req;
  78. } p;
  79. } __attribute__ ((__packed__));
  80. struct rfm12_pkt
  81. {
  82. uint8_t dest_address;
  83. uint8_t source_address;
  84. uint8_t data_length;
  85. uint8_t header_checksum;
  86. struct bootloader_msg msg;
  87. } __attribute__ ((__packed__));
  88. /* *********************************************************************** */
  89. #define READ_BLOCK_SIZE 32 /* bytes in one flash/eeprom read request */
  90. #define WRITE_BLOCK_SIZE 32 /* bytes in one eeprom write request */
  91. /* *********************************************************************** */
  92. #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
  93. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  94. struct multiboot_ops funk_ops;
  95. struct funk_privdata
  96. {
  97. char *device;
  98. int fd;
  99. int connected;
  100. int address;
  101. int src_address;
  102. int seqnum;
  103. int flashsize;
  104. int flashpage;
  105. int eepromsize;
  106. struct termios oldtio;
  107. };
  108. static struct option funk_optargs[] =
  109. {
  110. { "address", 1, 0, 'a'}, /* -a <addr> */
  111. { "device", 1, 0, 'd'}, /* [ -d <device> ] */
  112. };
  113. /* *************************************************************************
  114. * funk_optarg_cb
  115. * ************************************************************************* */
  116. static int funk_optarg_cb(int val, const char *arg, void *privdata)
  117. {
  118. struct funk_privdata *funk = (struct funk_privdata *)privdata;
  119. switch (val)
  120. {
  121. case 'a': /* address */
  122. {
  123. char *endptr;
  124. funk->address = strtol(arg, &endptr, 16);
  125. if (*endptr != '\0' || funk->address < 0x00 || funk->address > 0xFF) {
  126. fprintf(stderr, "invalid address: '%s'\n", arg);
  127. return -1;
  128. }
  129. }
  130. break;
  131. case 'd': /* device */
  132. if (funk->device != NULL) {
  133. fprintf(stderr, "invalid device: '%s'\n", optarg);
  134. return -1;
  135. }
  136. funk->device = strdup(optarg);
  137. if (funk->device == NULL) {
  138. perror("strdup()");
  139. return -1;
  140. }
  141. break;
  142. case 'h':
  143. case '?': /* error */
  144. fprintf(stderr, "Usage: funkboot [options]\n"
  145. " -a <address> - selects rfm12 address (0x00 - 0xFF)\n"
  146. " -d <device> - selects funkbridge device\n"
  147. " -r <flash|eeprom>:<file> - reads flash/eeprom to file (.bin | .hex | -)\n"
  148. " -w <flash|eeprom>:<file> - write flash/eeprom from file (.bin | .hex)\n"
  149. " -n - disable verify after write\n"
  150. " -p <0|1|2> - progress bar mode\n"
  151. "\n"
  152. "Example: funkboot -d /dev/ttyUSB0 -a 0x22 -w flash:blmc.hex -w flash:blmc_eeprom.hex\n"
  153. "\n");
  154. return -1;
  155. default:
  156. return 1;
  157. }
  158. return 0;
  159. } /* funk_optarg_cb */
  160. /* *************************************************************************
  161. * funk_alloc
  162. * ************************************************************************* */
  163. static struct multiboot * funk_alloc(void)
  164. {
  165. struct multiboot * mboot = malloc(sizeof(struct multiboot));
  166. if (mboot == NULL)
  167. {
  168. return NULL;
  169. }
  170. memset(mboot, 0x00, sizeof(struct multiboot));
  171. mboot->ops = &funk_ops;
  172. struct funk_privdata *funk = malloc(sizeof(struct funk_privdata));
  173. if (funk == NULL)
  174. {
  175. free(mboot);
  176. return NULL;
  177. }
  178. memset(funk, 0x00, sizeof(struct funk_privdata));
  179. funk->device = NULL;
  180. funk->address = 0;
  181. optarg_register(funk_optargs, ARRAY_SIZE(funk_optargs), funk_optarg_cb, (void *)funk);
  182. mboot->privdata = funk;
  183. return mboot;
  184. } /* funk_alloc */
  185. /* *************************************************************************
  186. * funk_free
  187. * ************************************************************************* */
  188. static void funk_free(struct multiboot *mboot)
  189. {
  190. struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
  191. if (funk->device != NULL)
  192. {
  193. free(funk->device);
  194. }
  195. free(funk);
  196. free(mboot);
  197. } /* funk_free */
  198. /* *************************************************************************
  199. * optarg_copy
  200. * ************************************************************************* */
  201. static int funk_get_memtype(struct multiboot *mboot,
  202. const char *memname)
  203. {
  204. if (strcmp(memname, "flash") == 0)
  205. {
  206. return MEMTYPE_FLASH;
  207. }
  208. else if (strcmp(memname, "eeprom") == 0)
  209. {
  210. return MEMTYPE_EEPROM;
  211. }
  212. return -1;
  213. } /* funk_get_memtype */
  214. /* *************************************************************************
  215. * optarg_copy
  216. * ************************************************************************* */
  217. static int funk_get_memsize(struct multiboot *mboot,
  218. int memtype)
  219. {
  220. struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
  221. if (!funk->connected)
  222. {
  223. return 0;
  224. }
  225. switch (memtype)
  226. {
  227. case MEMTYPE_FLASH:
  228. return funk->flashsize;
  229. case MEMTYPE_EEPROM:
  230. return funk->eepromsize;
  231. default:
  232. return 0;
  233. }
  234. } /* funk_get_memsize */
  235. /* *************************************************************************
  236. * funk_serial_read
  237. * ************************************************************************* */
  238. static int funk_serial_read(int fd, void *data, int size)
  239. {
  240. int pos = 0;
  241. while (1)
  242. {
  243. fd_set fdset;
  244. struct timeval timeout = { .tv_sec = 1, .tv_usec = 0 };
  245. FD_ZERO(&fdset);
  246. FD_SET(fd, &fdset);
  247. int ret = select(fd +1, &fdset, NULL, NULL, &timeout);
  248. if (ret == -1)
  249. {
  250. perror("select");
  251. return -1;
  252. }
  253. else if (ret == 0)
  254. {
  255. break;
  256. }
  257. else if (FD_ISSET(fd, &fdset))
  258. {
  259. int len = read(fd, data + pos, size - pos);
  260. if (len < 0)
  261. {
  262. return -1;
  263. }
  264. else
  265. {
  266. pos += len;
  267. if (pos == size)
  268. {
  269. break;
  270. }
  271. }
  272. }
  273. }
  274. return pos;
  275. } /* funk_serial_read */
  276. #if (FUNK_BRIDGE_DEBUG == 1) || (FUNK_PACKET_DEBUG == 1)
  277. /* *************************************************************************
  278. * funk_print_data
  279. * ************************************************************************* */
  280. static char * funk_print_data(uint8_t *data, uint16_t length)
  281. {
  282. int pos = 0, i = 0, j;
  283. char *buf = malloc(length * 4 + 64);
  284. while (pos < length)
  285. {
  286. i += sprintf(buf + i, "%04X: ", pos);
  287. for (j = 0; j < 16; j++)
  288. {
  289. if (pos + j < length)
  290. {
  291. i += sprintf(buf + i, "%02X", data[pos + j]);
  292. }
  293. else
  294. {
  295. i += sprintf(buf + i, " ");
  296. if (j % 2)
  297. {
  298. buf[i++] = ' ';
  299. }
  300. }
  301. for (j = 0; j < 16; j++)
  302. {
  303. if (pos + j < length)
  304. {
  305. unsigned char val = data[pos + j];
  306. if (val >= 0x20 && val < 0x80)
  307. {
  308. buf[i++] = val;
  309. }
  310. else
  311. {
  312. buf[i++] = '.';
  313. }
  314. }
  315. else
  316. {
  317. buf[i++] = ' ';
  318. }
  319. }
  320. pos += 16;
  321. buf[i++] = '\r';
  322. buf[i++] = '\n';
  323. }
  324. buf[i] = 0;
  325. return buf;
  326. } /* funk_print_data */
  327. #endif
  328. /* *************************************************************************
  329. * funk_bridge_send
  330. * ************************************************************************* */
  331. static int funk_bridge_send(struct funk_privdata *funk,
  332. uint8_t *header,
  333. uint8_t headerlength,
  334. uint8_t *data,
  335. uint8_t datalength)
  336. {
  337. if (headerlength > 0)
  338. {
  339. if (write(funk->fd, header, headerlength) != headerlength)
  340. {
  341. return -1;
  342. }
  343. }
  344. if (datalength > 0)
  345. {
  346. if (write(funk->fd, data, datalength) != datalength)
  347. {
  348. return -1;
  349. }
  350. }
  351. #if (FUNK_BRIDGE_DEBUG == 1)
  352. char *dump = funk_print_data(data, datalength);
  353. printf("funk_bridge_send() cmd=0x%02x length=0x%02x\n%s\n", header[0], datalength, dump);
  354. free(dump);
  355. #endif
  356. return 0;
  357. } /* funk_bridge_send */
  358. /* *************************************************************************
  359. * funk_bridge_recv
  360. * ************************************************************************* */
  361. static int funk_bridge_recv(struct funk_privdata *funk,
  362. uint8_t command,
  363. uint8_t *cause,
  364. uint8_t *buffer,
  365. int buffersize)
  366. {
  367. uint8_t response[3];
  368. int len;
  369. len = funk_serial_read(funk->fd, response, sizeof(response));
  370. if (len != sizeof(response))
  371. {
  372. fprintf(stderr, "short read() from device\n");
  373. return -1;
  374. }
  375. if (response[0] != command)
  376. {
  377. fprintf(stderr, "invalid command response (0x%02x != 0x%02x)\n",
  378. response[0], command);
  379. return -1;
  380. }
  381. *cause = response[1];
  382. uint16_t length = response[2];
  383. uint16_t bufferpos = 0;
  384. while (length > 0)
  385. {
  386. /* free space in output buffer? */
  387. if ((bufferpos < buffersize) && (buffer != NULL))
  388. {
  389. uint16_t size = MIN(buffersize - bufferpos, length);
  390. len = funk_serial_read(funk->fd, buffer + bufferpos, size);
  391. if (len <= 0)
  392. {
  393. fprintf(stderr, "short read() from device (%d != %d)\n",
  394. len, size);
  395. return -1;
  396. }
  397. bufferpos += len;
  398. length -= len;
  399. }
  400. else
  401. {
  402. uint8_t dummy[256];
  403. /* no space in output buffer, but device still sends data -> do dummy read */
  404. uint16_t size = MIN(sizeof(dummy), length);
  405. len = funk_serial_read(funk->fd, dummy, size);
  406. if (len <= 0)
  407. {
  408. fprintf(stderr, "short read() from device (%d != %d)\n",
  409. len, size);
  410. return -1;
  411. }
  412. length -= len;
  413. }
  414. }
  415. #if (FUNK_BRIDGE_DEBUG == 1)
  416. char *dump = funk_print_data(buffer, bufferpos);
  417. printf("funk_bridge_recv() cmd=0x%02x cause=0x%02x length=0x%02x\n%s\n",
  418. command, *cause, length, dump);
  419. free(dump);
  420. #endif
  421. return bufferpos;
  422. } /* funk_bridge_recv */
  423. /* *************************************************************************
  424. * funk_send_packet
  425. * ************************************************************************* */
  426. static int funk_send_packet(struct funk_privdata *funk,
  427. struct rfm12_pkt *pkt,
  428. int length)
  429. {
  430. uint8_t request[] = { BRIDGE_CMD_TRANSMIT, length };
  431. int ret = funk_bridge_send(funk, request, sizeof(request), (uint8_t *)pkt, length);
  432. if (ret < 0)
  433. {
  434. return ret;
  435. }
  436. uint8_t cause = BRIDGE_CAUSE_SUCCESS;
  437. ret = funk_bridge_recv(funk, request[0], &cause, NULL, 0);
  438. if (ret != 0)
  439. {
  440. return -1;
  441. }
  442. #if (FUNK_PACKET_DEBUG == 1)
  443. char *dump = funk_print_data((uint8_t *)pkt, length);
  444. printf("funk_send_packet() cause=0x%02x length=0x%02x\n%s\n",
  445. cause, length, dump);
  446. free(dump);
  447. #endif
  448. return (cause != BRIDGE_CAUSE_SUCCESS);
  449. } /* funk_send_packet */
  450. /* *************************************************************************
  451. * funk_recv_packet
  452. * ************************************************************************* */
  453. static int funk_recv_packet(struct funk_privdata *funk,
  454. struct rfm12_pkt *pkt,
  455. int *length)
  456. {
  457. uint8_t request[] = { BRIDGE_CMD_RECEIVE, 0 };
  458. int ret = funk_bridge_send(funk, request, sizeof(request), NULL, 0);
  459. if (ret < 0)
  460. {
  461. return ret;
  462. }
  463. uint8_t cause = BRIDGE_CAUSE_SUCCESS;
  464. ret = funk_bridge_recv(funk, request[0], &cause, (uint8_t *)pkt, *length);
  465. if (ret < 0)
  466. {
  467. return -1;
  468. }
  469. *length = ret;
  470. #if (FUNK_PACKET_DEBUG == 1)
  471. char *dump = funk_print_data((uint8_t *)pkt, *length);
  472. printf("funk_recv_packet() cause=0x%02x length=0x%02x\n%s\n", cause, *length, dump);
  473. free(dump);
  474. #endif
  475. return (cause != BRIDGE_CAUSE_SUCCESS);
  476. } /* funk_recv_packet */
  477. /* *************************************************************************
  478. * funk_bridge_version
  479. * ************************************************************************* */
  480. static int funk_bridge_version(struct funk_privdata *funk,
  481. uint8_t *version,
  482. int size)
  483. {
  484. uint8_t request[] = { BRIDGE_CMD_VERSION, 0 };
  485. int ret = funk_bridge_send(funk, request, sizeof(request), NULL, 0);
  486. if (ret < 0)
  487. {
  488. return ret;
  489. }
  490. uint8_t cause = BRIDGE_CAUSE_SUCCESS;
  491. ret = funk_bridge_recv(funk, request[0], &cause, version, size);
  492. if (ret < 0)
  493. {
  494. return ret;
  495. }
  496. version[ret] = '\0';
  497. return (cause != BRIDGE_CAUSE_SUCCESS);
  498. } /* funk_bridge_version */
  499. /* *************************************************************************
  500. * funk_close_device
  501. * ************************************************************************* */
  502. static void funk_close_device(struct funk_privdata *funk)
  503. {
  504. /* delay close() / tcsetattr() */
  505. usleep(100000);
  506. tcsetattr(funk->fd, TCSANOW, &funk->oldtio);
  507. close(funk->fd);
  508. } /* funk_close_device */
  509. /* *************************************************************************
  510. * funk_open_device
  511. * ************************************************************************* */
  512. static int funk_open_device(struct funk_privdata *funk)
  513. {
  514. funk->fd = open(funk->device, O_RDWR | O_NOCTTY | O_CLOEXEC);
  515. if (funk->fd < 0)
  516. {
  517. perror("open()");
  518. return -1;
  519. }
  520. if (tcgetattr(funk->fd, &funk->oldtio) < 0)
  521. {
  522. perror("tcgetattr(oldtio)");
  523. close(funk->fd);
  524. return -1;
  525. }
  526. struct termios newtio;
  527. memset(&newtio, 0, sizeof(newtio));
  528. newtio.c_iflag |= IGNBRK;
  529. newtio.c_cflag |= B38400 | CS8 | CLOCAL | CREAD;
  530. newtio.c_cc[VMIN] = 1;
  531. newtio.c_cc[VTIME] = 0;
  532. int err = tcsetattr(funk->fd, TCSANOW, &newtio);
  533. if (err < 0)
  534. {
  535. perror("tcsetattr(newtio)");
  536. close(funk->fd);
  537. return -1;
  538. }
  539. funk->connected = 1;
  540. return 0;
  541. } /* funk_open_device */
  542. /* *************************************************************************
  543. * funk_switch_application
  544. * ************************************************************************* */
  545. static int funk_switch_application(struct funk_privdata *funk,
  546. uint8_t application)
  547. {
  548. struct rfm12_pkt packet;
  549. packet.dest_address = funk->address;
  550. packet.source_address = 0xCC; // TODO: changed in bridge
  551. packet.data_length = 0x04;
  552. packet.header_checksum = 0xCC; // TODO: calced in bridge
  553. packet.msg.command = MSG_CMD_SWITCHAPP_REQUEST;
  554. packet.msg.seqnum = ++funk->seqnum; // TODO: retransmit in bridge?
  555. packet.msg.cause = CAUSE_SUCCESS;
  556. packet.msg.p.switchapp.app = application;
  557. int ret = funk_send_packet(funk, &packet, 4 + packet.data_length);
  558. if (ret < 0)
  559. {
  560. fprintf(stderr, "funk_switch_application(): funk_send_packet()\n");
  561. return ret;
  562. }
  563. int response_size = sizeof(packet);
  564. ret = funk_recv_packet(funk, &packet, &response_size);
  565. if (ret < 0)
  566. {
  567. fprintf(stderr, "funk_switch_application(): funk_recv_packet()\n");
  568. return ret;
  569. }
  570. if ((packet.msg.command != MSG_CMD_SWITCHAPP_RESPONSE) ||
  571. (packet.msg.cause != CAUSE_SUCCESS)
  572. )
  573. {
  574. return -1;
  575. }
  576. return 0;
  577. } /* funk_switch_application */
  578. /* *************************************************************************
  579. * funk_read_version
  580. * ************************************************************************* */
  581. static int funk_read_version(struct funk_privdata *funk,
  582. uint8_t *version,
  583. uint16_t length)
  584. {
  585. struct rfm12_pkt packet;
  586. packet.dest_address = funk->address;
  587. packet.source_address = 0xCC; // TODO: changed in bridge
  588. packet.data_length = 0x03;
  589. packet.header_checksum = 0xCC; // TODO: calced in bridge
  590. packet.msg.command = MSG_CMD_VERSION_REQUEST;
  591. packet.msg.seqnum = ++funk->seqnum; // TODO: retransmit in bridge?
  592. packet.msg.cause = CAUSE_SUCCESS;
  593. int ret = funk_send_packet(funk, &packet, 4 + packet.data_length);
  594. if (ret < 0)
  595. {
  596. fprintf(stderr, "funk_read_version(): funk_send_packet()\n");
  597. return ret;
  598. }
  599. int response_size = sizeof(packet);
  600. ret = funk_recv_packet(funk, &packet, &response_size);
  601. if (ret < 0)
  602. {
  603. fprintf(stderr, "funk_read_version(): funk_recv_packet()\n");
  604. return ret;
  605. }
  606. if ((packet.msg.command != MSG_CMD_VERSION_RESPONSE) ||
  607. (packet.msg.cause != CAUSE_SUCCESS)
  608. )
  609. {
  610. return -1;
  611. }
  612. int i;
  613. for (i = 0; i < packet.data_length -3; i++)
  614. {
  615. version[i] = packet.msg.p.version.data[i] & 0x7F;
  616. }
  617. version[i] = '\0';
  618. return 0;
  619. } /* funk_read_version */
  620. /* *************************************************************************
  621. * funk_read_chipinfo
  622. * ************************************************************************* */
  623. static int funk_read_chipinfo(struct funk_privdata *funk,
  624. uint8_t *chipinfo,
  625. uint16_t length)
  626. {
  627. struct rfm12_pkt packet;
  628. packet.dest_address = funk->address;
  629. packet.source_address = 0xCC; // TODO: changed in bridge
  630. packet.data_length = 0x03;
  631. packet.header_checksum = 0xCC; // TODO: calced in bridge
  632. packet.msg.command = MSG_CMD_CHIPINFO_REQUEST;
  633. packet.msg.seqnum = ++funk->seqnum; // TODO: retransmit in bridge?
  634. packet.msg.cause = CAUSE_SUCCESS;
  635. int ret = funk_send_packet(funk, &packet, 4 + packet.data_length);
  636. if (ret < 0)
  637. {
  638. fprintf(stderr, "funk_read_chipinfo(): funk_send_packet()\n");
  639. return ret;
  640. }
  641. int response_size = sizeof(packet);
  642. ret = funk_recv_packet(funk, &packet, &response_size);
  643. if (ret < 0) {
  644. fprintf(stderr, "funk_read_chipinfo(): funk_recv_packet()\n");
  645. return ret;
  646. }
  647. if ((packet.msg.command != MSG_CMD_CHIPINFO_RESPONSE) ||
  648. (packet.msg.cause != CAUSE_SUCCESS)
  649. )
  650. {
  651. return -1;
  652. }
  653. memcpy(chipinfo, packet.msg.p.chipinfo.data, MIN(packet.data_length -3, length));
  654. return 0;
  655. } /* funk_read_chipinfo */
  656. /* *************************************************************************
  657. * funk_read_memory
  658. * ************************************************************************* */
  659. static int funk_read_memory(struct funk_privdata *funk,
  660. uint8_t *buffer,
  661. uint16_t size,
  662. uint8_t memtype,
  663. uint16_t address)
  664. {
  665. struct rfm12_pkt packet;
  666. packet.dest_address = funk->address;
  667. packet.source_address = 0xCC; // TODO: changed in bridge
  668. packet.data_length = 0x07;
  669. packet.header_checksum = 0xCC; // TODO: calced in bridge
  670. packet.msg.command = MSG_CMD_READ_REQUEST;
  671. packet.msg.seqnum = ++funk->seqnum; // TODO: retransmit in bridge?
  672. packet.msg.cause = CAUSE_SUCCESS;
  673. packet.msg.p.read_req.address = address;
  674. packet.msg.p.read_req.mem_type = memtype;
  675. packet.msg.p.read_req.size = size;
  676. int ret = funk_send_packet(funk, &packet, 4 + packet.data_length);
  677. if (ret < 0) {
  678. fprintf(stderr, "funk_read_memory(): funk_send_packet()\n");
  679. return ret;
  680. }
  681. int response_size = sizeof(packet);
  682. ret = funk_recv_packet(funk, &packet, &response_size);
  683. if (ret < 0) {
  684. fprintf(stderr, "funk_read_memory(): funk_recv_packet()\n");
  685. return ret;
  686. }
  687. if ((packet.msg.command != MSG_CMD_READ_RESPONSE) ||
  688. (packet.msg.cause != CAUSE_SUCCESS)
  689. )
  690. {
  691. return -1;
  692. }
  693. memcpy(buffer, packet.msg.p.read_rsp.data, MIN(packet.data_length -3, size));
  694. return 0;
  695. } /* funk_read_memory */
  696. /* *************************************************************************
  697. * __funk_write_memory
  698. * ************************************************************************* */
  699. static int __funk_write_memory(struct funk_privdata *funk,
  700. uint8_t *buffer,
  701. uint16_t size,
  702. uint8_t memtype,
  703. uint16_t address)
  704. {
  705. struct rfm12_pkt packet;
  706. packet.dest_address = funk->address;
  707. packet.source_address = 0xCC; // TODO: changed in bridge
  708. packet.data_length = 0x07 + size;
  709. packet.header_checksum = 0xCC; // TODO: calced in bridge
  710. packet.msg.command = MSG_CMD_WRITE_REQUEST;
  711. packet.msg.seqnum = ++funk->seqnum; // TODO: retransmit in bridge?
  712. packet.msg.cause = CAUSE_SUCCESS;
  713. packet.msg.p.write_req.address = address;
  714. packet.msg.p.write_req.mem_type = memtype;
  715. packet.msg.p.write_req.size = size;
  716. memcpy(packet.msg.p.write_req.data, buffer, size);
  717. int ret = funk_send_packet(funk, &packet, 4 + packet.data_length);
  718. if (ret < 0)
  719. {
  720. fprintf(stderr, "funk_write_memory(): funk_send_packet()\n");
  721. return ret;
  722. }
  723. int response_size = sizeof(packet);
  724. ret = funk_recv_packet(funk, &packet, &response_size);
  725. if (ret < 0)
  726. {
  727. fprintf(stderr, "funk_write_memory(): funk_recv_packet()\n");
  728. return ret;
  729. }
  730. if ((packet.msg.command != MSG_CMD_WRITE_RESPONSE) ||
  731. (packet.msg.cause != CAUSE_SUCCESS)
  732. )
  733. {
  734. return -1;
  735. }
  736. return 0;
  737. } /* __funk_write_memory */
  738. /* *************************************************************************
  739. * funk_write_memory
  740. * ************************************************************************* */
  741. static int funk_write_memory(struct funk_privdata *funk,
  742. uint8_t *buffer,
  743. uint16_t size,
  744. uint8_t memtype,
  745. uint16_t address)
  746. {
  747. if (memtype == MEMTYPE_EEPROM)
  748. {
  749. return __funk_write_memory(funk, buffer, size, memtype, address);
  750. }
  751. else if ((address & (funk->flashpage -1)) != 0x00)
  752. {
  753. fprintf(stderr, "funk_write_memory(): address 0x%04x not aligned to pagesize 0x%02x\n", address, funk->flashpage);
  754. return -1;
  755. }
  756. uint8_t *pagebuf = malloc(funk->flashpage);
  757. if (pagebuf == NULL)
  758. {
  759. perror("malloc()");
  760. return -1;
  761. }
  762. memcpy(pagebuf, buffer, size);
  763. memset(pagebuf + size, 0xFF, funk->flashpage - size);
  764. int pos = 0;
  765. int ret = 0;
  766. for (pos = 0; pos < funk->flashpage; pos += WRITE_BLOCK_SIZE)
  767. {
  768. ret = __funk_write_memory(funk, &pagebuf[pos], WRITE_BLOCK_SIZE, memtype, address + pos);
  769. if (ret < 0)
  770. {
  771. break;
  772. }
  773. }
  774. free(pagebuf);
  775. return ret;
  776. } /* funk_write_memory */
  777. /* *************************************************************************
  778. * funk_close
  779. * ************************************************************************* */
  780. static int funk_close(struct multiboot *mboot)
  781. {
  782. struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
  783. if (funk->connected)
  784. {
  785. funk_switch_application(funk, BOOTTYPE_APPLICATION);
  786. }
  787. funk_close_device(funk);
  788. return 0;
  789. } /* funk_close */
  790. /* *************************************************************************
  791. * funk_open
  792. * ************************************************************************* */
  793. static int funk_open(struct multiboot *mboot)
  794. {
  795. struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
  796. if (funk->address == 0)
  797. {
  798. fprintf(stderr, "abort: no address given\n");
  799. return -1;
  800. }
  801. if (funk->device == NULL)
  802. {
  803. fprintf(stderr, "abort: no device given\n");
  804. return -1;
  805. }
  806. if (funk_open_device(funk) < 0)
  807. {
  808. return -1;
  809. }
  810. printf("funkbridge dev : %-16s\n", funk->device);
  811. char bridge_version[20];
  812. if (funk_bridge_version(funk, (uint8_t *)bridge_version, sizeof(bridge_version)))
  813. {
  814. fprintf(stderr, "failed to get funkbridge version\n");
  815. funk_close(mboot);
  816. return -1;
  817. }
  818. printf("funkbridge ver : %-16s\n", bridge_version);
  819. if (funk_switch_application(funk, BOOTTYPE_BOOTLOADER))
  820. {
  821. fprintf(stderr, "failed to switch to bootloader (invalid address?)\n");
  822. funk_close(mboot);
  823. return -1;
  824. }
  825. printf("address : 0x%02X\n", funk->address);
  826. /* wait for watchdog and startup time */
  827. usleep(100000);
  828. char version[20];
  829. if (funk_read_version(funk, (uint8_t *)version, sizeof(version)))
  830. {
  831. fprintf(stderr, "failed to get bootloader version\n");
  832. funk_close(mboot);
  833. return -1;
  834. }
  835. uint8_t chipinfo[8];
  836. if (funk_read_chipinfo(funk, chipinfo, sizeof(chipinfo)))
  837. {
  838. fprintf(stderr, "failed to get bootloader chipinfo\n");
  839. funk_close(mboot);
  840. return -1;
  841. }
  842. const char *chipname = chipinfo_get_avr_name(chipinfo);
  843. funk->flashpage = chipinfo[3];
  844. funk->flashsize = (chipinfo[4] << 8) + chipinfo[5];
  845. funk->eepromsize = (chipinfo[6] << 8) + chipinfo[7];
  846. printf("version : %-16s (sig: 0x%02x 0x%02x 0x%02x => %s)\n",
  847. version, chipinfo[0], chipinfo[1], chipinfo[2], chipname);
  848. printf("flash size : 0x%04x / %5d (0x%02x bytes/page)\n",
  849. funk->flashsize, funk->flashsize, funk->flashpage);
  850. printf("eeprom size : 0x%04x / %5d\n",
  851. funk->eepromsize, funk->eepromsize);
  852. return 0;
  853. } /* funk_open */
  854. /* *************************************************************************
  855. * funk_read
  856. * ************************************************************************* */
  857. static int funk_read(struct multiboot *mboot,
  858. struct databuf *dbuf,
  859. int memtype)
  860. {
  861. struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
  862. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "reading flash" : "reading eeprom";
  863. int pos = 0;
  864. int size = (memtype == MEMTYPE_FLASH) ? funk->flashsize : funk->eepromsize;
  865. while (pos < size)
  866. {
  867. mboot->progress_cb(progress_msg, pos, size);
  868. int len = MIN(READ_BLOCK_SIZE, size - pos);
  869. if (funk_read_memory(funk, dbuf->data + pos, len, memtype, pos))
  870. {
  871. mboot->progress_cb(progress_msg, -1, -1);
  872. return -1;
  873. }
  874. pos += len;
  875. }
  876. dbuf->length = pos;
  877. mboot->progress_cb(progress_msg, pos, size);
  878. return 0;
  879. } /* funk_read */
  880. /* *************************************************************************
  881. * funk_write
  882. * ************************************************************************* */
  883. static int funk_write(struct multiboot *mboot,
  884. struct databuf *dbuf,
  885. int memtype)
  886. {
  887. struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
  888. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "writing flash" : "writing eeprom";
  889. int pos = 0;
  890. while (pos < dbuf->length)
  891. {
  892. mboot->progress_cb(progress_msg, pos, dbuf->length);
  893. int len = (memtype == MEMTYPE_FLASH) ? funk->flashpage : WRITE_BLOCK_SIZE;
  894. len = MIN(len, dbuf->length - pos);
  895. if (funk_write_memory(funk, dbuf->data + pos, len, memtype, pos))
  896. {
  897. mboot->progress_cb(progress_msg, -1, -1);
  898. return -1;
  899. }
  900. pos += len;
  901. }
  902. mboot->progress_cb(progress_msg, pos, dbuf->length);
  903. return 0;
  904. } /* funk_write */
  905. /* *************************************************************************
  906. * funk_verify
  907. * ************************************************************************* */
  908. static int funk_verify(struct multiboot *mboot,
  909. struct databuf *dbuf,
  910. int memtype)
  911. {
  912. struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
  913. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "verifing flash" : "verifing eeprom";
  914. int pos = 0;
  915. uint8_t comp[READ_BLOCK_SIZE];
  916. while (pos < dbuf->length)
  917. {
  918. mboot->progress_cb(progress_msg, pos, dbuf->length);
  919. int len = MIN(READ_BLOCK_SIZE, dbuf->length - pos);
  920. if (funk_read_memory(funk, comp, len, memtype, pos))
  921. {
  922. mboot->progress_cb(progress_msg, -1, -1);
  923. return -1;
  924. }
  925. if (memcmp(comp, dbuf->data + pos, len) != 0x00)
  926. {
  927. mboot->progress_cb(progress_msg, -1, -1);
  928. fprintf(stderr, "verify failed at page 0x%04x!!\n", pos);
  929. return -1;
  930. }
  931. pos += len;
  932. }
  933. dbuf->length = pos;
  934. mboot->progress_cb(progress_msg, pos, dbuf->length);
  935. return 0;
  936. } /* funk_verify */
  937. struct multiboot_ops funk_ops =
  938. {
  939. .alloc = funk_alloc,
  940. .free = funk_free,
  941. .get_memtype = funk_get_memtype,
  942. .get_memsize = funk_get_memsize,
  943. .open = funk_open,
  944. .close = funk_close,
  945. .read = funk_read,
  946. .write = funk_write,
  947. .verify = funk_verify,
  948. };