/*************************************************************************** * Copyright (C) 11/2014 by Olaf Rempel * * razzor@kopf-tisch.de * * * * 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; version 2 of the License, * * * * 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. * ***************************************************************************/ #include #include #include #include #include #include "target.h" #include "rfm12.h" /* *********************************************************************** */ #define BOOTWAIT_EXPIRED 0x0000 #define BOOTWAIT_INTERRUPTED 0xFFFF #define MSG_TYPE_REQUEST 0x00 /* master -> slave req */ #define MSG_TYPE_CONFIRMATION 0x40 /* master -> slave rsp */ #define MSG_TYPE_INDICATION 0x80 /* slave -> master req */ #define MSG_TYPE_RESPONSE 0xC0 /* slave -> master rsp */ #define MSG_TYPE_MASK 0xC0 #define MSG_CMD_MASK 0x3F #define MSG_CMD_SWITCHAPP_REQUEST (MSG_TYPE_REQUEST | 0x20) #define MSG_CMD_SWITCHAPP_RESPONSE (MSG_TYPE_RESPONSE | 0x20) #define MSG_CMD_VERSION_REQUEST (MSG_TYPE_REQUEST | 0x21) #define MSG_CMD_VERSION_RESPONSE (MSG_TYPE_RESPONSE | 0x21) #define MSG_CMD_CHIPINFO_REQUEST (MSG_TYPE_REQUEST | 0x22) #define MSG_CMD_CHIPINFO_RESPONSE (MSG_TYPE_RESPONSE | 0x22) #define MSG_CMD_READ_REQUEST (MSG_TYPE_REQUEST | 0x23) #define MSG_CMD_READ_RESPONSE (MSG_TYPE_RESPONSE | 0x23) #define MSG_CMD_WRITE_REQUEST (MSG_TYPE_REQUEST | 0x24) #define MSG_CMD_WRITE_RESPONSE (MSG_TYPE_RESPONSE | 0x24) #define CAUSE_SUCCESS 0x00 #define CAUSE_NOT_SUPPORTED 0xF0 #define CAUSE_INVALID_PARAMETER 0xF1 #define CAUSE_UNSPECIFIED_ERROR 0xFF #define BOOTMODE_BOOTLOADER 0x00 #define BOOTMODE_APPLICATION 0x80 #define MEMTYPE_FLASH 0x01 #define MEMTYPE_EEPROM 0x02 /* *********************************************************************** */ struct bootloader_msg { uint8_t command; uint8_t seqnum; uint8_t cause; union { struct { uint8_t app; } switchapp; struct { uint8_t data[16]; } version; struct { uint8_t data[8]; } chipinfo; struct { uint16_t address; uint8_t mem_type; uint8_t size; } read_req; struct { uint8_t data[32]; } read_rsp; struct { uint16_t address; uint8_t mem_type; uint8_t size; uint8_t data[32]; } write_req; } p; }; /* *********************************************************************** */ #define LED_RX 0 #define LED_TX 1 static uint8_t led_timer[2]; volatile static uint8_t clock_tick; const static uint8_t version_info[16] = VERSION_STRING; const static uint8_t chip_info[8] = { SIGNATURE_BYTES, SPM_PAGESIZE, ((BOOTLOADER_START) >> 8) & 0xFF, (BOOTLOADER_START) & 0xFF, ((E2END +1) >> 8 & 0xFF), (E2END +1) & 0xFF }; /* *********************************************************************** */ static void read_flash(uint8_t *data, uint16_t address, uint8_t size) { while (size--) { *data++ = pgm_read_byte_near(address++); } } /* read_flash_byte */ static void write_flash(uint8_t *data, uint16_t address, uint8_t size) { static uint16_t pagestart; static uint8_t pagesize; if ((address & (SPM_PAGESIZE -1)) == 0x00) { pagestart = address; pagesize = SPM_PAGESIZE; boot_page_erase(pagestart); boot_spm_busy_wait(); } while (size && pagesize) { uint16_t dataword; dataword = (*data++); dataword |= (*data++) << 8; boot_page_fill(address, dataword); address += 2; pagesize -= 2; size -= 2; } if (pagesize == 0) { boot_page_write(pagestart); boot_spm_busy_wait(); boot_rww_enable(); } } /* write_flash */ static void read_eeprom(uint8_t *data, uint16_t address, uint8_t size) { while (size--) { EEARL = address; EEARH = (address >> 8); EECR |= (1<> 8); EEDR = *data++; address++; cli(); #if defined (__AVR_ATmega168__) EECR |= (1< 0) { led_timer[LED_RX]--; LED_GN_ON(); } else { LED_GN_OFF(); } if (led_timer[LED_TX] > 0) { led_timer[LED_TX]--; LED_RT_ON(); } else { LED_RT_OFF(); } /* do periodic work (wait for 5 ticks silence before start TX) */ rfm12_tick(5); /* get TX buffer */ struct rfm12_packet *rsp_pkt = rfm12_get_txpkt(); if (boot_timeout == BOOTWAIT_EXPIRED) { /* timeout elapsed and TX buffer available (tx completed) -> start application */ if (rsp_pkt != NULL) { break; } } else if (boot_timeout != BOOTWAIT_INTERRUPTED) { boot_timeout--; } if ((boot_timeout & 0x3F) == 0) { led_timer[LED_TX] = 5; } /* get RX data */ struct rfm12_packet *req_pkt = rfm12_get_rxpkt(); if (req_pkt == NULL) { /* no data available */ continue; } else { led_timer[LED_RX] = 5; /* no tx buffer available, ignore request */ if (rsp_pkt == NULL) { rfm12_clear_rx(); continue; } } /* stay in bootloader */ boot_timeout = BOOTWAIT_INTERRUPTED; struct bootloader_msg *req_msg = (struct bootloader_msg *)req_pkt->data; struct bootloader_msg *rsp_msg = (struct bootloader_msg *)rsp_pkt->data; /* retransmitted request -> retransmit response */ if ((req_pkt->source_address == rsp_pkt->dest_address) && ((req_msg->command & MSG_CMD_MASK) == (rsp_msg->command & MSG_CMD_MASK)) && (req_msg->seqnum == rsp_msg->seqnum) ) { /* RX packet no longer needed */ rfm12_clear_rx(); /* transmit response */ if (rfm12_start_tx()) { led_timer[LED_TX] = 5; } continue; } rsp_pkt->dest_address = req_pkt->source_address; rsp_pkt->data_length = 3; rsp_msg->command = req_msg->command | MSG_TYPE_RESPONSE; rsp_msg->seqnum = req_msg->seqnum; rsp_msg->cause = CAUSE_SUCCESS; switch (req_msg->command) { case MSG_CMD_SWITCHAPP_REQUEST: if (req_msg->p.switchapp.app == BOOTMODE_APPLICATION) { boot_timeout = BOOTWAIT_EXPIRED; } else if (req_msg->p.switchapp.app != BOOTMODE_BOOTLOADER) { rsp_msg->cause = CAUSE_INVALID_PARAMETER; } break; case MSG_CMD_VERSION_REQUEST: memcpy(rsp_msg->p.version.data, version_info, sizeof(rsp_msg->p.version.data)); rsp_pkt->data_length += sizeof(rsp_msg->p.version.data); break; case MSG_CMD_CHIPINFO_REQUEST: memcpy(rsp_msg->p.chipinfo.data, chip_info, sizeof(rsp_msg->p.chipinfo.data)); rsp_pkt->data_length += sizeof(rsp_msg->p.chipinfo.data); break; case MSG_CMD_READ_REQUEST: if (req_msg->p.read_req.mem_type == MEMTYPE_FLASH) { read_flash(rsp_msg->p.read_rsp.data, req_msg->p.read_req.address, req_msg->p.read_req.size); rsp_pkt->data_length += req_msg->p.read_req.size; } else if (req_msg->p.read_req.mem_type == MEMTYPE_EEPROM) { read_eeprom(rsp_msg->p.read_rsp.data, req_msg->p.read_req.address, req_msg->p.read_req.size); rsp_pkt->data_length += req_msg->p.read_req.size; } else { rsp_msg->cause = CAUSE_INVALID_PARAMETER; } break; case MSG_CMD_WRITE_REQUEST: if (req_msg->p.write_req.mem_type == MEMTYPE_FLASH) { write_flash(req_msg->p.write_req.data, req_msg->p.write_req.address, req_msg->p.write_req.size); } else if (req_msg->p.write_req.mem_type == MEMTYPE_EEPROM) { write_eeprom(req_msg->p.write_req.data, req_msg->p.write_req.address, req_msg->p.write_req.size); } else { rsp_msg->cause = CAUSE_INVALID_PARAMETER; } break; default: rsp_msg->cause = CAUSE_NOT_SUPPORTED; break; } /* RX packet no longer needed */ rfm12_clear_rx(); /* transmit response */ if (rfm12_start_tx()) { led_timer[LED_TX] = 5; } } cli(); #if defined (__AVR_ATmega168__) /* disable timer0 */ TIMSK0 = 0x00; TCCR0B = 0x00; /* move interrupt vectors back to application */ MCUCR = (1<