/* bwbootloader.c */ /* binwatch - Tiny binary wristwatch. {{{ * * Copyright (C) 2010 Nicolas Schodet * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Contact : * Web: http://ni.fr.eu.org/ * Email: * }}} */ #include "common.h" #include "modules/twi/twi.h" #include "modules/utils/utils.h" #include "modules/utils/byte.h" #include "bwbootloader.h" #include "prog.h" #include "timer.h" #include /** Start application when it reach zero. */ volatile uint8_t start_delay; /** Stop start delay counter when 1. */ volatile uint8_t start_delay_pause; int main (void) { twi_init (0xb8); timer_init (); #if AC_BWBOOTLOADER_BOOTSTRAP start_delay_pause = 1; #endif /* Handle bootloader messages. */ start_delay = 40; while (start_delay) { twi_update (); if (!start_delay_pause && timer_overflowed ()) start_delay--; } /* Stop bootloader, start application. */ twi_uninit (); timer_uninit (); prog_start (); return 0; } void bwbootloader_recv (const uint8_t *buffer, uint8_t size) { /* Stop start countdown. */ start_delay_pause = 1; /* Command is the first byte, it will be repeated as acknowledgement. * Words are little endian. */ static uint8_t rbuffer[AC_TWI_SLAVE_SEND_BUFFER_SIZE]; if (size != 0) { switch (buffer[0]) { case BWBOOTLOADER_INFO: /* Return informations. * => * - 12b: 'bwbootloader'. * - b: page size. * - w: flash size (minus bootloader size). */ if (size != 1) break; rbuffer[0] = buffer[0]; memcpy (&rbuffer[1], BWBOOTLOADER_SIGNATURE, 12); rbuffer[13] = PROG_PAGE_SIZE; rbuffer[14] = BWBOOTLOADER_LIMIT & 0xff; rbuffer[15] = BWBOOTLOADER_LIMIT >> 8; twi_slave_update (rbuffer, 16); return; case BWBOOTLOADER_START: /* Start application. */ if (size != 1) break; start_delay_pause = 0; start_delay = 4; twi_slave_update (buffer, 1); return; case BWBOOTLOADER_READ: /* Read from flash. * - w: address. * - b: size. * => * - w: address. * - size x b: flash content. */ if (size != 4 || buffer[3] > AC_TWI_SLAVE_SEND_BUFFER_SIZE - 3) break; rbuffer[0] = buffer[0]; rbuffer[1] = buffer[1]; rbuffer[2] = buffer[2]; prog_read (v8_to_v16 (buffer[2], buffer[1]), &rbuffer[3], buffer[3]); twi_slave_update (rbuffer, buffer[3] + 3); return; case BWBOOTLOADER_PAGE_WRITE: /* Write flash page. * - w: address. * - b: size (must be PROG_PAGE_SIZE). * - size x b: page content. * => * - w: address. */ if (size != PROG_PAGE_SIZE + 4 || buffer[3] != PROG_PAGE_SIZE) break; if (!prog_page_write (v8_to_v16 (buffer[2], buffer[1]), &buffer[4])) break; twi_slave_update (buffer, 3); return; case BWBOOTLOADER_READ_FUSES: /* Read fuse bytes. * => * - b: low fuses. * - b: high fuses. * - b: extended fuses. */ if (size != 1) break; rbuffer[0] = buffer[0]; prog_read_fuses (&rbuffer[1]); twi_slave_update (rbuffer, 4); return; } } /* Error. */ twi_slave_update (NULL, 0); }