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.

1184 lines
33 KiB

  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. /* unused parameter */
  205. (void)mboot;
  206. if (strcmp(memname, "flash") == 0)
  207. {
  208. return MEMTYPE_FLASH;
  209. }
  210. else if (strcmp(memname, "eeprom") == 0)
  211. {
  212. return MEMTYPE_EEPROM;
  213. }
  214. return -1;
  215. } /* funk_get_memtype */
  216. /* *************************************************************************
  217. * optarg_copy
  218. * ************************************************************************* */
  219. static int funk_get_memsize(struct multiboot *mboot,
  220. int memtype)
  221. {
  222. struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
  223. if (!funk->connected)
  224. {
  225. return 0;
  226. }
  227. switch (memtype)
  228. {
  229. case MEMTYPE_FLASH:
  230. return funk->flashsize;
  231. case MEMTYPE_EEPROM:
  232. return funk->eepromsize;
  233. default:
  234. return 0;
  235. }
  236. } /* funk_get_memsize */
  237. /* *************************************************************************
  238. * funk_serial_read
  239. * ************************************************************************* */
  240. static int funk_serial_read(int fd, void *data, int size)
  241. {
  242. int pos = 0;
  243. while (1)
  244. {
  245. fd_set fdset;
  246. struct timeval timeout = { .tv_sec = 1, .tv_usec = 0 };
  247. FD_ZERO(&fdset);
  248. FD_SET(fd, &fdset);
  249. int ret = select(fd +1, &fdset, NULL, NULL, &timeout);
  250. if (ret == -1)
  251. {
  252. perror("select");
  253. return -1;
  254. }
  255. else if (ret == 0)
  256. {
  257. break;
  258. }
  259. else if (FD_ISSET(fd, &fdset))
  260. {
  261. int len = read(fd, data + pos, size - pos);
  262. if (len < 0)
  263. {
  264. return -1;
  265. }
  266. else
  267. {
  268. pos += len;
  269. if (pos == size)
  270. {
  271. break;
  272. }
  273. }
  274. }
  275. }
  276. return pos;
  277. } /* funk_serial_read */
  278. #if (FUNK_BRIDGE_DEBUG == 1) || (FUNK_PACKET_DEBUG == 1)
  279. /* *************************************************************************
  280. * funk_print_data
  281. * ************************************************************************* */
  282. static char * funk_print_data(uint8_t *data, uint16_t length)
  283. {
  284. int pos = 0, i = 0, j;
  285. char *buf = malloc(length * 4 + 64);
  286. while (pos < length)
  287. {
  288. i += sprintf(buf + i, "%04X: ", pos);
  289. for (j = 0; j < 16; j++)
  290. {
  291. if (pos + j < length)
  292. {
  293. i += sprintf(buf + i, "%02X", data[pos + j]);
  294. }
  295. else
  296. {
  297. i += sprintf(buf + i, " ");
  298. if (j % 2)
  299. {
  300. buf[i++] = ' ';
  301. }
  302. }
  303. for (j = 0; j < 16; j++)
  304. {
  305. if (pos + j < length)
  306. {
  307. unsigned char val = data[pos + j];
  308. if (val >= 0x20 && val < 0x80)
  309. {
  310. buf[i++] = val;
  311. }
  312. else
  313. {
  314. buf[i++] = '.';
  315. }
  316. }
  317. else
  318. {
  319. buf[i++] = ' ';
  320. }
  321. }
  322. pos += 16;
  323. buf[i++] = '\r';
  324. buf[i++] = '\n';
  325. }
  326. buf[i] = 0;
  327. return buf;
  328. } /* funk_print_data */
  329. #endif
  330. /* *************************************************************************
  331. * funk_bridge_send
  332. * ************************************************************************* */
  333. static int funk_bridge_send(struct funk_privdata *funk,
  334. uint8_t *header,
  335. uint8_t headerlength,
  336. uint8_t *data,
  337. uint8_t datalength)
  338. {
  339. if (headerlength > 0)
  340. {
  341. if (write(funk->fd, header, headerlength) != headerlength)
  342. {
  343. return -1;
  344. }
  345. }
  346. if (datalength > 0)
  347. {
  348. if (write(funk->fd, data, datalength) != datalength)
  349. {
  350. return -1;
  351. }
  352. }
  353. #if (FUNK_BRIDGE_DEBUG == 1)
  354. char *dump = funk_print_data(data, datalength);
  355. printf("funk_bridge_send() cmd=0x%02x length=0x%02x\n%s\n", header[0], datalength, dump);
  356. free(dump);
  357. #endif
  358. return 0;
  359. } /* funk_bridge_send */
  360. /* *************************************************************************
  361. * funk_bridge_recv
  362. * ************************************************************************* */
  363. static int funk_bridge_recv(struct funk_privdata *funk,
  364. uint8_t command,
  365. uint8_t *cause,
  366. uint8_t *buffer,
  367. int buffersize)
  368. {
  369. uint8_t response[3];
  370. int len;
  371. len = funk_serial_read(funk->fd, response, sizeof(response));
  372. if (len != sizeof(response))
  373. {
  374. fprintf(stderr, "short read() from device\n");
  375. return -1;
  376. }
  377. if (response[0] != command)
  378. {
  379. fprintf(stderr, "invalid command response (0x%02x != 0x%02x)\n",
  380. response[0], command);
  381. return -1;
  382. }
  383. *cause = response[1];
  384. uint16_t length = response[2];
  385. uint16_t bufferpos = 0;
  386. while (length > 0)
  387. {
  388. /* free space in output buffer? */
  389. if ((bufferpos < buffersize) && (buffer != NULL))
  390. {
  391. uint16_t size = MIN(buffersize - bufferpos, length);
  392. len = funk_serial_read(funk->fd, buffer + bufferpos, size);
  393. if (len <= 0)
  394. {
  395. fprintf(stderr, "short read() from device (%d != %d)\n",
  396. len, size);
  397. return -1;
  398. }
  399. bufferpos += len;
  400. length -= len;
  401. }
  402. else
  403. {
  404. uint8_t dummy[256];
  405. /* no space in output buffer, but device still sends data -> do dummy read */
  406. uint16_t size = MIN(sizeof(dummy), length);
  407. len = funk_serial_read(funk->fd, dummy, size);
  408. if (len <= 0)
  409. {
  410. fprintf(stderr, "short read() from device (%d != %d)\n",
  411. len, size);
  412. return -1;
  413. }
  414. length -= len;
  415. }
  416. }
  417. #if (FUNK_BRIDGE_DEBUG == 1)
  418. char *dump = funk_print_data(buffer, bufferpos);
  419. printf("funk_bridge_recv() cmd=0x%02x cause=0x%02x length=0x%02x\n%s\n",
  420. command, *cause, length, dump);
  421. free(dump);
  422. #endif
  423. return bufferpos;
  424. } /* funk_bridge_recv */
  425. /* *************************************************************************
  426. * funk_send_packet
  427. * ************************************************************************* */
  428. static int funk_send_packet(struct funk_privdata *funk,
  429. struct rfm12_pkt *pkt,
  430. int length)
  431. {
  432. uint8_t request[] = { BRIDGE_CMD_TRANSMIT, length };
  433. int ret = funk_bridge_send(funk, request, sizeof(request), (uint8_t *)pkt, length);
  434. if (ret < 0)
  435. {
  436. return ret;
  437. }
  438. uint8_t cause = BRIDGE_CAUSE_SUCCESS;
  439. ret = funk_bridge_recv(funk, request[0], &cause, NULL, 0);
  440. if (ret != 0)
  441. {
  442. return -1;
  443. }
  444. #if (FUNK_PACKET_DEBUG == 1)
  445. char *dump = funk_print_data((uint8_t *)pkt, length);
  446. printf("funk_send_packet() cause=0x%02x length=0x%02x\n%s\n",
  447. cause, length, dump);
  448. free(dump);
  449. #endif
  450. return (cause != BRIDGE_CAUSE_SUCCESS);
  451. } /* funk_send_packet */
  452. /* *************************************************************************
  453. * funk_recv_packet
  454. * ************************************************************************* */
  455. static int funk_recv_packet(struct funk_privdata *funk,
  456. struct rfm12_pkt *pkt,
  457. int *length)
  458. {
  459. uint8_t request[] = { BRIDGE_CMD_RECEIVE, 0 };
  460. int ret = funk_bridge_send(funk, request, sizeof(request), NULL, 0);
  461. if (ret < 0)
  462. {
  463. return ret;
  464. }
  465. uint8_t cause = BRIDGE_CAUSE_SUCCESS;
  466. ret = funk_bridge_recv(funk, request[0], &cause, (uint8_t *)pkt, *length);
  467. if (ret < 0)
  468. {
  469. return -1;
  470. }
  471. *length = ret;
  472. #if (FUNK_PACKET_DEBUG == 1)
  473. char *dump = funk_print_data((uint8_t *)pkt, *length);
  474. printf("funk_recv_packet() cause=0x%02x length=0x%02x\n%s\n", cause, *length, dump);
  475. free(dump);
  476. #endif
  477. return (cause != BRIDGE_CAUSE_SUCCESS);
  478. } /* funk_recv_packet */
  479. /* *************************************************************************
  480. * funk_bridge_version
  481. * ************************************************************************* */
  482. static int funk_bridge_version(struct funk_privdata *funk,
  483. uint8_t *version,
  484. int size)
  485. {
  486. uint8_t request[] = { BRIDGE_CMD_VERSION, 0 };
  487. int ret = funk_bridge_send(funk, request, sizeof(request), NULL, 0);
  488. if (ret < 0)
  489. {
  490. return ret;
  491. }
  492. uint8_t cause = BRIDGE_CAUSE_SUCCESS;
  493. ret = funk_bridge_recv(funk, request[0], &cause, version, size);
  494. if (ret < 0)
  495. {
  496. return ret;
  497. }
  498. version[ret] = '\0';
  499. return (cause != BRIDGE_CAUSE_SUCCESS);
  500. } /* funk_bridge_version */
  501. /* *************************************************************************
  502. * funk_close_device
  503. * ************************************************************************* */
  504. static void funk_close_device(struct funk_privdata *funk)
  505. {
  506. /* delay close() / tcsetattr() */
  507. usleep(100000);
  508. tcsetattr(funk->fd, TCSANOW, &funk->oldtio);
  509. close(funk->fd);
  510. } /* funk_close_device */
  511. /* *************************************************************************
  512. * funk_open_device
  513. * ************************************************************************* */
  514. static int funk_open_device(struct funk_privdata *funk)
  515. {
  516. funk->fd = open(funk->device, O_RDWR | O_NOCTTY | O_CLOEXEC);
  517. if (funk->fd < 0)
  518. {
  519. perror("open()");
  520. return -1;
  521. }
  522. if (tcgetattr(funk->fd, &funk->oldtio) < 0)
  523. {
  524. perror("tcgetattr(oldtio)");
  525. close(funk->fd);
  526. return -1;
  527. }
  528. struct termios newtio;
  529. memset(&newtio, 0, sizeof(newtio));
  530. newtio.c_iflag |= IGNBRK;
  531. newtio.c_cflag |= B38400 | CS8 | CLOCAL | CREAD;
  532. newtio.c_cc[VMIN] = 1;
  533. newtio.c_cc[VTIME] = 0;
  534. int err = tcsetattr(funk->fd, TCSANOW, &newtio);
  535. if (err < 0)
  536. {
  537. perror("tcsetattr(newtio)");
  538. close(funk->fd);
  539. return -1;
  540. }
  541. funk->connected = 1;
  542. return 0;
  543. } /* funk_open_device */
  544. /* *************************************************************************
  545. * funk_switch_application
  546. * ************************************************************************* */
  547. static int funk_switch_application(struct funk_privdata *funk,
  548. uint8_t application)
  549. {
  550. struct rfm12_pkt packet;
  551. packet.dest_address = funk->address;
  552. packet.source_address = 0xCC; // TODO: changed in bridge
  553. packet.data_length = 0x04;
  554. packet.header_checksum = 0xCC; // TODO: calced in bridge
  555. packet.msg.command = MSG_CMD_SWITCHAPP_REQUEST;
  556. packet.msg.seqnum = ++funk->seqnum; // TODO: retransmit in bridge?
  557. packet.msg.cause = CAUSE_SUCCESS;
  558. packet.msg.p.switchapp.app = application;
  559. int ret = funk_send_packet(funk, &packet, 4 + packet.data_length);
  560. if (ret < 0)
  561. {
  562. fprintf(stderr, "funk_switch_application(): funk_send_packet()\n");
  563. return ret;
  564. }
  565. int response_size = sizeof(packet);
  566. ret = funk_recv_packet(funk, &packet, &response_size);
  567. if (ret < 0)
  568. {
  569. fprintf(stderr, "funk_switch_application(): funk_recv_packet()\n");
  570. return ret;
  571. }
  572. if ((packet.msg.command != MSG_CMD_SWITCHAPP_RESPONSE) ||
  573. (packet.msg.cause != CAUSE_SUCCESS)
  574. )
  575. {
  576. return -1;
  577. }
  578. return 0;
  579. } /* funk_switch_application */
  580. /* *************************************************************************
  581. * funk_read_version
  582. * ************************************************************************* */
  583. static int funk_read_version(struct funk_privdata *funk,
  584. uint8_t *version,
  585. uint16_t length)
  586. {
  587. struct rfm12_pkt packet;
  588. packet.dest_address = funk->address;
  589. packet.source_address = 0xCC; // TODO: changed in bridge
  590. packet.data_length = 0x03;
  591. packet.header_checksum = 0xCC; // TODO: calced in bridge
  592. packet.msg.command = MSG_CMD_VERSION_REQUEST;
  593. packet.msg.seqnum = ++funk->seqnum; // TODO: retransmit in bridge?
  594. packet.msg.cause = CAUSE_SUCCESS;
  595. int ret = funk_send_packet(funk, &packet, 4 + packet.data_length);
  596. if (ret < 0)
  597. {
  598. fprintf(stderr, "funk_read_version(): funk_send_packet()\n");
  599. return ret;
  600. }
  601. int response_size = sizeof(packet);
  602. ret = funk_recv_packet(funk, &packet, &response_size);
  603. if (ret < 0)
  604. {
  605. fprintf(stderr, "funk_read_version(): funk_recv_packet()\n");
  606. return ret;
  607. }
  608. if ((packet.msg.command != MSG_CMD_VERSION_RESPONSE) ||
  609. (packet.msg.cause != CAUSE_SUCCESS)
  610. )
  611. {
  612. return -1;
  613. }
  614. int i;
  615. for (i = 0; i < packet.data_length -3; i++)
  616. {
  617. version[i] = packet.msg.p.version.data[i] & 0x7F;
  618. }
  619. version[i] = '\0';
  620. return 0;
  621. } /* funk_read_version */
  622. /* *************************************************************************
  623. * funk_read_chipinfo
  624. * ************************************************************************* */
  625. static int funk_read_chipinfo(struct funk_privdata *funk,
  626. uint8_t *chipinfo,
  627. uint16_t length)
  628. {
  629. struct rfm12_pkt packet;
  630. packet.dest_address = funk->address;
  631. packet.source_address = 0xCC; // TODO: changed in bridge
  632. packet.data_length = 0x03;
  633. packet.header_checksum = 0xCC; // TODO: calced in bridge
  634. packet.msg.command = MSG_CMD_CHIPINFO_REQUEST;
  635. packet.msg.seqnum = ++funk->seqnum; // TODO: retransmit in bridge?
  636. packet.msg.cause = CAUSE_SUCCESS;
  637. int ret = funk_send_packet(funk, &packet, 4 + packet.data_length);
  638. if (ret < 0)
  639. {
  640. fprintf(stderr, "funk_read_chipinfo(): funk_send_packet()\n");
  641. return ret;
  642. }
  643. int response_size = sizeof(packet);
  644. ret = funk_recv_packet(funk, &packet, &response_size);
  645. if (ret < 0) {
  646. fprintf(stderr, "funk_read_chipinfo(): funk_recv_packet()\n");
  647. return ret;
  648. }
  649. if ((packet.msg.command != MSG_CMD_CHIPINFO_RESPONSE) ||
  650. (packet.msg.cause != CAUSE_SUCCESS)
  651. )
  652. {
  653. return -1;
  654. }
  655. memcpy(chipinfo, packet.msg.p.chipinfo.data, MIN(packet.data_length -3, length));
  656. return 0;
  657. } /* funk_read_chipinfo */
  658. /* *************************************************************************
  659. * funk_read_memory
  660. * ************************************************************************* */
  661. static int funk_read_memory(struct funk_privdata *funk,
  662. uint8_t *buffer,
  663. uint16_t size,
  664. uint8_t memtype,
  665. uint16_t address)
  666. {
  667. struct rfm12_pkt packet;
  668. packet.dest_address = funk->address;
  669. packet.source_address = 0xCC; // TODO: changed in bridge
  670. packet.data_length = 0x07;
  671. packet.header_checksum = 0xCC; // TODO: calced in bridge
  672. packet.msg.command = MSG_CMD_READ_REQUEST;
  673. packet.msg.seqnum = ++funk->seqnum; // TODO: retransmit in bridge?
  674. packet.msg.cause = CAUSE_SUCCESS;
  675. packet.msg.p.read_req.address = address;
  676. packet.msg.p.read_req.mem_type = memtype;
  677. packet.msg.p.read_req.size = size;
  678. int ret = funk_send_packet(funk, &packet, 4 + packet.data_length);
  679. if (ret < 0) {
  680. fprintf(stderr, "funk_read_memory(): funk_send_packet()\n");
  681. return ret;
  682. }
  683. int response_size = sizeof(packet);
  684. ret = funk_recv_packet(funk, &packet, &response_size);
  685. if (ret < 0) {
  686. fprintf(stderr, "funk_read_memory(): funk_recv_packet()\n");
  687. return ret;
  688. }
  689. if ((packet.msg.command != MSG_CMD_READ_RESPONSE) ||
  690. (packet.msg.cause != CAUSE_SUCCESS)
  691. )
  692. {
  693. return -1;
  694. }
  695. memcpy(buffer, packet.msg.p.read_rsp.data, MIN(packet.data_length -3, size));
  696. return 0;
  697. } /* funk_read_memory */
  698. /* *************************************************************************
  699. * __funk_write_memory
  700. * ************************************************************************* */
  701. static int __funk_write_memory(struct funk_privdata *funk,
  702. uint8_t *buffer,
  703. uint16_t size,
  704. uint8_t memtype,
  705. uint16_t address)
  706. {
  707. struct rfm12_pkt packet;
  708. packet.dest_address = funk->address;
  709. packet.source_address = 0xCC; // TODO: changed in bridge
  710. packet.data_length = 0x07 + size;
  711. packet.header_checksum = 0xCC; // TODO: calced in bridge
  712. packet.msg.command = MSG_CMD_WRITE_REQUEST;
  713. packet.msg.seqnum = ++funk->seqnum; // TODO: retransmit in bridge?
  714. packet.msg.cause = CAUSE_SUCCESS;
  715. packet.msg.p.write_req.address = address;
  716. packet.msg.p.write_req.mem_type = memtype;
  717. packet.msg.p.write_req.size = size;
  718. memcpy(packet.msg.p.write_req.data, buffer, size);
  719. int ret = funk_send_packet(funk, &packet, 4 + packet.data_length);
  720. if (ret < 0)
  721. {
  722. fprintf(stderr, "funk_write_memory(): funk_send_packet()\n");
  723. return ret;
  724. }
  725. int response_size = sizeof(packet);
  726. ret = funk_recv_packet(funk, &packet, &response_size);
  727. if (ret < 0)
  728. {
  729. fprintf(stderr, "funk_write_memory(): funk_recv_packet()\n");
  730. return ret;
  731. }
  732. if ((packet.msg.command != MSG_CMD_WRITE_RESPONSE) ||
  733. (packet.msg.cause != CAUSE_SUCCESS)
  734. )
  735. {
  736. return -1;
  737. }
  738. return 0;
  739. } /* __funk_write_memory */
  740. /* *************************************************************************
  741. * funk_write_memory
  742. * ************************************************************************* */
  743. static int funk_write_memory(struct funk_privdata *funk,
  744. uint8_t *buffer,
  745. uint16_t size,
  746. uint8_t memtype,
  747. uint16_t address)
  748. {
  749. if (memtype == MEMTYPE_EEPROM)
  750. {
  751. return __funk_write_memory(funk, buffer, size, memtype, address);
  752. }
  753. else if ((address & (funk->flashpage -1)) != 0x00)
  754. {
  755. fprintf(stderr, "funk_write_memory(): address 0x%04x not aligned to pagesize 0x%02x\n", address, funk->flashpage);
  756. return -1;
  757. }
  758. uint8_t *pagebuf = malloc(funk->flashpage);
  759. if (pagebuf == NULL)
  760. {
  761. perror("malloc()");
  762. return -1;
  763. }
  764. memcpy(pagebuf, buffer, size);
  765. memset(pagebuf + size, 0xFF, funk->flashpage - size);
  766. int pos = 0;
  767. int ret = 0;
  768. for (pos = 0; pos < funk->flashpage; pos += WRITE_BLOCK_SIZE)
  769. {
  770. ret = __funk_write_memory(funk, &pagebuf[pos], WRITE_BLOCK_SIZE, memtype, address + pos);
  771. if (ret < 0)
  772. {
  773. break;
  774. }
  775. }
  776. free(pagebuf);
  777. return ret;
  778. } /* funk_write_memory */
  779. /* *************************************************************************
  780. * funk_close
  781. * ************************************************************************* */
  782. static int funk_close(struct multiboot *mboot)
  783. {
  784. struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
  785. if (funk->connected)
  786. {
  787. funk_switch_application(funk, BOOTTYPE_APPLICATION);
  788. }
  789. funk_close_device(funk);
  790. return 0;
  791. } /* funk_close */
  792. /* *************************************************************************
  793. * funk_open
  794. * ************************************************************************* */
  795. static int funk_open(struct multiboot *mboot)
  796. {
  797. struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
  798. if (funk->address == 0)
  799. {
  800. fprintf(stderr, "abort: no address given\n");
  801. return -1;
  802. }
  803. if (funk->device == NULL)
  804. {
  805. fprintf(stderr, "abort: no device given\n");
  806. return -1;
  807. }
  808. if (funk_open_device(funk) < 0)
  809. {
  810. return -1;
  811. }
  812. printf("funkbridge dev : %-16s\n", funk->device);
  813. char bridge_version[20];
  814. if (funk_bridge_version(funk, (uint8_t *)bridge_version, sizeof(bridge_version)))
  815. {
  816. fprintf(stderr, "failed to get funkbridge version\n");
  817. funk_close(mboot);
  818. return -1;
  819. }
  820. printf("funkbridge ver : %-16s\n", bridge_version);
  821. if (funk_switch_application(funk, BOOTTYPE_BOOTLOADER))
  822. {
  823. fprintf(stderr, "failed to switch to bootloader (invalid address?)\n");
  824. funk_close(mboot);
  825. return -1;
  826. }
  827. printf("address : 0x%02X\n", funk->address);
  828. /* wait for watchdog and startup time */
  829. usleep(100000);
  830. char version[20];
  831. if (funk_read_version(funk, (uint8_t *)version, sizeof(version)))
  832. {
  833. fprintf(stderr, "failed to get bootloader version\n");
  834. funk_close(mboot);
  835. return -1;
  836. }
  837. uint8_t chipinfo[8];
  838. if (funk_read_chipinfo(funk, chipinfo, sizeof(chipinfo)))
  839. {
  840. fprintf(stderr, "failed to get bootloader chipinfo\n");
  841. funk_close(mboot);
  842. return -1;
  843. }
  844. const char *chipname = chipinfo_get_avr_name(chipinfo);
  845. funk->flashpage = chipinfo[3];
  846. funk->flashsize = (chipinfo[4] << 8) + chipinfo[5];
  847. funk->eepromsize = (chipinfo[6] << 8) + chipinfo[7];
  848. printf("version : %-16s (sig: 0x%02x 0x%02x 0x%02x => %s)\n",
  849. version, chipinfo[0], chipinfo[1], chipinfo[2], chipname);
  850. printf("flash size : 0x%04x / %5d (0x%02x bytes/page)\n",
  851. funk->flashsize, funk->flashsize, funk->flashpage);
  852. printf("eeprom size : 0x%04x / %5d\n",
  853. funk->eepromsize, funk->eepromsize);
  854. return 0;
  855. } /* funk_open */
  856. /* *************************************************************************
  857. * funk_read
  858. * ************************************************************************* */
  859. static int funk_read(struct multiboot *mboot,
  860. struct databuf *dbuf,
  861. int memtype)
  862. {
  863. struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
  864. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "reading flash" : "reading eeprom";
  865. uint16_t pos = 0;
  866. uint16_t size = (memtype == MEMTYPE_FLASH) ? funk->flashsize : funk->eepromsize;
  867. while (pos < size)
  868. {
  869. mboot->progress_cb(progress_msg, pos, size);
  870. uint16_t len = MIN(READ_BLOCK_SIZE, size - pos);
  871. if (funk_read_memory(funk, dbuf->data + pos, len, memtype, pos))
  872. {
  873. mboot->progress_cb(progress_msg, -1, -1);
  874. return -1;
  875. }
  876. pos += len;
  877. }
  878. dbuf->length = pos;
  879. mboot->progress_cb(progress_msg, pos, size);
  880. return 0;
  881. } /* funk_read */
  882. /* *************************************************************************
  883. * funk_write
  884. * ************************************************************************* */
  885. static int funk_write(struct multiboot *mboot,
  886. struct databuf *dbuf,
  887. int memtype)
  888. {
  889. struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
  890. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "writing flash" : "writing eeprom";
  891. uint16_t pos = 0;
  892. while (pos < dbuf->length)
  893. {
  894. mboot->progress_cb(progress_msg, pos, dbuf->length);
  895. uint16_t len = (memtype == MEMTYPE_FLASH) ? funk->flashpage : WRITE_BLOCK_SIZE;
  896. len = MIN(len, dbuf->length - pos);
  897. if (funk_write_memory(funk, dbuf->data + pos, len, memtype, pos))
  898. {
  899. mboot->progress_cb(progress_msg, -1, -1);
  900. return -1;
  901. }
  902. pos += len;
  903. }
  904. mboot->progress_cb(progress_msg, pos, dbuf->length);
  905. return 0;
  906. } /* funk_write */
  907. /* *************************************************************************
  908. * funk_verify
  909. * ************************************************************************* */
  910. static int funk_verify(struct multiboot *mboot,
  911. struct databuf *dbuf,
  912. int memtype)
  913. {
  914. struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
  915. char *progress_msg = (memtype == MEMTYPE_FLASH) ? "verifing flash" : "verifing eeprom";
  916. uint16_t pos = 0;
  917. uint8_t comp[READ_BLOCK_SIZE];
  918. while (pos < dbuf->length)
  919. {
  920. mboot->progress_cb(progress_msg, pos, dbuf->length);
  921. uint16_t len = MIN(READ_BLOCK_SIZE, dbuf->length - pos);
  922. if (funk_read_memory(funk, comp, len, memtype, pos))
  923. {
  924. mboot->progress_cb(progress_msg, -1, -1);
  925. return -1;
  926. }
  927. if (memcmp(comp, dbuf->data + pos, len) != 0x00)
  928. {
  929. mboot->progress_cb(progress_msg, -1, -1);
  930. fprintf(stderr, "verify failed at page 0x%04x!!\n", pos);
  931. return -1;
  932. }
  933. pos += len;
  934. }
  935. dbuf->length = pos;
  936. mboot->progress_cb(progress_msg, pos, dbuf->length);
  937. return 0;
  938. } /* funk_verify */
  939. struct multiboot_ops funk_ops =
  940. {
  941. .exec_name = "funkboot",
  942. .alloc = funk_alloc,
  943. .free = funk_free,
  944. .get_memtype = funk_get_memtype,
  945. .get_memsize = funk_get_memsize,
  946. .open = funk_open,
  947. .close = funk_close,
  948. .read = funk_read,
  949. .write = funk_write,
  950. .verify = funk_verify,
  951. };