diff --git a/bin/ota-updater-rfcat.py b/bin/ota-updater-rfcat.py new file mode 100755 index 0000000..125bbe5 --- /dev/null +++ b/bin/ota-updater-rfcat.py @@ -0,0 +1,281 @@ +#!/usr/bin/env python3 + +import struct +from rflib import * +from time import sleep +from argparse import ArgumentParser +from binascii import hexlify, unhexlify +from hexdump import hexdump +from time import sleep + +import progressbar + +GREEN = '\u001b[32m' +BLUE = '\u001b[34m' +RED = '\u001b[31m' +YELLOW = '\u001b[33m' +RESET = '\u001b[0m' + +PROGRESSBAR_WIDGETS = [ + progressbar.SimpleProgress(), + f'{YELLOW} ', + progressbar.Bar(), + ' ', + progressbar.Percentage(), + f'{RESET} ', + progressbar.widgets.FileTransferSpeed(unit='pkt'), + ' ', + progressbar.Timer(), + progressbar.ETA(), +] + +PKT_TYPE_INIT = 0 +PKT_TYPE_DATA = 1 +PKT_TYPE_REBOOT = 2 +PKT_TYPE_LOG = 0xf0 +PKT_TYPE_RESET = 0xf1 +PKT_TYPE_BUSY = 0xfa +PKT_TYPE_DENIED = 0xfb +PKT_TYPE_UNK = 0xfc +PKT_TYPE_OOO = 0xfd +PKT_TYPE_ERR = 0xfe +PKT_TYPE_OK = 0xff + + +IHEX_TYPE_DATA = 0 +IHEX_TYPE_EOF = 1 +IHEX_TYPE_ENTRY_POINT = 3 + +class Updater: + def __init__(self, freq): + d = RfCat() + + d.setFreq(freq) + d.setEnablePktCRC(True) + d.setMdmModulation(MOD_GFSK) + d.setMdmSyncWord(0xd391) + d.setMdmDRate(250000) + # d.setMdmChanSpc(200) # seems not to work ?! + d.setMdmChanSpc(chanspc_m=0x11, chanspc_e=3) + d.setMdmChanBW(541666) + d.setMdmDeviatn(122953) + # d.setRFRegister(DEVIATN, (5 << 4) | 4) + d.setMdmSyncMode(SYNCM_30_of_32) + d.setMdmNumPreamble(MFMCFG1_NUM_PREAMBLE_24) + d.setMaxPower() + + d.makePktVLEN(255) + # print(d.reprRadioConfig()) + + self.dongle = d + + def listen(self): + self.dongle.RFlisten() + + def flash(self, fn): + + writes = [] + + with open(fn) as f: + + for line in f.readlines(): + line = line.strip() + + if line[0] != ':': + return + + count = int(line[1:3], 16) + addr = int(line[3:7], 16) + type = int(line[7:9], 16) + data = unhexlify(line[9:-2]) + crc = int(line[-2:], 16) + + crc_calc = (-sum(unhexlify(line[1:-2]))) & 0x0FF + + if crc != crc_calc: + print(f'crc error {crc:x} != {crc_calc:x}: line', file=sys.stderr) + + if type == IHEX_TYPE_DATA: + + if writes and addr == writes[-1][0] + len(writes[-1][1]) and len(writes[-1][1]) + len(data) <= 56: + writes[-1][1] += data + else: + writes += [[addr, data]] + + # writes = [writes[0]] + pkt = self.make_init_packet(len(writes)) + # return + + if not self.send_raw(pkt, check_ok=True): + print('Init failed') + return + + print(f'{GREEN}Initialized: {len(writes)} packets {RESET}') + + bar = progressbar.ProgressBar(max_value=len(writes), widgets=PROGRESSBAR_WIDGETS, redirect_stdout=True) + + for nr, (addr, data) in enumerate(writes): + bar.update(nr) + + pkt = self.make_data_packet(nr + 1, addr, data) + # print(f'{nr+1} {addr:x} {data}') + + ret = self.send_raw(pkt) + + if not ret: + print(f'{RED}Connection timeout / stale @ {nr + 1}/{len(writes)} ({addr:x}){RESET}') + return False + + if ret[0] == PKT_TYPE_OK: + # print('ok') + continue + + if ret[0] == PKT_TYPE_OOO: + print('Out of Order received: Trying to fix it') + + last_pkt = self.make_data_packet(nr, writes[nr-1][0], writes[nr-1][1]) + + if self.send_raw(last_pkt): + if self.send_raw(pkt): + print('Fixed') + continue + + print('{RED}Failed{RESET}') + + return False + + elif ret[0] == PKT_TYPE_ERR: + print('write failed, try again') + + if self.send_raw(pkt): + print('Fixed') + continue + + return False + + # bar.finish() + + print(f'{GREEN}Flashing complete{RESET}') + return True + + + def log(self): + pkt = self.make_packet(PKT_TYPE_LOG) + + data = self.send_raw(pkt) + + if not data: + return + + if data[0] == PKT_TYPE_UNK: + print(f'{RED}Log command not understood: not debug build?{RESET}') + return + + if data[0] != PKT_TYPE_OK: + print(f'{RED}Unexpected response: {data}') + return + + try: + print(data[1:].decode()) + except: + print(data[1:]) + + def reset(self): + pkt = self.make_packet(PKT_TYPE_RESET) + return self.send_raw(pkt, check_ok=True) + + def reboot(self): + pkt = self.make_packet(PKT_TYPE_REBOOT) + return self.send_raw(pkt, check_ok=True) + + def send_raw(self, pkt, check_ok=False, retry=10): + + data = None + + for i in range(retry): + + self.dongle.setModeIDLE() + self.dongle.RFxmit(pkt) + + self.dongle.setModeRX() + + try: + data, ts = self.dongle.RFrecv(1000) + except: + # print('Timeout') + continue + + break + + + if i > 0: + print(f'{YELLOW}resent={i} pkt={pkt} data={data}{RESET}') + # print(f'resent={i} pkt={pkt} data={data}') + + if data and check_ok: + if data[0] == PKT_TYPE_UNK: + print(f'{RED}Command not understood{RESET}') + elif data[0] not in [PKT_TYPE_OK, PKT_TYPE_ERR]: + print(f'unknown data: {data}') + return False + + return data[0] == PKT_TYPE_OK + + return data + + def make_init_packet(self, num_packets): + data = struct.pack('H', num_packets) + return self.make_packet(PKT_TYPE_INIT, data) + + def make_data_packet(self, num, addr, data): + data = struct.pack('H', num) + struct.pack('H', addr) + data + return self.make_packet(PKT_TYPE_DATA, data) + + def make_packet(self, type, data=b''): + + pkt = struct.pack('B', type) + pkt += data + + return pkt + + + +if __name__ == '__main__': + p = ArgumentParser() + + p.add_argument('-L', '--listen', action='store_true', default=False, help='listen for packets') + p.add_argument('flash', nargs='?', help='goodwatch.ihex') + p.add_argument('-l', '--log', action='store_true', default=False, help='fetches log of updater') + p.add_argument('-r', '--reset', action='store_true', default=False, help='resets updater on target') + p.add_argument('-R', '--reboot', action='store_true', default=False, help='reboots updater on target') + + p.add_argument('-f', '--freq', type=int, default=433920000, help='listen for packets') + + args = p.parse_args() + + upd = Updater(args.freq) + + if args.reset: + if upd.reset(): + print(f'{GREEN}Device reseted{RESET}') + else: + print(f'{RED}Device not reseted{RESET}') + sys.exit(1) + + if args.listen: + upd.listen() + sys.exit(0) + + if args.log: + upd.log() + + if args.flash: + upd.flash(args.flash) + + if args.reboot and not args.flash: + if upd.reboot(): + print(f'{GREEN}Device rebooted{RESET}') + else: + print(f'{RED}Device not rebooted{RESET}') + sys.exit(1) + diff --git a/firmware/Makefile b/firmware/Makefile index 13dcc1e..4d1f316 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -19,11 +19,12 @@ COUNTER_APP = 1 DMESG_APP = 1 PAGER_APP = 0 JUKEBOX_APP = 1 +OTAUPDATE_APP = 0 + #Don't forget to set your timezone for Beats in config.h. BEATS_APP = 0 - #set default flashing serial port, dont override if passed in as an argument PORT ?= /dev/ttyUSB0 #Mandatory applets. @@ -110,6 +111,10 @@ ifeq ($(JUKEBOX_APP),1) APPS_OBJ += apps/jukebox.o APPS_DEFINES += JUKEBOX_APP endif +ifeq ($(OTAUPDATE_APP),1) +APPS_OBJ += apps/ota_update.o +APPS_DEFINES += OTAUPDATE_APP +endif ifeq ($(BEATS_APP),1) APPS_OBJ += apps/beats.o APPS_DEFINES += BEATS_APP diff --git a/firmware/applist.c b/firmware/applist.c index aea3b3c..92d2857 100644 --- a/firmware/applist.c +++ b/firmware/applist.c @@ -184,6 +184,14 @@ const struct app subapps[]={ .keypress=calibrate_keypress }, #endif + + +#ifdef OTAUPDATE_APP + {.name="update", .init=ota_update_init, .draw=ota_update_draw, .exit=ota_update_exit, + .keypress=ota_update_keypress, + .packetrx=ota_update_packetrx, .packettx=ota_update_packettx, + }, +#endif #ifdef BEATS_APP { diff --git a/firmware/applist.h b/firmware/applist.h index e4b576a..246e66c 100644 --- a/firmware/applist.h +++ b/firmware/applist.h @@ -33,7 +33,7 @@ extern const struct app clock_applet; #include "apps/counter.h" #include "apps/pager.h" #include "apps/jukebox.h" - +#include "apps/ota_update.h" /* For each application, the init() function is called at entry. The draw() function is called four times per second. The exit() diff --git a/firmware/apps/ota_update.c b/firmware/apps/ota_update.c new file mode 100644 index 0000000..b88fd7f --- /dev/null +++ b/firmware/apps/ota_update.c @@ -0,0 +1,189 @@ +/*! \file beacon.c + \brief OTA Update Application + + Quick little comm demo that sends a callsign as a beacon. + +*/ + +#include +#include +#include +#include +#include "api.h" + + +#define LOADING_ADDRESS 0x2400 + +//! Radio config: GFSK, 250k baud, crc, crc auto flush, vlen +static const uint8_t ota_update_rf_settings[]={ + FIFOTHR, 0x47, //RX FIFO and TX FIFO Thresholds + PKTCTRL1, 0x0c, //No address check. + FREND0, 0x11, //FREND0 Front end TX configuration, use PA_TABLE[1] + TEST2, 0x81, //Various Test Settings + TEST1, 0x35, //Various Test Settings + ADDR, 0x00, //ADDR Device address. + MCSM1, 0x30, //MCSM1, return to IDLE after packet. Or with 2 for TX carrier test. + IOCFG2, 0x29, //IOCFG2 GDO2 output pin configuration. + IOCFG0, 0x06, //gdo0 output configuration + PKTCTRL0, 0x05, //packet automation control + FSCTRL1, 0x0c, //frequency synthesizer control + MDMCFG4, 0x2d, //modem configuration + MDMCFG3, 0x3b, //modem configuration + MDMCFG2, 0x13, //modem configuration + MDMCFG1, 0x72, //modem configuration + DEVIATN, 0x62, //modem deviation setting + MCSM0, 0x10, //main radio control state machine configuration + FOCCFG, 0x1d, //frequency offset compensation configuration + BSCFG, 0x1c, //bit synchronization configuration + AGCCTRL2, 0xc7, //agc control + AGCCTRL1, 0x00, //agc control + AGCCTRL0, 0xb0, //agc control + WORCTRL, 0xfb, //wake on radio control + FREND1, 0xb6, //front end rx configuration + FSCAL3, 0xea, //frequency synthesizer calibration + FSCAL2, 0x2a, //frequency synthesizer calibration + FSCAL1, 0x00, //frequency synthesizer calibration + FSCAL0, 0x1f, //frequency synthesizer calibration + TEST0, 0x09, //various test settings + 0,0, +}; + +//! Updater blob, generated from firmware/ota-updater/ +static const uint8_t updater_blob[] = { + 0x31, 0x40, 0xFF, 0x1D, 0x3C, 0x40, 0x8A, 0x28, 0x0D, 0x43, 0x3E, 0x40, 0x8C, 0x00, 0xB0, 0x12, + 0x70, 0x28, 0x3C, 0x40, 0x88, 0x28, 0x3D, 0x40, 0x88, 0x28, 0x0D, 0x9C, 0x04, 0x24, 0x3E, 0x40, + 0x02, 0x00, 0xB0, 0x12, 0x2A, 0x28, 0x0C, 0x43, 0xB0, 0x12, 0xDA, 0x27, 0x34, 0x40, 0x84, 0x28, + 0x35, 0x40, 0x84, 0x28, 0x26, 0x43, 0x0D, 0x3C, 0x34, 0x40, 0x84, 0x28, 0x35, 0x40, 0x84, 0x28, + 0x26, 0x43, 0x07, 0x3C, 0x34, 0x40, 0x84, 0x28, 0x35, 0x40, 0x84, 0x28, 0x36, 0x40, 0xFE, 0xFF, + 0x00, 0x3C, 0x05, 0x94, 0x04, 0x24, 0x27, 0x44, 0x04, 0x56, 0x87, 0x12, 0xFA, 0x3F, 0x30, 0x41, + 0x00, 0x13, 0x3C, 0xF0, 0xFF, 0x00, 0xB2, 0xF0, 0xBF, 0xFF, 0x02, 0x0F, 0xB2, 0xB0, 0x10, 0x00, + 0x02, 0x0F, 0xFC, 0x27, 0xF2, 0x40, 0x80, 0xFF, 0x13, 0x0F, 0xB2, 0xB0, 0x80, 0x00, 0x02, 0x0F, + 0xFC, 0x27, 0x5D, 0x42, 0x20, 0x0F, 0xB2, 0xB0, 0x10, 0x00, 0x02, 0x0F, 0xFC, 0x27, 0xC2, 0x43, + 0x11, 0x0F, 0xF2, 0x40, 0x29, 0x00, 0x10, 0x0F, 0xC2, 0x4C, 0x11, 0x0F, 0xA2, 0xB2, 0x30, 0x0F, + 0x10, 0x24, 0x7C, 0x50, 0xC8, 0xFF, 0x5E, 0x43, 0x4E, 0x9C, 0x0B, 0x2C, 0x3C, 0x40, 0xEA, 0x03, + 0xA2, 0xB2, 0x30, 0x0F, 0x15, 0x20, 0x0D, 0x14, 0x3D, 0x40, 0x18, 0x01, 0x1D, 0x83, 0xFE, 0x23, + 0x0D, 0x16, 0xB2, 0xB0, 0x10, 0x00, 0x02, 0x0F, 0xFC, 0x27, 0xC2, 0x43, 0x11, 0x0F, 0xC2, 0x4D, + 0x10, 0x0F, 0xB2, 0xB0, 0x40, 0x00, 0x02, 0x0F, 0xFC, 0x27, 0x5C, 0x42, 0x21, 0x0F, 0x30, 0x41, + 0x3C, 0x53, 0x0C, 0x93, 0xE5, 0x23, 0x7C, 0x40, 0xFF, 0x00, 0xF9, 0x3F, 0x0A, 0x15, 0xB2, 0xF0, + 0xFF, 0xFD, 0x36, 0x0F, 0xB2, 0xF0, 0xFF, 0xFD, 0x32, 0x0F, 0x3A, 0x40, 0x62, 0x24, 0x7C, 0x40, + 0x36, 0x00, 0x8A, 0x12, 0x7C, 0x40, 0x3A, 0x00, 0x8A, 0x12, 0x82, 0x43, 0x14, 0x29, 0x0A, 0x17, + 0x30, 0x41, 0x92, 0x43, 0x14, 0x29, 0xB2, 0xD0, 0x00, 0x02, 0x34, 0x0F, 0xB2, 0xF0, 0xFF, 0xFD, + 0x32, 0x0F, 0xB2, 0xD0, 0x00, 0x02, 0x36, 0x0F, 0x7C, 0x40, 0x34, 0x00, 0xB0, 0x12, 0x62, 0x24, + 0x30, 0x41, 0xBF, 0x15, 0x1C, 0x42, 0x38, 0x0F, 0x1C, 0xC3, 0x3C, 0x90, 0x14, 0x00, 0x7D, 0x20, + 0x82, 0x93, 0x14, 0x29, 0x37, 0x25, 0x7E, 0x40, 0xF5, 0xFF, 0xC2, 0x4E, 0x13, 0x0F, 0xB2, 0xB0, + 0x80, 0x00, 0x02, 0x0F, 0xFC, 0x27, 0x5C, 0x42, 0x20, 0x0F, 0x0D, 0x4C, 0x3D, 0x50, 0xF3, 0xFF, + 0x6F, 0x43, 0x0F, 0x9D, 0xF2, 0x2F, 0x7D, 0x50, 0xF9, 0xFF, 0x5F, 0x43, 0x4F, 0x9D, 0xED, 0x2F, + 0x1C, 0x93, 0x14, 0x21, 0xF2, 0x40, 0xFB, 0xFF, 0x13, 0x0F, 0xB2, 0xB0, 0x80, 0x00, 0x02, 0x0F, + 0xFC, 0x27, 0x5C, 0x42, 0x20, 0x0F, 0xC2, 0x4C, 0x12, 0x29, 0x0C, 0x93, 0x15, 0x24, 0xB2, 0xB0, + 0x10, 0x00, 0x02, 0x0F, 0xFC, 0x27, 0x7D, 0x40, 0x40, 0x00, 0x4D, 0x9C, 0x01, 0x2C, 0x4C, 0x4D, + 0x3C, 0xF0, 0xFF, 0x00, 0xF2, 0x43, 0x13, 0x0F, 0x4D, 0x43, 0x0E, 0x4C, 0x3E, 0x53, 0x0D, 0x9E, + 0x46, 0x28, 0xDC, 0x42, 0x20, 0x0F, 0xCF, 0x28, 0xB0, 0x12, 0xEC, 0x24, 0x0D, 0x14, 0x3D, 0x40, + 0x0E, 0x0B, 0x1D, 0x83, 0xFE, 0x23, 0x0D, 0x16, 0x3E, 0x40, 0xD0, 0x28, 0x5D, 0x4E, 0x01, 0x00, + 0x5D, 0x93, 0x61, 0x24, 0x4D, 0x93, 0x3C, 0x24, 0x6D, 0x93, 0xD4, 0x24, 0x7D, 0x90, 0xF1, 0xFF, + 0xCE, 0x24, 0x7C, 0x40, 0xFC, 0x00, 0xC2, 0x93, 0x88, 0x28, 0x27, 0x24, 0xD2, 0x43, 0x8A, 0x28, + 0xC2, 0x4C, 0x8B, 0x28, 0xC2, 0x43, 0x88, 0x28, 0x82, 0x93, 0xCE, 0x28, 0x1E, 0x20, 0x92, 0x43, + 0xCE, 0x28, 0xB2, 0xD0, 0x00, 0x02, 0x34, 0x0F, 0xB2, 0xF0, 0xFF, 0xFD, 0x32, 0x0F, 0xB2, 0xD0, + 0x00, 0x02, 0x36, 0x0F, 0xB2, 0xB0, 0x10, 0x00, 0x02, 0x0F, 0xFC, 0x27, 0xB2, 0x40, 0x01, 0x7F, + 0x10, 0x0F, 0xC2, 0x4C, 0x10, 0x0F, 0xB2, 0xB0, 0x20, 0x00, 0x02, 0x0F, 0xFC, 0x27, 0x5C, 0x42, + 0x20, 0x0F, 0x7C, 0x40, 0x35, 0x00, 0xB0, 0x12, 0x62, 0x24, 0xB4, 0x17, 0x00, 0x13, 0xB2, 0xB0, + 0x80, 0x00, 0x02, 0x0F, 0xFC, 0x27, 0xDD, 0x42, 0x22, 0x0F, 0xD0, 0x28, 0x1D, 0x53, 0xAF, 0x3F, + 0xC2, 0x93, 0xCC, 0x28, 0x9A, 0x20, 0x92, 0x4E, 0x02, 0x00, 0xCA, 0x28, 0x82, 0x43, 0xC8, 0x28, + 0x92, 0xB3, 0x44, 0x01, 0xFD, 0x23, 0xB2, 0x40, 0x00, 0xA5, 0x44, 0x01, 0x1C, 0x42, 0x44, 0x01, + 0x5C, 0xF3, 0x0C, 0x93, 0xFB, 0x23, 0xB2, 0x40, 0x06, 0xA5, 0x40, 0x01, 0xC2, 0x4C, 0xE0, 0xFF, + 0x92, 0xB3, 0x44, 0x01, 0xFD, 0x23, 0xB2, 0x40, 0x10, 0xA5, 0x44, 0x01, 0xD2, 0x43, 0xCC, 0x28, + 0x7C, 0x40, 0xFF, 0x00, 0xA8, 0x3F, 0xD2, 0x93, 0xCC, 0x28, 0x7A, 0x20, 0x1C, 0x4E, 0x02, 0x00, + 0x1D, 0x42, 0xC8, 0x28, 0x1D, 0x53, 0x0C, 0x9D, 0x76, 0x20, 0x82, 0x9C, 0xCA, 0x28, 0x73, 0x28, + 0xB2, 0x40, 0x00, 0xA5, 0x44, 0x01, 0xB2, 0x40, 0x40, 0xA5, 0x40, 0x01, 0x1B, 0x4E, 0x04, 0x00, + 0x0B, 0x93, 0x58, 0x34, 0x0C, 0x4B, 0x0D, 0x43, 0x6E, 0x4E, 0x7E, 0x50, 0xFB, 0xFF, 0x4E, 0x4E, + 0x0F, 0x43, 0x08, 0x4E, 0x08, 0x5C, 0x09, 0x4F, 0x09, 0x6D, 0x5E, 0x43, 0x0E, 0x99, 0x4A, 0x28, + 0x19, 0x93, 0x02, 0x20, 0x08, 0x93, 0x46, 0x20, 0x3E, 0x40, 0xD6, 0x28, 0x06, 0x49, 0x0A, 0x4B, + 0x5A, 0xF3, 0x0F, 0x48, 0x3F, 0x53, 0x0B, 0x49, 0x3B, 0x63, 0x07, 0x4D, 0x0D, 0x99, 0x19, 0x28, + 0x06, 0x9D, 0x03, 0x20, 0x07, 0x4C, 0x0C, 0x98, 0x14, 0x28, 0x5C, 0x43, 0xB2, 0x40, 0x00, 0xA5, + 0x40, 0x01, 0xB2, 0x40, 0x10, 0xA5, 0x44, 0x01, 0x0C, 0x93, 0x2E, 0x24, 0x92, 0x53, 0xC8, 0x28, + 0x7C, 0x40, 0xFF, 0x00, 0x92, 0x92, 0xCA, 0x28, 0xD2, 0x28, 0x5D, 0x23, 0xE2, 0x43, 0xCC, 0x28, + 0xAF, 0x3F, 0x07, 0x4C, 0x0A, 0x93, 0x04, 0x20, 0x0F, 0x9C, 0x0F, 0x20, 0x0B, 0x9D, 0x0D, 0x20, + 0x65, 0x4E, 0x92, 0xB3, 0x44, 0x01, 0xFD, 0x23, 0xC7, 0x45, 0x00, 0x00, 0x92, 0xB3, 0x44, 0x01, + 0xFD, 0x23, 0x1E, 0x53, 0x1C, 0x53, 0x0D, 0x63, 0xD0, 0x3F, 0x25, 0x4E, 0x92, 0xB3, 0x44, 0x01, + 0xFD, 0x23, 0x87, 0x45, 0x00, 0x00, 0x92, 0xB3, 0x44, 0x01, 0xFD, 0x23, 0x2E, 0x53, 0x1C, 0x53, + 0x0D, 0x63, 0xF0, 0x3F, 0x4C, 0x43, 0xCA, 0x3F, 0x7C, 0x40, 0xFE, 0x00, 0xD3, 0x3F, 0xC2, 0x43, + 0xCC, 0x28, 0x86, 0x3F, 0xC2, 0x4D, 0xCC, 0x28, 0x83, 0x3F, 0x7C, 0x40, 0xFA, 0x00, 0x2B, 0x3F, + 0x7C, 0x40, 0xFB, 0x00, 0x28, 0x3F, 0x7C, 0x40, 0xFD, 0x00, 0x25, 0x3F, 0x3C, 0x90, 0x11, 0x00, + 0x4C, 0x23, 0x3A, 0x40, 0x62, 0x24, 0x7C, 0x40, 0x3A, 0x00, 0x8A, 0x12, 0x7C, 0x40, 0x34, 0x00, + 0x8A, 0x12, 0x43, 0x3F, 0x82, 0x93, 0xCE, 0x28, 0x40, 0x27, 0xB2, 0xF0, 0xFF, 0xFD, 0x36, 0x0F, + 0x82, 0x43, 0xCE, 0x28, 0xE2, 0x93, 0xCC, 0x28, 0x03, 0x20, 0xB2, 0x40, 0x04, 0xA5, 0x20, 0x01, + 0xD2, 0x43, 0x88, 0x28, 0xB0, 0x12, 0x12, 0x25, 0x30, 0x3F, 0xB2, 0x40, 0x80, 0x5A, 0x5C, 0x01, + 0xC2, 0x43, 0x1B, 0x02, 0xF2, 0xF0, 0x8F, 0xFF, 0xA0, 0x04, 0xB0, 0x12, 0xEC, 0x24, 0x0D, 0x42, + 0x32, 0xC2, 0x03, 0x43, 0x3C, 0x40, 0x80, 0x2B, 0xBC, 0x40, 0x60, 0x24, 0x00, 0x00, 0x2C, 0x53, + 0x3C, 0x90, 0x00, 0x2C, 0xF9, 0x23, 0xB2, 0x40, 0x32, 0x25, 0xEA, 0x2B, 0x92, 0xD3, 0x80, 0x01, + 0x0C, 0x4D, 0x7C, 0xF0, 0xFF, 0x00, 0x03, 0x43, 0x02, 0x4C, 0x03, 0x43, 0xB0, 0x12, 0x12, 0x25, + 0x03, 0x43, 0x32, 0xD0, 0xD8, 0x00, 0x03, 0x43, 0xFF, 0x3F, 0x1A, 0x15, 0x0D, 0x9C, 0x1E, 0x2C, + 0x0A, 0x4D, 0x0A, 0x5E, 0x0C, 0x9A, 0x1A, 0x2C, 0x09, 0x4E, 0x39, 0xE3, 0x4D, 0x43, 0x3D, 0x53, + 0x09, 0x9D, 0x02, 0x20, 0x19, 0x17, 0x30, 0x41, 0x0F, 0x4D, 0x0F, 0x5E, 0x0F, 0x5C, 0x0B, 0x4A, + 0x0B, 0x5D, 0xEF, 0x4B, 0x00, 0x00, 0xF3, 0x3F, 0x0B, 0x4D, 0x0B, 0x5F, 0x0A, 0x4C, 0x0A, 0x5F, + 0xEA, 0x4B, 0x00, 0x00, 0x1F, 0x53, 0x0E, 0x9F, 0xF7, 0x23, 0xEC, 0x3F, 0x4F, 0x43, 0xFB, 0x3F, + 0x4F, 0x43, 0x0E, 0x9F, 0x01, 0x20, 0x30, 0x41, 0x0B, 0x4C, 0x0B, 0x5F, 0xCB, 0x4D, 0x00, 0x00, + 0x1F, 0x53, 0xF7, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, +}; + + +//! Enter the OTA Update application. +void ota_update_init(){ + if(!has_radio){ + app_next(); + return; + } + lcd_string("PRESS S"); +} + +//! Exit the OTA Update application. +int ota_update_exit(){ + return 0; +} + +//! Dummy functions for RX/TX +void ota_update_packetrx(uint8_t *packet, int len){ +} + +void ota_update_packettx(){ +} + +//! Start radio +static void radio_start(){ + radio_on(); + radio_writesettings(ota_update_rf_settings); + radio_writepower(0x25); + codeplug_setfreq(); + packet_rxon(); +} + +//! Copy updater to ram and execute it +static void launch_updater(){ + typedef void (*fn_t)(); + + fn_t fn = (fn_t) LOADING_ADDRESS; + + memcpy((uint8_t*)fn, updater_blob, sizeof(updater_blob)); + + fn(); +} + +//! Use this to launch updater after display has been updated +static bool button_pressed = false; + +//! Draw the OTA Update screen. +void ota_update_draw(char forced){ + if (button_pressed){ + radio_start(); + launch_updater(); + } + + if (sidebutton_set()){ + lcd_string("--------"); + button_pressed = true; + } +} + +//! Keypress handler for the beacon applet. +int ota_update_keypress(char ch){ + return 0; +} diff --git a/firmware/apps/ota_update.h b/firmware/apps/ota_update.h new file mode 100644 index 0000000..368d759 --- /dev/null +++ b/firmware/apps/ota_update.h @@ -0,0 +1,23 @@ +/*! \file ota_update.h + \brief OTA Update Application + +*/ + +//! Enter the OTA Update application. +void ota_update_init(); + +//! Exit the OTA Update application. +int ota_update_exit(); + +//! Draw the OTA Update screen. +void ota_update_draw(); + +//! Handle an incoming packet. +void ota_update_packetrx(uint8_t *packet, int len); + +//! Callback after transmission. +void ota_update_packettx(); + +//! Keypress handler for the OTA Update applet. +int ota_update_keypress(char ch); + diff --git a/firmware/ota-updater/Makefile b/firmware/ota-updater/Makefile new file mode 100644 index 0000000..14e5dbb --- /dev/null +++ b/firmware/ota-updater/Makefile @@ -0,0 +1,24 @@ + +#GCC8 from Texas Instruments, not the GCC4 that ships with Debian. +CC = msp430-elf-gcc -minrt -msmall -mmcu=cc430f6137 -Wall -I. -I/opt/msp430-gcc-support-files/include/ -Os -Wl,--gc-sections,--print-gc-sections -fdata-sections -ffunction-sections -fno-asynchronous-unwind-tables -flto -fshort-enums + +modules=main.o radio.o packet.o debug.o flash.o + +all: ccode + +dbg: CC += -DDEBUG +dbg: ccode + +blob.elf: $(modules) + $(CC) -T cc430f6137.ld -o blob.elf $(modules) $(apps) + ../../bin/printsizes.py blob.elf || echo "Please install python-pyelftools." + +blob.hex: blob.elf + msp430-elf-objcopy -O ihex blob.elf blob.hex + +ccode: blob.hex + ./convert.py blob.hex -i -c + + +clean: + rm -rf *~ */*~ *.hex *.elf *.o */*.o blob.hex blob.elf diff --git a/firmware/ota-updater/cc430f6137.ld b/firmware/ota-updater/cc430f6137.ld new file mode 100644 index 0000000..e80631b --- /dev/null +++ b/firmware/ota-updater/cc430f6137.ld @@ -0,0 +1,407 @@ +/* ============================================================================ */ +/* Copyright (c) 2019, Texas Instruments Incorporated */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions */ +/* are met: */ +/* */ +/* * Redistributions of source code must retain the above copyright */ +/* notice, this list of conditions and the following disclaimer. */ +/* */ +/* * Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* * Neither the name of Texas Instruments Incorporated nor the names of */ +/* its contributors may be used to endorse or promote products derived */ +/* from this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" */ +/* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, */ +/* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */ +/* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR */ +/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, */ +/* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, */ +/* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; */ +/* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */ +/* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR */ +/* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */ +/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* ============================================================================ */ + +/* This file supports CC430F6137 devices. */ +/* Version: 1.207 */ +/* Default linker script, for normal executables */ + +OUTPUT_ARCH(msp430) +ENTRY(_start) + +MEMORY { + SFR : ORIGIN = 0x0000, LENGTH = 0x0010 /* END=0x0010, size 16 */ + BSL : ORIGIN = 0x1000, LENGTH = 0x0800 +/* RAM : ORIGIN = 0x1C00, LENGTH = 0x0FFE /* END=0x2BFD, size 4094 */ + /*RAM : ORIGIN = 0x1C00, LENGTH = 0x0800 /* Just half of RAM. */ + RAM : ORIGIN = 0x2400, LENGTH = 0x0700 /* Second half just for dmesg. */ + HEAP : ORIGIN = 0x1C00, LENGTH = 0xff + STACK : ORIGIN = 0x1D00, LENGTH = 0xff + /*LOG : ORIGIN = 0x1e00, LENGTH = 0xfe */ + INFOMEM : ORIGIN = 0x1800, LENGTH = 0x0200 /* END=0x19FF, size 512 as 4 128-byte segments */ + INFOA : ORIGIN = 0x1980, LENGTH = 0x0080 /* END=0x19FF, size 128 */ + INFOB : ORIGIN = 0x1900, LENGTH = 0x0080 /* END=0x197F, size 128 */ + INFOC : ORIGIN = 0x1880, LENGTH = 0x0080 /* END=0x18FF, size 128 */ + INFOD : ORIGIN = 0x1800, LENGTH = 0x0080 /* END=0x187F, size 128 */ + /*ROM (rx) : ORIGIN = 0x8000, LENGTH = 0x7F80 /* END=0xFF7F, size 32640 */ + VECT1 : ORIGIN = 0xFF80, LENGTH = 0x0002 + VECT2 : ORIGIN = 0xFF82, LENGTH = 0x0002 + VECT3 : ORIGIN = 0xFF84, LENGTH = 0x0002 + VECT4 : ORIGIN = 0xFF86, LENGTH = 0x0002 + VECT5 : ORIGIN = 0xFF88, LENGTH = 0x0002 + VECT6 : ORIGIN = 0xFF8A, LENGTH = 0x0002 + VECT7 : ORIGIN = 0xFF8C, LENGTH = 0x0002 + VECT8 : ORIGIN = 0xFF8E, LENGTH = 0x0002 + VECT9 : ORIGIN = 0xFF90, LENGTH = 0x0002 + VECT10 : ORIGIN = 0xFF92, LENGTH = 0x0002 + VECT11 : ORIGIN = 0xFF94, LENGTH = 0x0002 + VECT12 : ORIGIN = 0xFF96, LENGTH = 0x0002 + VECT13 : ORIGIN = 0xFF98, LENGTH = 0x0002 + VECT14 : ORIGIN = 0xFF9A, LENGTH = 0x0002 + VECT15 : ORIGIN = 0xFF9C, LENGTH = 0x0002 + VECT16 : ORIGIN = 0xFF9E, LENGTH = 0x0002 + VECT17 : ORIGIN = 0xFFA0, LENGTH = 0x0002 + VECT18 : ORIGIN = 0xFFA2, LENGTH = 0x0002 + VECT19 : ORIGIN = 0xFFA4, LENGTH = 0x0002 + VECT20 : ORIGIN = 0xFFA6, LENGTH = 0x0002 + VECT21 : ORIGIN = 0xFFA8, LENGTH = 0x0002 + VECT22 : ORIGIN = 0xFFAA, LENGTH = 0x0002 + VECT23 : ORIGIN = 0xFFAC, LENGTH = 0x0002 + VECT24 : ORIGIN = 0xFFAE, LENGTH = 0x0002 + VECT25 : ORIGIN = 0xFFB0, LENGTH = 0x0002 + VECT26 : ORIGIN = 0xFFB2, LENGTH = 0x0002 + VECT27 : ORIGIN = 0xFFB4, LENGTH = 0x0002 + VECT28 : ORIGIN = 0xFFB6, LENGTH = 0x0002 + VECT29 : ORIGIN = 0xFFB8, LENGTH = 0x0002 + VECT30 : ORIGIN = 0xFFBA, LENGTH = 0x0002 + VECT31 : ORIGIN = 0xFFBC, LENGTH = 0x0002 + VECT32 : ORIGIN = 0xFFBE, LENGTH = 0x0002 + VECT33 : ORIGIN = 0xFFC0, LENGTH = 0x0002 + VECT34 : ORIGIN = 0xFFC2, LENGTH = 0x0002 + VECT35 : ORIGIN = 0xFFC4, LENGTH = 0x0002 + VECT36 : ORIGIN = 0xFFC6, LENGTH = 0x0002 + VECT37 : ORIGIN = 0xFFC8, LENGTH = 0x0002 + VECT38 : ORIGIN = 0xFFCA, LENGTH = 0x0002 + VECT39 : ORIGIN = 0xFFCC, LENGTH = 0x0002 + VECT40 : ORIGIN = 0xFFCE, LENGTH = 0x0002 + VECT41 : ORIGIN = 0xFFD0, LENGTH = 0x0002 + VECT42 : ORIGIN = 0xFFD2, LENGTH = 0x0002 + VECT43 : ORIGIN = 0xFFD4, LENGTH = 0x0002 + VECT44 : ORIGIN = 0xFFD6, LENGTH = 0x0002 + VECT45 : ORIGIN = 0xFFD8, LENGTH = 0x0002 + VECT46 : ORIGIN = 0xFFDA, LENGTH = 0x0002 + VECT47 : ORIGIN = 0xFFDC, LENGTH = 0x0002 + VECT48 : ORIGIN = 0xFFDE, LENGTH = 0x0002 + VECT49 : ORIGIN = 0xFFE0, LENGTH = 0x0002 + VECT50 : ORIGIN = 0xFFE2, LENGTH = 0x0002 + VECT51 : ORIGIN = 0xFFE4, LENGTH = 0x0002 + VECT52 : ORIGIN = 0xFFE6, LENGTH = 0x0002 + VECT53 : ORIGIN = 0xFFE8, LENGTH = 0x0002 + VECT54 : ORIGIN = 0xFFEA, LENGTH = 0x0002 + VECT55 : ORIGIN = 0xFFEC, LENGTH = 0x0002 + VECT56 : ORIGIN = 0xFFEE, LENGTH = 0x0002 + VECT57 : ORIGIN = 0xFFF0, LENGTH = 0x0002 + VECT58 : ORIGIN = 0xFFF2, LENGTH = 0x0002 + VECT59 : ORIGIN = 0xFFF4, LENGTH = 0x0002 + VECT60 : ORIGIN = 0xFFF6, LENGTH = 0x0002 + VECT61 : ORIGIN = 0xFFF8, LENGTH = 0x0002 + VECT62 : ORIGIN = 0xFFFA, LENGTH = 0x0002 + VECT63 : ORIGIN = 0xFFFC, LENGTH = 0x0002 + RESETVEC : ORIGIN = 0xFFFE, LENGTH = 0x0002 +} + +SECTIONS +{ + __interrupt_vector_1 : { KEEP (*(__interrupt_vector_1 )) } > VECT1 + __interrupt_vector_2 : { KEEP (*(__interrupt_vector_2 )) } > VECT2 + __interrupt_vector_3 : { KEEP (*(__interrupt_vector_3 )) } > VECT3 + __interrupt_vector_4 : { KEEP (*(__interrupt_vector_4 )) } > VECT4 + __interrupt_vector_5 : { KEEP (*(__interrupt_vector_5 )) } > VECT5 + __interrupt_vector_6 : { KEEP (*(__interrupt_vector_6 )) } > VECT6 + __interrupt_vector_7 : { KEEP (*(__interrupt_vector_7 )) } > VECT7 + __interrupt_vector_8 : { KEEP (*(__interrupt_vector_8 )) } > VECT8 + __interrupt_vector_9 : { KEEP (*(__interrupt_vector_9 )) } > VECT9 + __interrupt_vector_10 : { KEEP (*(__interrupt_vector_10)) } > VECT10 + __interrupt_vector_11 : { KEEP (*(__interrupt_vector_11)) } > VECT11 + __interrupt_vector_12 : { KEEP (*(__interrupt_vector_12)) } > VECT12 + __interrupt_vector_13 : { KEEP (*(__interrupt_vector_13)) } > VECT13 + __interrupt_vector_14 : { KEEP (*(__interrupt_vector_14)) } > VECT14 + __interrupt_vector_15 : { KEEP (*(__interrupt_vector_15)) } > VECT15 + __interrupt_vector_16 : { KEEP (*(__interrupt_vector_16)) } > VECT16 + __interrupt_vector_17 : { KEEP (*(__interrupt_vector_17)) } > VECT17 + __interrupt_vector_18 : { KEEP (*(__interrupt_vector_18)) } > VECT18 + __interrupt_vector_19 : { KEEP (*(__interrupt_vector_19)) } > VECT19 + __interrupt_vector_20 : { KEEP (*(__interrupt_vector_20)) } > VECT20 + __interrupt_vector_21 : { KEEP (*(__interrupt_vector_21)) } > VECT21 + __interrupt_vector_22 : { KEEP (*(__interrupt_vector_22)) } > VECT22 + __interrupt_vector_23 : { KEEP (*(__interrupt_vector_23)) } > VECT23 + __interrupt_vector_24 : { KEEP (*(__interrupt_vector_24)) } > VECT24 + __interrupt_vector_25 : { KEEP (*(__interrupt_vector_25)) } > VECT25 + __interrupt_vector_26 : { KEEP (*(__interrupt_vector_26)) } > VECT26 + __interrupt_vector_27 : { KEEP (*(__interrupt_vector_27)) } > VECT27 + __interrupt_vector_28 : { KEEP (*(__interrupt_vector_28)) } > VECT28 + __interrupt_vector_29 : { KEEP (*(__interrupt_vector_29)) } > VECT29 + __interrupt_vector_30 : { KEEP (*(__interrupt_vector_30)) } > VECT30 + __interrupt_vector_31 : { KEEP (*(__interrupt_vector_31)) } > VECT31 + __interrupt_vector_32 : { KEEP (*(__interrupt_vector_32)) } > VECT32 + __interrupt_vector_33 : { KEEP (*(__interrupt_vector_33)) } > VECT33 + __interrupt_vector_34 : { KEEP (*(__interrupt_vector_34)) } > VECT34 + __interrupt_vector_35 : { KEEP (*(__interrupt_vector_35)) } > VECT35 + __interrupt_vector_36 : { KEEP (*(__interrupt_vector_36)) } > VECT36 + __interrupt_vector_37 : { KEEP (*(__interrupt_vector_37)) } > VECT37 + __interrupt_vector_38 : { KEEP (*(__interrupt_vector_38)) } > VECT38 + __interrupt_vector_39 : { KEEP (*(__interrupt_vector_39)) } > VECT39 + __interrupt_vector_40 : { KEEP (*(__interrupt_vector_40)) } > VECT40 + __interrupt_vector_41 : { KEEP (*(__interrupt_vector_41)) } > VECT41 + __interrupt_vector_42 : { KEEP (*(__interrupt_vector_42)) } > VECT42 + __interrupt_vector_43 : { KEEP (*(__interrupt_vector_43)) } > VECT43 + __interrupt_vector_44 : { KEEP (*(__interrupt_vector_44)) } > VECT44 + __interrupt_vector_45 : { KEEP (*(__interrupt_vector_45)) } > VECT45 + __interrupt_vector_46 : { KEEP (*(__interrupt_vector_46)) KEEP (*(__interrupt_vector_aes)) } > VECT46 + __interrupt_vector_47 : { KEEP (*(__interrupt_vector_47)) KEEP (*(__interrupt_vector_rtc)) } > VECT47 + __interrupt_vector_48 : { KEEP (*(__interrupt_vector_48)) KEEP (*(__interrupt_vector_lcd_b)) } > VECT48 + __interrupt_vector_49 : { KEEP (*(__interrupt_vector_49)) KEEP (*(__interrupt_vector_port2)) } > VECT49 + __interrupt_vector_50 : { KEEP (*(__interrupt_vector_50)) KEEP (*(__interrupt_vector_port1)) } > VECT50 + __interrupt_vector_51 : { KEEP (*(__interrupt_vector_51)) KEEP (*(__interrupt_vector_timer1_a1)) } > VECT51 + __interrupt_vector_52 : { KEEP (*(__interrupt_vector_52)) KEEP (*(__interrupt_vector_timer1_a0)) } > VECT52 + __interrupt_vector_53 : { KEEP (*(__interrupt_vector_53)) KEEP (*(__interrupt_vector_dma)) } > VECT53 + __interrupt_vector_54 : { KEEP (*(__interrupt_vector_54)) KEEP (*(__interrupt_vector_cc1101)) } > VECT54 + __interrupt_vector_55 : { KEEP (*(__interrupt_vector_55)) KEEP (*(__interrupt_vector_timer0_a1)) } > VECT55 + __interrupt_vector_56 : { KEEP (*(__interrupt_vector_56)) KEEP (*(__interrupt_vector_timer0_a0)) } > VECT56 + __interrupt_vector_57 : { KEEP (*(__interrupt_vector_57)) KEEP (*(__interrupt_vector_adc12)) } > VECT57 + __interrupt_vector_58 : { KEEP (*(__interrupt_vector_58)) KEEP (*(__interrupt_vector_usci_b0)) } > VECT58 + __interrupt_vector_59 : { KEEP (*(__interrupt_vector_59)) KEEP (*(__interrupt_vector_usci_a0)) } > VECT59 + __interrupt_vector_60 : { KEEP (*(__interrupt_vector_60)) KEEP (*(__interrupt_vector_wdt)) } > VECT60 + __interrupt_vector_61 : { KEEP (*(__interrupt_vector_61)) KEEP (*(__interrupt_vector_comp_b)) } > VECT61 + __interrupt_vector_62 : { KEEP (*(__interrupt_vector_62)) KEEP (*(__interrupt_vector_unmi)) } > VECT62 + __interrupt_vector_63 : { KEEP (*(__interrupt_vector_63)) KEEP (*(__interrupt_vector_sysnmi)) } > VECT63 + __reset_vector : + { + KEEP (*(__interrupt_vector_64)) + KEEP (*(__interrupt_vector_reset)) + KEEP (*(.resetvec)) + } > RESETVEC + + .text : + { + . = ALIGN(2); + PROVIDE (_start = .); + KEEP (*(SORT(.crt_*))) + *(.lowtext .text .stub .text.* .gnu.linkonce.t.* .text:*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.interp .hash .dynsym .dynstr .gnu.version*) + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(2); + KEEP (*(.init)) + KEEP (*(.fini)) + KEEP (*(.tm_clone_table)) + } > RAM + + .rodata : + { + . = ALIGN(2); + *(.plt) + *(.rodata .rodata.* .gnu.linkonce.r.* .const .const:*) + *(.rodata1) + KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) + PROVIDE (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE (__fini_array_end = .); + } > RAM + + /* Note: This is a separate .rodata section for sections which are + read only but which older linkers treat as read-write. + This prevents older linkers from marking the entire .rodata + section as read-write. */ + .rodata2 : + { + . = ALIGN(2); + *(.eh_frame_hdr) + KEEP (*(.eh_frame)) + + /* gcc uses crtbegin.o to find the start of the constructors, so + we make sure it is first. Because this is a wildcard, it + doesn't matter if the user does not actually link against + crtbegin.o; the linker won't look for a file to match a + wildcard. The wildcard also means that it doesn't matter which + directory crtbegin.o is in. */ + KEEP (*crtbegin*.o(.ctors)) + + /* We don't want to include the .ctor section from from the + crtend.o file until after the sorted ctors. The .ctor section + from the crtend file contains the end of ctors marker and it + must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } > RAM + + + .data : + { + . = ALIGN(2); + PROVIDE (__datastart = .); + + KEEP (*(.jcr)) + *(.data.rel.ro.local) *(.data.rel.ro*) + *(.dynamic) + + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + *(.data1) + *(.got.plt) *(.got) + + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + . = ALIGN(2); + *(.sdata .sdata.* .gnu.linkonce.s.* D_2 D_1) + + . = ALIGN(2); + _edata = .; + PROVIDE (edata = .); + PROVIDE (__dataend = .); + } > RAM AT>RAM + + /* Note that crt0 assumes this is a multiple of two; all the + start/stop symbols are also assumed word-aligned. */ + PROVIDE(__romdatastart = LOADADDR(.data)); + PROVIDE (__romdatacopysize = SIZEOF(.data)); + + .bss : + { + . = ALIGN(2); + PROVIDE (__bssstart = .); + *(.dynbss) + *(.sbss .sbss.*) + *(.bss .bss.* .gnu.linkonce.b.*) + . = ALIGN(2); + *(COMMON) + PROVIDE (__bssend = .); + } > RAM + PROVIDE (__bsssize = SIZEOF(.bss)); + + /* This section contains data that is not initialised during load + or application reset. */ + .noinit (NOLOAD) : + { + . = ALIGN(2); + PROVIDE (__noinit_start = .); + *(.noinit) + . = ALIGN(2); + PROVIDE (__noinit_end = .); + end = .; + } > RAM + + /* We create this section so that "end" will always be in the + RAM region (matching .stack below), even if the .bss + section is empty. */ + .heap (NOLOAD) : + { + . = ALIGN(2); + __heap_start__ = .; + _end = __heap_start__; + PROVIDE (end = .); + KEEP (*(.heap)) + _end = .; + PROVIDE (end = .); + /* This word is here so that the section is not empty, and thus + not discarded by the linker. The actual value does not matter + and is ignored. */ + LONG(0); + __heap_end__ = .; + __HeapLimit = __heap_end__; + } > HEAP + /* WARNING: Do not place anything in RAM here. + The heap section must be the last section in RAM and the stack + section must be placed at the very end of the RAM region. */ + + .stack (ORIGIN (STACK) + LENGTH(STACK)) : + { + PROVIDE (__stack = .); + *(.stack) + } + + .infoA : {} > INFOA /* MSP430 INFO FLASH MEMORY SEGMENTS */ + .infoB : {} > INFOB + .infoC : {} > INFOC + .infoD : {} > INFOD + + .MSP430.attributes 0 : + { + KEEP (*(.MSP430.attributes)) + KEEP (*(.gnu.attributes)) + KEEP (*(__TI_build_attributes)) + } + + /* The rest are all not normally part of the runtime image. */ + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.note.GNU-stack) } +} + + +/****************************************************************************/ +/* Include peripherals memory map */ +/****************************************************************************/ + +INCLUDE cc430f6137_symbols.ld + diff --git a/firmware/ota-updater/cc430f6137_symbols.ld b/firmware/ota-updater/cc430f6137_symbols.ld new file mode 100644 index 0000000..5aca217 --- /dev/null +++ b/firmware/ota-updater/cc430f6137_symbols.ld @@ -0,0 +1,825 @@ +/* ============================================================================ */ +/* Copyright (c) 2019, Texas Instruments Incorporated */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions */ +/* are met: */ +/* */ +/* * Redistributions of source code must retain the above copyright */ +/* notice, this list of conditions and the following disclaimer. */ +/* */ +/* * Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* * Neither the name of Texas Instruments Incorporated nor the names of */ +/* its contributors may be used to endorse or promote products derived */ +/* from this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" */ +/* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, */ +/* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */ +/* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR */ +/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, */ +/* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, */ +/* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; */ +/* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */ +/* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR */ +/* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */ +/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* ============================================================================ */ + +/* This file supports CC430F6137 devices. */ +/* Version: 1.207 */ + +/************************************************************ +* STANDARD BITS +************************************************************/ +/************************************************************ +* STATUS REGISTER BITS +************************************************************/ +/************************************************************ +* PERIPHERAL FILE MAP +************************************************************/ +/************************************************************ +* ADC12 PLUS +************************************************************/ +PROVIDE(ADC12CTL0 = 0x0700); +PROVIDE(ADC12CTL0_L = 0x0700); +PROVIDE(ADC12CTL0_H = 0x0701); +PROVIDE(ADC12CTL1 = 0x0702); +PROVIDE(ADC12CTL1_L = 0x0702); +PROVIDE(ADC12CTL1_H = 0x0703); +PROVIDE(ADC12CTL2 = 0x0704); +PROVIDE(ADC12CTL2_L = 0x0704); +PROVIDE(ADC12CTL2_H = 0x0705); +PROVIDE(ADC12IFG = 0x070A); +PROVIDE(ADC12IFG_L = 0x070A); +PROVIDE(ADC12IFG_H = 0x070B); +PROVIDE(ADC12IE = 0x070C); +PROVIDE(ADC12IE_L = 0x070C); +PROVIDE(ADC12IE_H = 0x070D); +PROVIDE(ADC12IV = 0x070E); +PROVIDE(ADC12IV_L = 0x070E); +PROVIDE(ADC12IV_H = 0x070F); +PROVIDE(ADC12MEM0 = 0x0720); +PROVIDE(ADC12MEM0_L = 0x0720); +PROVIDE(ADC12MEM0_H = 0x0721); +PROVIDE(ADC12MEM1 = 0x0722); +PROVIDE(ADC12MEM1_L = 0x0722); +PROVIDE(ADC12MEM1_H = 0x0723); +PROVIDE(ADC12MEM2 = 0x0724); +PROVIDE(ADC12MEM2_L = 0x0724); +PROVIDE(ADC12MEM2_H = 0x0725); +PROVIDE(ADC12MEM3 = 0x0726); +PROVIDE(ADC12MEM3_L = 0x0726); +PROVIDE(ADC12MEM3_H = 0x0727); +PROVIDE(ADC12MEM4 = 0x0728); +PROVIDE(ADC12MEM4_L = 0x0728); +PROVIDE(ADC12MEM4_H = 0x0729); +PROVIDE(ADC12MEM5 = 0x072A); +PROVIDE(ADC12MEM5_L = 0x072A); +PROVIDE(ADC12MEM5_H = 0x072B); +PROVIDE(ADC12MEM6 = 0x072C); +PROVIDE(ADC12MEM6_L = 0x072C); +PROVIDE(ADC12MEM6_H = 0x072D); +PROVIDE(ADC12MEM7 = 0x072E); +PROVIDE(ADC12MEM7_L = 0x072E); +PROVIDE(ADC12MEM7_H = 0x072F); +PROVIDE(ADC12MEM8 = 0x0730); +PROVIDE(ADC12MEM8_L = 0x0730); +PROVIDE(ADC12MEM8_H = 0x0731); +PROVIDE(ADC12MEM9 = 0x0732); +PROVIDE(ADC12MEM9_L = 0x0732); +PROVIDE(ADC12MEM9_H = 0x0733); +PROVIDE(ADC12MEM10 = 0x0734); +PROVIDE(ADC12MEM10_L = 0x0734); +PROVIDE(ADC12MEM10_H = 0x0735); +PROVIDE(ADC12MEM11 = 0x0736); +PROVIDE(ADC12MEM11_L = 0x0736); +PROVIDE(ADC12MEM11_H = 0x0737); +PROVIDE(ADC12MEM12 = 0x0738); +PROVIDE(ADC12MEM12_L = 0x0738); +PROVIDE(ADC12MEM12_H = 0x0739); +PROVIDE(ADC12MEM13 = 0x073A); +PROVIDE(ADC12MEM13_L = 0x073A); +PROVIDE(ADC12MEM13_H = 0x073B); +PROVIDE(ADC12MEM14 = 0x073C); +PROVIDE(ADC12MEM14_L = 0x073C); +PROVIDE(ADC12MEM14_H = 0x073D); +PROVIDE(ADC12MEM15 = 0x073E); +PROVIDE(ADC12MEM15_L = 0x073E); +PROVIDE(ADC12MEM15_H = 0x073F); +PROVIDE(ADC12MCTL0 = 0x0710); +PROVIDE(ADC12MCTL1 = 0x0711); +PROVIDE(ADC12MCTL2 = 0x0712); +PROVIDE(ADC12MCTL3 = 0x0713); +PROVIDE(ADC12MCTL4 = 0x0714); +PROVIDE(ADC12MCTL5 = 0x0715); +PROVIDE(ADC12MCTL6 = 0x0716); +PROVIDE(ADC12MCTL7 = 0x0717); +PROVIDE(ADC12MCTL8 = 0x0718); +PROVIDE(ADC12MCTL9 = 0x0719); +PROVIDE(ADC12MCTL10 = 0x071A); +PROVIDE(ADC12MCTL11 = 0x071B); +PROVIDE(ADC12MCTL12 = 0x071C); +PROVIDE(ADC12MCTL13 = 0x071D); +PROVIDE(ADC12MCTL14 = 0x071E); +PROVIDE(ADC12MCTL15 = 0x071F); +/************************************************************ +* AES Accelerator +************************************************************/ +PROVIDE(AESACTL0 = 0x09C0); +PROVIDE(AESACTL0_L = 0x09C0); +PROVIDE(AESACTL0_H = 0x09C1); +PROVIDE(AESASTAT = 0x09C4); +PROVIDE(AESASTAT_L = 0x09C4); +PROVIDE(AESASTAT_H = 0x09C5); +PROVIDE(AESAKEY = 0x09C6); +PROVIDE(AESAKEY_L = 0x09C6); +PROVIDE(AESAKEY_H = 0x09C7); +PROVIDE(AESADIN = 0x09C8); +PROVIDE(AESADIN_L = 0x09C8); +PROVIDE(AESADIN_H = 0x09C9); +PROVIDE(AESADOUT = 0x09CA); +PROVIDE(AESADOUT_L = 0x09CA); +PROVIDE(AESADOUT_H = 0x09CB); +/************************************************************ +* Comparator B +************************************************************/ +PROVIDE(CBCTL0 = 0x08C0); +PROVIDE(CBCTL0_L = 0x08C0); +PROVIDE(CBCTL0_H = 0x08C1); +PROVIDE(CBCTL1 = 0x08C2); +PROVIDE(CBCTL1_L = 0x08C2); +PROVIDE(CBCTL1_H = 0x08C3); +PROVIDE(CBCTL2 = 0x08C4); +PROVIDE(CBCTL2_L = 0x08C4); +PROVIDE(CBCTL2_H = 0x08C5); +PROVIDE(CBCTL3 = 0x08C6); +PROVIDE(CBCTL3_L = 0x08C6); +PROVIDE(CBCTL3_H = 0x08C7); +PROVIDE(CBINT = 0x08CC); +PROVIDE(CBINT_L = 0x08CC); +PROVIDE(CBINT_H = 0x08CD); +PROVIDE(CBIV = 0x08CE); +/************************************************************ +* CC1101 Radio Interface +************************************************************/ +PROVIDE(RF1AIFCTL0 = 0x0F00); +PROVIDE(RF1AIFCTL0_L = 0x0F00); +PROVIDE(RF1AIFCTL0_H = 0x0F01); +PROVIDE(RF1AIFCTL1 = 0x0F02); +PROVIDE(RF1AIFCTL1_L = 0x0F02); +PROVIDE(RF1AIFCTL1_H = 0x0F03); +PROVIDE(RF1AIFCTL2 = 0x0F04); +PROVIDE(RF1AIFCTL2_L = 0x0F04); +PROVIDE(RF1AIFCTL2_H = 0x0F05); +PROVIDE(RF1AIFERR = 0x0F06); +PROVIDE(RF1AIFERR_L = 0x0F06); +PROVIDE(RF1AIFERR_H = 0x0F07); +PROVIDE(RF1AIFERRV = 0x0F0C); +PROVIDE(RF1AIFERRV_L = 0x0F0C); +PROVIDE(RF1AIFERRV_H = 0x0F0D); +PROVIDE(RF1AIFIV = 0x0F0E); +PROVIDE(RF1AIFIV_L = 0x0F0E); +PROVIDE(RF1AIFIV_H = 0x0F0F); +PROVIDE(RF1AINSTRW = 0x0F10); +PROVIDE(RF1AINSTRW_L = 0x0F10); +PROVIDE(RF1AINSTRW_H = 0x0F11); +PROVIDE(RF1AINSTR1W = 0x0F12); +PROVIDE(RF1AINSTR1W_L = 0x0F12); +PROVIDE(RF1AINSTR1W_H = 0x0F13); +PROVIDE(RF1AINSTR2W = 0x0F14); +PROVIDE(RF1AINSTR2W_L = 0x0F14); +PROVIDE(RF1AINSTR2W_H = 0x0F15); +PROVIDE(RF1ADINW = 0x0F16); +PROVIDE(RF1ADINW_L = 0x0F16); +PROVIDE(RF1ADINW_H = 0x0F17); +PROVIDE(RF1ASTAT0W = 0x0F20); +PROVIDE(RF1ASTAT0W_L = 0x0F20); +PROVIDE(RF1ASTAT0W_H = 0x0F21); +PROVIDE(RF1ASTAT1W = 0x0F22); +PROVIDE(RF1ASTAT1W_L = 0x0F22); +PROVIDE(RF1ASTAT1W_H = 0x0F23); +PROVIDE(RF1ASTAT2W = 0x0F24); +PROVIDE(RF1ASTAT2W_L = 0x0F24); +PROVIDE(RF1ASTAT2W_H = 0x0F25); +PROVIDE(RF1ADOUT0W = 0x0F28); +PROVIDE(RF1ADOUT0W_L = 0x0F28); +PROVIDE(RF1ADOUT0W_H = 0x0F29); +PROVIDE(RF1ADOUT1W = 0x0F2A); +PROVIDE(RF1ADOUT1W_L = 0x0F2A); +PROVIDE(RF1ADOUT1W_H = 0x0F2B); +PROVIDE(RF1ADOUT2W = 0x0F2C); +PROVIDE(RF1ADOUT2W_L = 0x0F2C); +PROVIDE(RF1ADOUT2W_H = 0x0F2D); +PROVIDE(RF1AIN = 0x0F30); +PROVIDE(RF1AIN_L = 0x0F30); +PROVIDE(RF1AIN_H = 0x0F31); +PROVIDE(RF1AIFG = 0x0F32); +PROVIDE(RF1AIFG_L = 0x0F32); +PROVIDE(RF1AIFG_H = 0x0F33); +PROVIDE(RF1AIES = 0x0F34); +PROVIDE(RF1AIES_L = 0x0F34); +PROVIDE(RF1AIES_H = 0x0F35); +PROVIDE(RF1AIE = 0x0F36); +PROVIDE(RF1AIE_L = 0x0F36); +PROVIDE(RF1AIE_H = 0x0F37); +PROVIDE(RF1AIV = 0x0F38); +PROVIDE(RF1AIV_L = 0x0F38); +PROVIDE(RF1AIV_H = 0x0F39); +PROVIDE(RF1ARXFIFO = 0x0F3C); +PROVIDE(RF1ARXFIFO_L = 0x0F3C); +PROVIDE(RF1ARXFIFO_H = 0x0F3D); +PROVIDE(RF1ATXFIFO = 0x0F3E); +PROVIDE(RF1ATXFIFO_L = 0x0F3E); +PROVIDE(RF1ATXFIFO_H = 0x0F3F); +/************************************************************* +* CRC Module +*************************************************************/ +PROVIDE(CRCDI = 0x0150); +PROVIDE(CRCDI_L = 0x0150); +PROVIDE(CRCDI_H = 0x0151); +PROVIDE(CRCINIRES = 0x0154); +PROVIDE(CRCINIRES_L = 0x0154); +PROVIDE(CRCINIRES_H = 0x0155); +/************************************************************ +* DMA_X +************************************************************/ +PROVIDE(DMACTL0 = 0x0500); +PROVIDE(DMACTL1 = 0x0502); +PROVIDE(DMACTL2 = 0x0504); +PROVIDE(DMACTL3 = 0x0506); +PROVIDE(DMACTL4 = 0x0508); +PROVIDE(DMAIV = 0x050E); +PROVIDE(DMA0CTL = 0x0510); +PROVIDE(DMA0SA = 0x0512); +PROVIDE(DMA0SAL = 0x0512); +PROVIDE(DMA0DA = 0x0516); +PROVIDE(DMA0DAL = 0x0516); +PROVIDE(DMA0SZ = 0x051A); +PROVIDE(DMA1CTL = 0x0520); +PROVIDE(DMA1SA = 0x0522); +PROVIDE(DMA1SAL = 0x0522); +PROVIDE(DMA1DA = 0x0526); +PROVIDE(DMA1DAL = 0x0526); +PROVIDE(DMA1SZ = 0x052A); +PROVIDE(DMA2CTL = 0x0530); +PROVIDE(DMA2SA = 0x0532); +PROVIDE(DMA2SAL = 0x0532); +PROVIDE(DMA2DA = 0x0536); +PROVIDE(DMA2DAL = 0x0536); +PROVIDE(DMA2SZ = 0x053A); +/************************************************************* +* Flash Memory +*************************************************************/ +PROVIDE(FCTL1 = 0x0140); +PROVIDE(FCTL1_L = 0x0140); +PROVIDE(FCTL1_H = 0x0141); +PROVIDE(FCTL3 = 0x0144); +PROVIDE(FCTL3_L = 0x0144); +PROVIDE(FCTL3_H = 0x0145); +PROVIDE(FCTL4 = 0x0146); +PROVIDE(FCTL4_L = 0x0146); +PROVIDE(FCTL4_H = 0x0147); +/************************************************************ +* LCD_B +************************************************************/ +PROVIDE(LCDBCTL0 = 0x0A00); +PROVIDE(LCDBCTL0_L = 0x0A00); +PROVIDE(LCDBCTL0_H = 0x0A01); +PROVIDE(LCDBCTL1 = 0x0A02); +PROVIDE(LCDBCTL1_L = 0x0A02); +PROVIDE(LCDBCTL1_H = 0x0A03); +PROVIDE(LCDBBLKCTL = 0x0A04); +PROVIDE(LCDBBLKCTL_L = 0x0A04); +PROVIDE(LCDBBLKCTL_H = 0x0A05); +PROVIDE(LCDBMEMCTL = 0x0A06); +PROVIDE(LCDBMEMCTL_L = 0x0A06); +PROVIDE(LCDBMEMCTL_H = 0x0A07); +PROVIDE(LCDBVCTL = 0x0A08); +PROVIDE(LCDBVCTL_L = 0x0A08); +PROVIDE(LCDBVCTL_H = 0x0A09); +PROVIDE(LCDBPCTL0 = 0x0A0A); +PROVIDE(LCDBPCTL0_L = 0x0A0A); +PROVIDE(LCDBPCTL0_H = 0x0A0B); +PROVIDE(LCDBPCTL1 = 0x0A0C); +PROVIDE(LCDBPCTL1_L = 0x0A0C); +PROVIDE(LCDBPCTL1_H = 0x0A0D); +PROVIDE(LCDBPCTL2 = 0x0A0E); +PROVIDE(LCDBPCTL2_L = 0x0A0E); +PROVIDE(LCDBPCTL2_H = 0x0A0F); +PROVIDE(LCDBPCTL3 = 0x0A10); +PROVIDE(LCDBPCTL3_L = 0x0A10); +PROVIDE(LCDBPCTL3_H = 0x0A11); +PROVIDE(LCDBCPCTL = 0x0A12); +PROVIDE(LCDBCPCTL_L = 0x0A12); +PROVIDE(LCDBCPCTL_H = 0x0A13); +PROVIDE(LCDBIV = 0x0A1E); +PROVIDE(LCDM1 = 0x0A20); +PROVIDE(LCDM2 = 0x0A21); +PROVIDE(LCDM3 = 0x0A22); +PROVIDE(LCDM4 = 0x0A23); +PROVIDE(LCDM5 = 0x0A24); +PROVIDE(LCDM6 = 0x0A25); +PROVIDE(LCDM7 = 0x0A26); +PROVIDE(LCDM8 = 0x0A27); +PROVIDE(LCDM9 = 0x0A28); +PROVIDE(LCDM10 = 0x0A29); +PROVIDE(LCDM11 = 0x0A2A); +PROVIDE(LCDM12 = 0x0A2B); +PROVIDE(LCDM13 = 0x0A2C); +PROVIDE(LCDM14 = 0x0A2D); +PROVIDE(LCDM15 = 0x0A2E); +PROVIDE(LCDM16 = 0x0A2F); +PROVIDE(LCDM17 = 0x0A30); +PROVIDE(LCDM18 = 0x0A31); +PROVIDE(LCDM19 = 0x0A32); +PROVIDE(LCDM20 = 0x0A33); +PROVIDE(LCDM21 = 0x0A34); +PROVIDE(LCDM22 = 0x0A35); +PROVIDE(LCDM23 = 0x0A36); +PROVIDE(LCDM24 = 0x0A37); +PROVIDE(LCDBM1 = 0x0A40); +PROVIDE(LCDBM2 = 0x0A41); +PROVIDE(LCDBM3 = 0x0A42); +PROVIDE(LCDBM4 = 0x0A43); +PROVIDE(LCDBM5 = 0x0A44); +PROVIDE(LCDBM6 = 0x0A45); +PROVIDE(LCDBM7 = 0x0A46); +PROVIDE(LCDBM8 = 0x0A47); +PROVIDE(LCDBM9 = 0x0A48); +PROVIDE(LCDBM10 = 0x0A49); +PROVIDE(LCDBM11 = 0x0A4A); +PROVIDE(LCDBM12 = 0x0A4B); +PROVIDE(LCDBM13 = 0x0A4C); +PROVIDE(LCDBM14 = 0x0A4D); +PROVIDE(LCDBM15 = 0x0A4E); +PROVIDE(LCDBM16 = 0x0A4F); +PROVIDE(LCDBM17 = 0x0A50); +PROVIDE(LCDBM18 = 0x0A51); +PROVIDE(LCDBM19 = 0x0A52); +PROVIDE(LCDBM20 = 0x0A53); +PROVIDE(LCDBM21 = 0x0A54); +PROVIDE(LCDBM22 = 0x0A55); +PROVIDE(LCDBM23 = 0x0A56); +PROVIDE(LCDBM24 = 0x0A57); +/************************************************************ +* HARDWARE MULTIPLIER 32Bit +************************************************************/ +PROVIDE(MPY = 0x04C0); +PROVIDE(MPY_L = 0x04C0); +PROVIDE(MPY_H = 0x04C1); +PROVIDE(MPYS = 0x04C2); +PROVIDE(MPYS_L = 0x04C2); +PROVIDE(MPYS_H = 0x04C3); +PROVIDE(MAC = 0x04C4); +PROVIDE(MAC_L = 0x04C4); +PROVIDE(MAC_H = 0x04C5); +PROVIDE(MACS = 0x04C6); +PROVIDE(MACS_L = 0x04C6); +PROVIDE(MACS_H = 0x04C7); +PROVIDE(OP2 = 0x04C8); +PROVIDE(OP2_L = 0x04C8); +PROVIDE(OP2_H = 0x04C9); +PROVIDE(RESLO = 0x04CA); +PROVIDE(RESLO_L = 0x04CA); +PROVIDE(RESLO_H = 0x04CB); +PROVIDE(RESHI = 0x04CC); +PROVIDE(RESHI_L = 0x04CC); +PROVIDE(RESHI_H = 0x04CD); +PROVIDE(SUMEXT = 0x04CE); +PROVIDE(SUMEXT_L = 0x04CE); +PROVIDE(SUMEXT_H = 0x04CF); +PROVIDE(MPY32L = 0x04D0); +PROVIDE(MPY32L_L = 0x04D0); +PROVIDE(MPY32L_H = 0x04D1); +PROVIDE(MPY32H = 0x04D2); +PROVIDE(MPY32H_L = 0x04D2); +PROVIDE(MPY32H_H = 0x04D3); +PROVIDE(MPYS32L = 0x04D4); +PROVIDE(MPYS32L_L = 0x04D4); +PROVIDE(MPYS32L_H = 0x04D5); +PROVIDE(MPYS32H = 0x04D6); +PROVIDE(MPYS32H_L = 0x04D6); +PROVIDE(MPYS32H_H = 0x04D7); +PROVIDE(MAC32L = 0x04D8); +PROVIDE(MAC32L_L = 0x04D8); +PROVIDE(MAC32L_H = 0x04D9); +PROVIDE(MAC32H = 0x04DA); +PROVIDE(MAC32H_L = 0x04DA); +PROVIDE(MAC32H_H = 0x04DB); +PROVIDE(MACS32L = 0x04DC); +PROVIDE(MACS32L_L = 0x04DC); +PROVIDE(MACS32L_H = 0x04DD); +PROVIDE(MACS32H = 0x04DE); +PROVIDE(MACS32H_L = 0x04DE); +PROVIDE(MACS32H_H = 0x04DF); +PROVIDE(OP2L = 0x04E0); +PROVIDE(OP2L_L = 0x04E0); +PROVIDE(OP2L_H = 0x04E1); +PROVIDE(OP2H = 0x04E2); +PROVIDE(OP2H_L = 0x04E2); +PROVIDE(OP2H_H = 0x04E3); +PROVIDE(RES0 = 0x04E4); +PROVIDE(RES0_L = 0x04E4); +PROVIDE(RES0_H = 0x04E5); +PROVIDE(RES1 = 0x04E6); +PROVIDE(RES1_L = 0x04E6); +PROVIDE(RES1_H = 0x04E7); +PROVIDE(RES2 = 0x04E8); +PROVIDE(RES2_L = 0x04E8); +PROVIDE(RES2_H = 0x04E9); +PROVIDE(RES3 = 0x04EA); +PROVIDE(RES3_L = 0x04EA); +PROVIDE(RES3_H = 0x04EB); +PROVIDE(MPY32CTL0 = 0x04EC); +PROVIDE(MPY32CTL0_L = 0x04EC); +PROVIDE(MPY32CTL0_H = 0x04ED); +/************************************************************ +* DIGITAL I/O Port1/2 Pull up / Pull down Resistors +************************************************************/ +PROVIDE(PAIN = 0x0200); +PROVIDE(PAIN_L = 0x0200); +PROVIDE(PAIN_H = 0x0201); +PROVIDE(PAOUT = 0x0202); +PROVIDE(PAOUT_L = 0x0202); +PROVIDE(PAOUT_H = 0x0203); +PROVIDE(PADIR = 0x0204); +PROVIDE(PADIR_L = 0x0204); +PROVIDE(PADIR_H = 0x0205); +PROVIDE(PAREN = 0x0206); +PROVIDE(PAREN_L = 0x0206); +PROVIDE(PAREN_H = 0x0207); +PROVIDE(PADS = 0x0208); +PROVIDE(PADS_L = 0x0208); +PROVIDE(PADS_H = 0x0209); +PROVIDE(PASEL = 0x020A); +PROVIDE(PASEL_L = 0x020A); +PROVIDE(PASEL_H = 0x020B); +PROVIDE(PAIES = 0x0218); +PROVIDE(PAIES_L = 0x0218); +PROVIDE(PAIES_H = 0x0219); +PROVIDE(PAIE = 0x021A); +PROVIDE(PAIE_L = 0x021A); +PROVIDE(PAIE_H = 0x021B); +PROVIDE(PAIFG = 0x021C); +PROVIDE(PAIFG_L = 0x021C); +PROVIDE(PAIFG_H = 0x021D); +PROVIDE(P1IV = 0x020E); +PROVIDE(P2IV = 0x021E); +/************************************************************ +* DIGITAL I/O Port3/4 Pull up / Pull down Resistors +************************************************************/ +PROVIDE(PBIN = 0x0220); +PROVIDE(PBIN_L = 0x0220); +PROVIDE(PBIN_H = 0x0221); +PROVIDE(PBOUT = 0x0222); +PROVIDE(PBOUT_L = 0x0222); +PROVIDE(PBOUT_H = 0x0223); +PROVIDE(PBDIR = 0x0224); +PROVIDE(PBDIR_L = 0x0224); +PROVIDE(PBDIR_H = 0x0225); +PROVIDE(PBREN = 0x0226); +PROVIDE(PBREN_L = 0x0226); +PROVIDE(PBREN_H = 0x0227); +PROVIDE(PBDS = 0x0228); +PROVIDE(PBDS_L = 0x0228); +PROVIDE(PBDS_H = 0x0229); +PROVIDE(PBSEL = 0x022A); +PROVIDE(PBSEL_L = 0x022A); +PROVIDE(PBSEL_H = 0x022B); +/************************************************************ +* DIGITAL I/O Port5 Pull up / Pull down Resistors +************************************************************/ +PROVIDE(PCIN = 0x0240); +PROVIDE(PCIN_L = 0x0240); +PROVIDE(PCIN_H = 0x0241); +PROVIDE(PCOUT = 0x0242); +PROVIDE(PCOUT_L = 0x0242); +PROVIDE(PCOUT_H = 0x0243); +PROVIDE(PCDIR = 0x0244); +PROVIDE(PCDIR_L = 0x0244); +PROVIDE(PCDIR_H = 0x0245); +PROVIDE(PCREN = 0x0246); +PROVIDE(PCREN_L = 0x0246); +PROVIDE(PCREN_H = 0x0247); +PROVIDE(PCDS = 0x0248); +PROVIDE(PCDS_L = 0x0248); +PROVIDE(PCDS_H = 0x0249); +PROVIDE(PCSEL = 0x024A); +PROVIDE(PCSEL_L = 0x024A); +PROVIDE(PCSEL_H = 0x024B); +/************************************************************ +* DIGITAL I/O PortJ Pull up / Pull down Resistors +************************************************************/ +PROVIDE(PJIN = 0x0320); +PROVIDE(PJIN_L = 0x0320); +PROVIDE(PJIN_H = 0x0321); +PROVIDE(PJOUT = 0x0322); +PROVIDE(PJOUT_L = 0x0322); +PROVIDE(PJOUT_H = 0x0323); +PROVIDE(PJDIR = 0x0324); +PROVIDE(PJDIR_L = 0x0324); +PROVIDE(PJDIR_H = 0x0325); +PROVIDE(PJREN = 0x0326); +PROVIDE(PJREN_L = 0x0326); +PROVIDE(PJREN_H = 0x0327); +PROVIDE(PJDS = 0x0328); +PROVIDE(PJDS_L = 0x0328); +PROVIDE(PJDS_H = 0x0329); +/************************************************************ +* PORT MAPPING CONTROLLER +************************************************************/ +PROVIDE(PMAPKEYID = 0x01C0); +PROVIDE(PMAPKEYID_L = 0x01C0); +PROVIDE(PMAPKEYID_H = 0x01C1); +PROVIDE(PMAPCTL = 0x01C2); +PROVIDE(PMAPCTL_L = 0x01C2); +PROVIDE(PMAPCTL_H = 0x01C3); +/************************************************************ +* PORT 1 MAPPING CONTROLLER +************************************************************/ +PROVIDE(P1MAP01 = 0x01C8); +PROVIDE(P1MAP01_L = 0x01C8); +PROVIDE(P1MAP01_H = 0x01C9); +PROVIDE(P1MAP23 = 0x01CA); +PROVIDE(P1MAP23_L = 0x01CA); +PROVIDE(P1MAP23_H = 0x01CB); +PROVIDE(P1MAP45 = 0x01CC); +PROVIDE(P1MAP45_L = 0x01CC); +PROVIDE(P1MAP45_H = 0x01CD); +PROVIDE(P1MAP67 = 0x01CE); +PROVIDE(P1MAP67_L = 0x01CE); +PROVIDE(P1MAP67_H = 0x01CF); +/************************************************************ +* PORT 2 MAPPING CONTROLLER +************************************************************/ +PROVIDE(P2MAP01 = 0x01D0); +PROVIDE(P2MAP01_L = 0x01D0); +PROVIDE(P2MAP01_H = 0x01D1); +PROVIDE(P2MAP23 = 0x01D2); +PROVIDE(P2MAP23_L = 0x01D2); +PROVIDE(P2MAP23_H = 0x01D3); +PROVIDE(P2MAP45 = 0x01D4); +PROVIDE(P2MAP45_L = 0x01D4); +PROVIDE(P2MAP45_H = 0x01D5); +PROVIDE(P2MAP67 = 0x01D6); +PROVIDE(P2MAP67_L = 0x01D6); +PROVIDE(P2MAP67_H = 0x01D7); +/************************************************************ +* PORT 3 MAPPING CONTROLLER +************************************************************/ +PROVIDE(P3MAP01 = 0x01D8); +PROVIDE(P3MAP01_L = 0x01D8); +PROVIDE(P3MAP01_H = 0x01D9); +PROVIDE(P3MAP23 = 0x01DA); +PROVIDE(P3MAP23_L = 0x01DA); +PROVIDE(P3MAP23_H = 0x01DB); +PROVIDE(P3MAP45 = 0x01DC); +PROVIDE(P3MAP45_L = 0x01DC); +PROVIDE(P3MAP45_H = 0x01DD); +PROVIDE(P3MAP67 = 0x01DE); +PROVIDE(P3MAP67_L = 0x01DE); +PROVIDE(P3MAP67_H = 0x01DF); +/************************************************************ +* PMM - Power Management System +************************************************************/ +PROVIDE(PMMCTL0 = 0x0120); +PROVIDE(PMMCTL0_L = 0x0120); +PROVIDE(PMMCTL0_H = 0x0121); +PROVIDE(PMMCTL1 = 0x0122); +PROVIDE(PMMCTL1_L = 0x0122); +PROVIDE(PMMCTL1_H = 0x0123); +PROVIDE(SVSMHCTL = 0x0124); +PROVIDE(SVSMHCTL_L = 0x0124); +PROVIDE(SVSMHCTL_H = 0x0125); +PROVIDE(SVSMLCTL = 0x0126); +PROVIDE(SVSMLCTL_L = 0x0126); +PROVIDE(SVSMLCTL_H = 0x0127); +PROVIDE(SVSMIO = 0x0128); +PROVIDE(SVSMIO_L = 0x0128); +PROVIDE(SVSMIO_H = 0x0129); +PROVIDE(PMMIFG = 0x012C); +PROVIDE(PMMIFG_L = 0x012C); +PROVIDE(PMMIFG_H = 0x012D); +PROVIDE(PMMRIE = 0x012E); +PROVIDE(PMMRIE_L = 0x012E); +PROVIDE(PMMRIE_H = 0x012F); +/************************************************************* +* RAM Control Module +*************************************************************/ +PROVIDE(RCCTL0 = 0x0158); +PROVIDE(RCCTL0_L = 0x0158); +PROVIDE(RCCTL0_H = 0x0159); +/************************************************************ +* Shared Reference +************************************************************/ +PROVIDE(REFCTL0 = 0x01B0); +PROVIDE(REFCTL0_L = 0x01B0); +PROVIDE(REFCTL0_H = 0x01B1); +/************************************************************ +* Real Time Clock +************************************************************/ +PROVIDE(RTCCTL01 = 0x04A0); +PROVIDE(RTCCTL01_L = 0x04A0); +PROVIDE(RTCCTL01_H = 0x04A1); +PROVIDE(RTCCTL23 = 0x04A2); +PROVIDE(RTCCTL23_L = 0x04A2); +PROVIDE(RTCCTL23_H = 0x04A3); +PROVIDE(RTCPS0CTL = 0x04A8); +PROVIDE(RTCPS0CTL_L = 0x04A8); +PROVIDE(RTCPS0CTL_H = 0x04A9); +PROVIDE(RTCPS1CTL = 0x04AA); +PROVIDE(RTCPS1CTL_L = 0x04AA); +PROVIDE(RTCPS1CTL_H = 0x04AB); +PROVIDE(RTCPS = 0x04AC); +PROVIDE(RTCPS_L = 0x04AC); +PROVIDE(RTCPS_H = 0x04AD); +PROVIDE(RTCIV = 0x04AE); +PROVIDE(RTCTIM0 = 0x04B0); +PROVIDE(RTCTIM0_L = 0x04B0); +PROVIDE(RTCTIM0_H = 0x04B1); +PROVIDE(RTCTIM1 = 0x04B2); +PROVIDE(RTCTIM1_L = 0x04B2); +PROVIDE(RTCTIM1_H = 0x04B3); +PROVIDE(RTCDATE = 0x04B4); +PROVIDE(RTCDATE_L = 0x04B4); +PROVIDE(RTCDATE_H = 0x04B5); +PROVIDE(RTCYEAR = 0x04B6); +PROVIDE(RTCYEAR_L = 0x04B6); +PROVIDE(RTCYEAR_H = 0x04B7); +PROVIDE(RTCAMINHR = 0x04B8); +PROVIDE(RTCAMINHR_L = 0x04B8); +PROVIDE(RTCAMINHR_H = 0x04B9); +PROVIDE(RTCADOWDAY = 0x04BA); +PROVIDE(RTCADOWDAY_L = 0x04BA); +PROVIDE(RTCADOWDAY_H = 0x04BB); +/************************************************************ +* SFR - Special Function Register Module +************************************************************/ +PROVIDE(SFRIE1 = 0x0100); +PROVIDE(SFRIE1_L = 0x0100); +PROVIDE(SFRIE1_H = 0x0101); +PROVIDE(SFRIFG1 = 0x0102); +PROVIDE(SFRIFG1_L = 0x0102); +PROVIDE(SFRIFG1_H = 0x0103); +PROVIDE(SFRRPCR = 0x0104); +PROVIDE(SFRRPCR_L = 0x0104); +PROVIDE(SFRRPCR_H = 0x0105); +/************************************************************ +* SYS - System Module +************************************************************/ +PROVIDE(SYSCTL = 0x0180); +PROVIDE(SYSCTL_L = 0x0180); +PROVIDE(SYSCTL_H = 0x0181); +PROVIDE(SYSBSLC = 0x0182); +PROVIDE(SYSBSLC_L = 0x0182); +PROVIDE(SYSBSLC_H = 0x0183); +PROVIDE(SYSJMBC = 0x0186); +PROVIDE(SYSJMBC_L = 0x0186); +PROVIDE(SYSJMBC_H = 0x0187); +PROVIDE(SYSJMBI0 = 0x0188); +PROVIDE(SYSJMBI0_L = 0x0188); +PROVIDE(SYSJMBI0_H = 0x0189); +PROVIDE(SYSJMBI1 = 0x018A); +PROVIDE(SYSJMBI1_L = 0x018A); +PROVIDE(SYSJMBI1_H = 0x018B); +PROVIDE(SYSJMBO0 = 0x018C); +PROVIDE(SYSJMBO0_L = 0x018C); +PROVIDE(SYSJMBO0_H = 0x018D); +PROVIDE(SYSJMBO1 = 0x018E); +PROVIDE(SYSJMBO1_L = 0x018E); +PROVIDE(SYSJMBO1_H = 0x018F); +PROVIDE(SYSBERRIV = 0x0198); +PROVIDE(SYSBERRIV_L = 0x0198); +PROVIDE(SYSBERRIV_H = 0x0199); +PROVIDE(SYSUNIV = 0x019A); +PROVIDE(SYSUNIV_L = 0x019A); +PROVIDE(SYSUNIV_H = 0x019B); +PROVIDE(SYSSNIV = 0x019C); +PROVIDE(SYSSNIV_L = 0x019C); +PROVIDE(SYSSNIV_H = 0x019D); +PROVIDE(SYSRSTIV = 0x019E); +PROVIDE(SYSRSTIV_L = 0x019E); +PROVIDE(SYSRSTIV_H = 0x019F); +/************************************************************ +* Timer0_A5 +************************************************************/ +PROVIDE(TA0CTL = 0x0340); +PROVIDE(TA0CCTL0 = 0x0342); +PROVIDE(TA0CCTL1 = 0x0344); +PROVIDE(TA0CCTL2 = 0x0346); +PROVIDE(TA0CCTL3 = 0x0348); +PROVIDE(TA0CCTL4 = 0x034A); +PROVIDE(TA0R = 0x0350); +PROVIDE(TA0CCR0 = 0x0352); +PROVIDE(TA0CCR1 = 0x0354); +PROVIDE(TA0CCR2 = 0x0356); +PROVIDE(TA0CCR3 = 0x0358); +PROVIDE(TA0CCR4 = 0x035A); +PROVIDE(TA0IV = 0x036E); +PROVIDE(TA0EX0 = 0x0360); +/************************************************************ +* Timer1_A3 +************************************************************/ +PROVIDE(TA1CTL = 0x0380); +PROVIDE(TA1CCTL0 = 0x0382); +PROVIDE(TA1CCTL1 = 0x0384); +PROVIDE(TA1CCTL2 = 0x0386); +PROVIDE(TA1R = 0x0390); +PROVIDE(TA1CCR0 = 0x0392); +PROVIDE(TA1CCR1 = 0x0394); +PROVIDE(TA1CCR2 = 0x0396); +PROVIDE(TA1IV = 0x03AE); +PROVIDE(TA1EX0 = 0x03A0); +/************************************************************ +* UNIFIED CLOCK SYSTEM FOR Radio Devices +************************************************************/ +PROVIDE(UCSCTL0 = 0x0160); +PROVIDE(UCSCTL0_L = 0x0160); +PROVIDE(UCSCTL0_H = 0x0161); +PROVIDE(UCSCTL1 = 0x0162); +PROVIDE(UCSCTL1_L = 0x0162); +PROVIDE(UCSCTL1_H = 0x0163); +PROVIDE(UCSCTL2 = 0x0164); +PROVIDE(UCSCTL2_L = 0x0164); +PROVIDE(UCSCTL2_H = 0x0165); +PROVIDE(UCSCTL3 = 0x0166); +PROVIDE(UCSCTL3_L = 0x0166); +PROVIDE(UCSCTL3_H = 0x0167); +PROVIDE(UCSCTL4 = 0x0168); +PROVIDE(UCSCTL4_L = 0x0168); +PROVIDE(UCSCTL4_H = 0x0169); +PROVIDE(UCSCTL5 = 0x016A); +PROVIDE(UCSCTL5_L = 0x016A); +PROVIDE(UCSCTL5_H = 0x016B); +PROVIDE(UCSCTL6 = 0x016C); +PROVIDE(UCSCTL6_L = 0x016C); +PROVIDE(UCSCTL6_H = 0x016D); +PROVIDE(UCSCTL7 = 0x016E); +PROVIDE(UCSCTL7_L = 0x016E); +PROVIDE(UCSCTL7_H = 0x016F); +PROVIDE(UCSCTL8 = 0x0170); +PROVIDE(UCSCTL8_L = 0x0170); +PROVIDE(UCSCTL8_H = 0x0171); +/************************************************************ +* USCI A0 +************************************************************/ +PROVIDE(UCA0CTLW0 = 0x05C0); +PROVIDE(UCA0CTLW0_L = 0x05C0); +PROVIDE(UCA0CTLW0_H = 0x05C1); +PROVIDE(UCA0BRW = 0x05C6); +PROVIDE(UCA0BRW_L = 0x05C6); +PROVIDE(UCA0BRW_H = 0x05C7); +PROVIDE(UCA0MCTL = 0x05C8); +PROVIDE(UCA0STAT = 0x05CA); +PROVIDE(UCA0RXBUF = 0x05CC); +PROVIDE(UCA0TXBUF = 0x05CE); +PROVIDE(UCA0ABCTL = 0x05D0); +PROVIDE(UCA0IRCTL = 0x05D2); +PROVIDE(UCA0IRCTL_L = 0x05D2); +PROVIDE(UCA0IRCTL_H = 0x05D3); +PROVIDE(UCA0ICTL = 0x05DC); +PROVIDE(UCA0ICTL_L = 0x05DC); +PROVIDE(UCA0ICTL_H = 0x05DD); +PROVIDE(UCA0IV = 0x05DE); +/************************************************************ +* USCI B0 +************************************************************/ +PROVIDE(UCB0CTLW0 = 0x05E0); +PROVIDE(UCB0CTLW0_L = 0x05E0); +PROVIDE(UCB0CTLW0_H = 0x05E1); +PROVIDE(UCB0BRW = 0x05E6); +PROVIDE(UCB0BRW_L = 0x05E6); +PROVIDE(UCB0BRW_H = 0x05E7); +PROVIDE(UCB0STAT = 0x05EA); +PROVIDE(UCB0RXBUF = 0x05EC); +PROVIDE(UCB0TXBUF = 0x05EE); +PROVIDE(UCB0I2COA = 0x05F0); +PROVIDE(UCB0I2COA_L = 0x05F0); +PROVIDE(UCB0I2COA_H = 0x05F1); +PROVIDE(UCB0I2CSA = 0x05F2); +PROVIDE(UCB0I2CSA_L = 0x05F2); +PROVIDE(UCB0I2CSA_H = 0x05F3); +PROVIDE(UCB0ICTL = 0x05FC); +PROVIDE(UCB0ICTL_L = 0x05FC); +PROVIDE(UCB0ICTL_H = 0x05FD); +PROVIDE(UCB0IV = 0x05FE); +/************************************************************ +* WATCHDOG TIMER A +************************************************************/ +PROVIDE(WDTCTL = 0x015C); +PROVIDE(WDTCTL_L = 0x015C); +PROVIDE(WDTCTL_H = 0x015D); +/************************************************************ +* TLV Descriptors +************************************************************/ +/************************************************************ +* Interrupt Vectors (offset from 0xFF80) +************************************************************/ +/************************************************************ +* End of Modules +************************************************************/ diff --git a/firmware/ota-updater/convert.py b/firmware/ota-updater/convert.py new file mode 100755 index 0000000..32ad734 --- /dev/null +++ b/firmware/ota-updater/convert.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 + +import sys +from binascii import hexlify, unhexlify +import struct +from argparse import ArgumentParser + + +GREEN = '\u001b[32m' +BLUE = '\u001b[34m' +RED = '\u001b[31m' +YELLOW = '\u001b[33m' +RESET = '\u001b[0m' + +MERGE_SECTIONS_MAX_BYTES = 16 + +TYPE_DATA = 0 +TYPE_EOF = 1 +TYPE_ENTRY_POINT = 3 + + +def parse_ihex(filename, ignore_isr=False): + ihex = {} + + cur_addr = 0 + cur_data = b'' + + total_bytes = 0 + segments = [] + + + for line in open(filename): + line = line.strip() + + if not line.startswith(':'): + print(f'line error: {line}', file=sys.stderr) + break + + count = int(line[1:3], 16) + addr = int(line[3:7], 16) + type = int(line[7:9], 16) + data = unhexlify(line[9:-2]) + crc = int(line[-2:], 16) + + crc_calc = (-sum(unhexlify(line[1:-2]))) & 0x0FF + + # print(f'{type:x} {addr:x} {count} {hexlify(data)} {crc:x}') + + if len(data) != count: + print(f'{RED}count error {count} != {len(data)}:{RESET} {line}', file=sys.stderr) + break + + if crc != crc_calc: + print(f'{RED}crc error {crc} != {crc_calc}:{RESET} line', file=sys.stderr) + + if type == TYPE_EOF: + break + + if type == TYPE_ENTRY_POINT: + print(f'{YELLOW}entry point:{RESET} 0x{struct.unpack(">I", data)[0]:x}', file=sys.stderr) + continue + + if type != TYPE_DATA: + print(f'{RED}unhandled type ({type}):{RESET} {line}', file=sys.stderr) + continue + + if addr > cur_addr + len(cur_data) + MERGE_SECTIONS_MAX_BYTES: + + if cur_addr and (not ignore_isr or cur_addr < 0xFF80): + segments += [(cur_addr, cur_data)] + total_bytes += len(cur_data) + + cur_data = b'' + cur_addr = addr + + cur_data += (addr - cur_addr - len(cur_data)) * b'\x00' + data + + + if cur_data and (not ignore_isr or cur_addr < 0xFF80): + segments += [(cur_addr, cur_data)] + total_bytes += len(cur_data) + + ihex['total_bytes'] = total_bytes + ihex['segments'] = segments + + return ihex + + +if __name__ == '__main__': + p = ArgumentParser() + p.add_argument('file') + p.add_argument('-c', '--c-output', action='store_true') + p.add_argument('-t', '--txt-output', action='store_true') + p.add_argument('-b', '--bin-output') + + p.add_argument('-i', '--ignore-isr', action='store_true', default=False) + + args = p.parse_args() + + ihex = parse_ihex(args.file, args.ignore_isr) + + print(f'{YELLOW}total:{RESET} {ihex["total_bytes"]} bytes', file=sys.stderr) + + if args.c_output: + for addr, data in ihex['segments']: + print(f'static const seg_{addr:x}[] = {{') + + for i in range(0, len(data), 16): + print('\t' + ', '.join('0x%02X' % c for c in data[i:i+16]) + ',') + + print('}\n') + + if args.txt_output: + for addr, data in ihex['segments']: + + print(f'@{addr:04X}') + + for i in range(0, len(data), 16): + print(' '.join('%02X' % c for c in data[i:i+16])) + + if args.bin_output: + with open(args.bin_output, 'wb+') as f: + + for addr, data in ihex['segments']: + f.seek(addr) + f.write(data) + diff --git a/firmware/ota-updater/debug.c b/firmware/ota-updater/debug.c new file mode 100644 index 0000000..ce9f43e --- /dev/null +++ b/firmware/ota-updater/debug.c @@ -0,0 +1,20 @@ +#include +#include "debug.h" + +#ifdef DEBUG +static char *debug = (char *) DEBUG_LOG_ADDRESS; + +void LC(char c){ + *debug++ = c; +} + +void L(char *msg){ + while(*msg) + LC(*msg++); + LC('\n'); +} + +#else +void LC(char c){}; +void L(char *msg){}; +#endif diff --git a/firmware/ota-updater/debug.h b/firmware/ota-updater/debug.h new file mode 100644 index 0000000..7dca0a9 --- /dev/null +++ b/firmware/ota-updater/debug.h @@ -0,0 +1,5 @@ + +#define DEBUG_LOG_ADDRESS 0x1e00 + +void L(char *msg); +void LC(char c); diff --git a/firmware/ota-updater/flash.c b/firmware/ota-updater/flash.c new file mode 100644 index 0000000..cde62cb --- /dev/null +++ b/firmware/ota-updater/flash.c @@ -0,0 +1,89 @@ +#include +#include +#include + +#include "flash.h" +#include "debug.h" + +#define DUMMY_ADDRESS 0xFFE0 + +void flash_unlock() { + FCTL3 = FWPW; // clear lock + FCTL1 = FWPW + WRT; // enable write +} + +void flash_lock(void) { + FCTL1 = FWPW; // clear write + FCTL3 = FWPW + LOCK; // set lock +} + +void flash_erase(void) { + volatile char *dummy_ptr; //Flash pointer + + while (FCTL3 & BUSY); + + FCTL3 = FWPW; // clear lock + + while (FCTL3 & BUSY); + + dummy_ptr = (char *)DUMMY_ADDRESS; // ivt start + FCTL1 = FWPW + MERAS + ERASE; // mass erase + *dummy_ptr = 0; // dummy write to make erase complete + + while (FCTL3 & BUSY); + + FCTL3 = FWPW + LOCK; // set lock +} + + +bool flash_write_byte(uint8_t *addr, uint8_t data) { + + while (FCTL3 & BUSY); + *addr = data; + while (FCTL3 & BUSY); + + if (*addr != data) { + return false; + } + return true; +} + +bool flash_write_word(uint16_t *addr, uint16_t data) { + + while (FCTL3 & BUSY); + *addr = data; + while (FCTL3 & BUSY); + if (*addr != data) { + return false; + } + return true; +} + +// Comparisons made in 32bit to prevent overflows +bool flash_write(uint16_t dst, uint8_t *src, uint8_t size) { + bool r = true; + + if (dst < 0x8000 || ((uint32_t) dst + (uint32_t) size) > (uint32_t) 0x10000){ + L("oob"); + return 0; + } + + for (uint32_t i = (uint32_t) dst; i < ((uint32_t) dst) + ((uint32_t) size); i++) { + + if ((dst & 0x01) || i == (uint32_t) dst + (uint32_t) size - 1) { + r = flash_write_byte((uint8_t *)((uint16_t)i), *src); + src += 1; + } else { + r = flash_write_word((uint16_t *)((uint16_t)i), *((uint16_t *)src)); // mis-alignment if rxbuffer is not aligned to 2 + src += 2; + i++; + } + + if (!r) { + return r; + } + + } + + return r; +} diff --git a/firmware/ota-updater/flash.h b/firmware/ota-updater/flash.h new file mode 100644 index 0000000..4f5bf32 --- /dev/null +++ b/firmware/ota-updater/flash.h @@ -0,0 +1,5 @@ + +void flash_unlock(); +void flash_lock(); +bool flash_write(uint16_t dst, uint8_t *src, uint8_t size); +void flash_erase(void); diff --git a/firmware/ota-updater/main.c b/firmware/ota-updater/main.c new file mode 100644 index 0000000..a1f196f --- /dev/null +++ b/firmware/ota-updater/main.c @@ -0,0 +1,245 @@ +#include +#include +#include +#include +//#include + +#include "packet.h" +#include "debug.h" +#include "radio.h" +#include "flash.h" + + +#define st(x) do { x } while (__LINE__ == -1) +#define ENTER_CRITICAL_SECTION(x) st( x = __get_interrupt_state(); __disable_interrupt(); ) +#define EXIT_CRITICAL_SECTION(x) __set_interrupt_state(x) + +#define RAM_IVT_ADDRESS 0x2b80 + +// SIMULATES FLASHING ( doesn't touch flash ) +#define TEST_MODE 0 + +enum STATE { + STATE_LISTEN, + STATE_TRANSFER, + STATE_FINISHED, +}; + +static enum STATE state = STATE_LISTEN; + +enum PKT_TYPE { + PKT_TYPE_INIT = 0, + PKT_TYPE_DATA = 1, + PKT_TYPE_REBOOT = 2, + PKT_TYPE_LOG = 0xf0, + PKT_TYPE_RESET = 0xf1, + PKT_TYPE_BUSY = 0xfa, + PKT_TYPE_DENIED = 0xfb, + PKT_TYPE_UNK = 0xfc, + PKT_TYPE_OOO = 0xfd, + PKT_TYPE_ERR = 0xfe, + PKT_TYPE_OK = 0xff, +}; + +typedef struct { + uint8_t len; + + enum PKT_TYPE type; + + union { + struct { + uint16_t num_packets; + } init; + + struct { + uint16_t nr; + uint16_t address; + uint8_t data[56]; + } __attribute__ ((packed)) data; + +#if DEBUG + struct { + uint8_t data[60]; + } log; +#endif + + uint8_t raw_data[60]; + }; + +} __attribute__ ((packed, aligned(2))) packet_t; + + +static packet_t pkt = {0}; + +static uint16_t pkts_tot = 0; +static uint16_t pkt_num = 0; +static bool ready_to_send = true; + +void packet_ack(enum PKT_TYPE type, int len){ + if (!ready_to_send) + return; + + pkt.len = len; + pkt.type = type; + + // packet_rxoff(); + // __delay_cycles(8500); // TODO: needed? + ready_to_send = false; + packet_tx((uint8_t *) &pkt, len + 1); +} + +void packet_rx(uint8_t *buf, int len){ + + // UCSCTL4 = SELM_3 + SELS_0 + SELA_0; // step up + packet_rxoff(); + __delay_cycles(8500); // TODO: needed? + + packet_t *packet = (packet_t *) buf; + + enum PKT_TYPE rettype = PKT_TYPE_ERR; + int pkt_len = 1; + + switch(packet->type){ + + case PKT_TYPE_INIT: + if (state == STATE_LISTEN){ + L("init"); + pkts_tot = packet->init.num_packets; + pkt_num = 0; + +#if !TEST_MODE + flash_erase(); +#endif + state = STATE_TRANSFER; + rettype = PKT_TYPE_OK; + } else { + L("bsy"); + rettype = PKT_TYPE_BUSY; + } + break; + + case PKT_TYPE_DATA: + if (state == STATE_TRANSFER){ + + if (packet->data.nr == pkt_num + 1 && packet->data.nr <= pkts_tot){ + +#if !TEST_MODE + flash_unlock(); + bool success = flash_write(packet->data.address, packet->data.data, packet->len - 5); + flash_lock(); +#else + bool success = true; +#endif + + if (success){ + // L("written"); + rettype = PKT_TYPE_OK; + pkt_num++; + } else { + L("faild"); + } + + if (packet->data.nr == pkts_tot) { + L("done"); + rettype = PKT_TYPE_OK; + state = STATE_FINISHED; + + // reset mcu + } + } else { + L("ooo"); + rettype = PKT_TYPE_OOO; + } + } else { + rettype = PKT_TYPE_DENIED; + } + break; + +#if DEBUG + case PKT_TYPE_LOG: + memcpy(pkt.log.data, (char*) DEBUG_LOG_ADDRESS, 60); + pkt_len = 60 + 1; + rettype = PKT_TYPE_OK; + break; +#endif + + case PKT_TYPE_RESET: + L("rst"); + state = STATE_LISTEN; + rettype = PKT_TYPE_OK; + break; + + case PKT_TYPE_REBOOT: + state = STATE_FINISHED; + rettype = PKT_TYPE_OK; + break; + + default: + L("unkn"); + rettype = PKT_TYPE_UNK; + break; + + }; + + //__delay_cycles(8500); // TODO: needed? + packet_ack(rettype, pkt_len); +} + +void packet_tx_callback(){ + + if (state == STATE_FINISHED){ + PMMCTL0 = PMMPW | PMMSWBOR; + } + + ready_to_send = true; + packet_rxon(); +} + + +__interrupt void default_isr(){ + L("isr"); +} + + +extern void _start(); +int main() { + L("init"); + + WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer + P2IE = 0; // Disable keypad (port2) + RTCCTL0 &= ~(RTCTEVIE | RTCAIE | RTCRDYIE); // disable rtc + + // UCSCTL4 = SELM_3 + SELS_0 + SELA_0; // step up + + uint8_t int_state; + + packet_rxoff(); + + ENTER_CRITICAL_SECTION(int_state); + + // Not sure what the best strategy is, copy old ivt / set handlers to nop / clear ivt + //memset((char *) RAM_IVT_ADDRESS, 0, 0x80) + //memcpy((char *) RAM_IVT_ADDRESS, (char *)0xff80, 0x80); + static uint16_t *ram_ivt = (uint16_t *) RAM_IVT_ADDRESS; + + for (int i = 0; i < 64; i++){ + ram_ivt[i] = (uint16_t)default_isr; + } + + ram_ivt[53] = (uint16_t) packet_isr; + //ram_ivt[63] = (uint16_t) _start; // doesn't work, as SYSRIVECT will get resetted + + SYSCTL |= SYSRIVECT; + + EXIT_CRITICAL_SECTION(int_state); + + packet_rxon(); + // __delay_cycles(8000); + + L("rdy"); + __bis_SR_register(LPM3_bits + GIE); // Enter LPM3 + + L("err"); + + while(1); +} diff --git a/firmware/ota-updater/packet.c b/firmware/ota-updater/packet.c new file mode 100644 index 0000000..10e7dc8 --- /dev/null +++ b/firmware/ota-updater/packet.c @@ -0,0 +1,120 @@ +/*! \file packet.c + \brief Packet handling library. + + This library is a companion to radio.c, allowing for reception and + transmission of packets. + + For now, we are limited to sixty byte packets that fit within the + radio's internal FIFO buffer. + +*/ + +#include +#include + +#include "packet.h" +#include "radio.h" +#include "debug.h" + +//! Receive packet buffer, with room for RSSI and LQI. +// Needs to be aligned to word size, otherwise write to flash fails silently +static uint8_t rxbuffer[PACKETLEN+2] __attribute__ ((aligned (2))); +//! Length of received packet. +uint8_t rxlen; + +static int transmitting=0, receiving=0; + +extern void packet_rx(uint8_t *buf, int len); +extern void packet_tx_callback(); + +//! Switch to receiving packets. +void packet_rxon(){ + receiving=1; + + RF1AIES |= BIT9; // Falling edge of RFIFG9 + RF1AIFG &= ~BIT9; // Clear a pending interrupt + RF1AIE |= BIT9; // Enable the interrupt + + radio_strobe( RF_SRX ); +} + +//! Stop receiving packets. +void packet_rxoff(){ + RF1AIE &= ~BIT9; // Disable RX interrupts + RF1AIFG &= ~BIT9; // Clear pending IFG + + /* If RXOFF is called in the middle of a packet, it's necessary to + flux the RX queue. + */ + radio_strobe( RF_SIDLE ); + radio_strobe( RF_SFRX ); + receiving=0; +} + +//! Transmit a packet. +void packet_tx(uint8_t *buffer, uint8_t length){ + if(transmitting){ + //printf("Refusing to transmit with pending packet.\n"); + return; + } + transmitting=1; + + RF1AIES |= BIT9; + RF1AIFG &= ~BIT9; // Clear pending interrupts + RF1AIE |= BIT9; // Enable TX end-of-packet interrupt + + + //Write the packet into the buffer. + radio_writeburstreg(RF_TXFIFOWR, buffer, length); + + //Strobe into transmit mode. + radio_strobe( RF_STX ); +} + + +//! Interrupt handler for incoming packets. +__interrupt void packet_isr (void) { + + int rf1aiv=RF1AIV; + int state; + + switch(rf1aiv&~1){ // Prioritizing Radio Core Interrupt + case 20: // RFIFG9 + if(receiving){ //End of RX packet. + + //Wait for end of packet. + do{ + state=radio_getstate(); + //__delay_cycles(8500); + }while(state==13 || state==14 || state==15 || state==20 || state==21); + + + if(state==1){ + // Read the length byte from the FIFO. + rxlen = radio_readreg( RXBYTES ); + //__delay_cycles(8500); + + /* We read no more than our buffer. */ + radio_readburstreg(RF_RXFIFORD, rxbuffer, rxlen > PACKETLEN ? PACKETLEN : rxlen); + + //Inform the application. + packet_rx(rxbuffer, rxlen); + + }else if(state==17){ + L("RXO"); + radio_strobe(RF_SFRX); + radio_strobe(RF_SRX); + }else{ + } + }else if(transmitting){ //End of TX packet. + RF1AIE &= ~BIT9; // Disable TX end-of-packet interrupt + transmitting = 0; + //Inform the updater + packet_tx_callback(); + }else{ + //printf("Unexpected packet ISR.\n"); + } + break; + } + +} diff --git a/firmware/ota-updater/packet.h b/firmware/ota-updater/packet.h new file mode 100644 index 0000000..1974b44 --- /dev/null +++ b/firmware/ota-updater/packet.h @@ -0,0 +1,26 @@ +/*! \file packet.h + \brief Packet handling library. +*/ + +#include + +//! Length of the packet buffer. +#define PACKETLEN 64 + +//! Receive packet buffer. +//extern uint8_t rxbuffer[]; +//! Transmit packet buffer. +//extern uint8_t txbuffer[]; + + + +//! Switch to receiving packets. +void packet_rxon(); + +//! Stop receiving packets. +void packet_rxoff(); + +//! Transmit a packet. +void packet_tx(uint8_t *buffer, uint8_t length); + +void packet_isr(); diff --git a/firmware/ota-updater/radio.c b/firmware/ota-updater/radio.c new file mode 100644 index 0000000..e1a3981 --- /dev/null +++ b/firmware/ota-updater/radio.c @@ -0,0 +1,159 @@ +/*! \file radio.c + \brief RF1A Radio Module Driver + + This is our neighborly little driver for the RF1A radio module. + While we try really hard to avoid lasagna-code by over-abstracting + drivers, the radio needs to be abstracted for good reasons, with + exceptions to that rule in applications as appropriate. + + In general: + + 1) Not all watches have a radio, so your application ought to + gracefully fail if XT2 is not present. + + 2) The CR2016 battery lasts forever when telling the time, but + you'll quickly run out of juice if you leave the radio on. For this + reason, your app should probably time out after three minutes and + you should never expect to be receiving in the background. + + 3) Remember that transmitting is cheaper than receiving, because a + transmitter can shut down afterward. + + 4) The CPU runs at 32kHz by default. You can speed it up, but at + the cost of power consumption. + +*/ + +#include +#include +#include + +#include "radio.h" + +//! Cleared to zero at the first radio failure. +//! Read a register from the radio. +uint8_t radio_readreg(uint8_t addr){ + // Check for valid configuration register address, 0x3E refers to PATABLE + if ((addr <= 0x2E) || (addr == 0x3E)) + // Send address + Instruction + 1 dummy byte (auto-read) + RF1AINSTR1B = (addr | RF_SNGLREGRD); + else + // Send address + Instruction + 1 dummy byte (auto-read) + RF1AINSTR1B = (addr | RF_STATREGRD); + + while (!(RF1AIFCTL1 & RFDOUTIFG) ); + + //Reading the data clears the interrupt flag. + return RF1ADOUTB; +} + +//! Read multiple bytes from a register. +void radio_readburstreg(uint8_t addr, + uint8_t *buffer, uint8_t count){ + unsigned int i; + + if(count > 0){ + while (!(RF1AIFCTL1 & RFINSTRIFG)); // Wait for INSTRIFG + RF1AINSTR1B = (addr | RF_REGRD); // Send addr of first conf. reg. to be read + // ... and the burst-register read instruction + for (i = 0; i < (count-1); i++) { + while (!(RFDOUTIFG&RF1AIFCTL1)); // Wait for the Radio Core to update the RF1ADOUTB reg + buffer[i] = RF1ADOUT1B; // Read DOUT from Radio Core + clears RFDOUTIFG + // Also initiates auo-read for next DOUT byte + } + buffer[count-1] = RF1ADOUT0B; // Store the last DOUT from Radio Core + } +} + +//! Write multiple bytes to a register. +void radio_writeburstreg(uint8_t addr, + uint8_t *buffer, uint8_t count){ + unsigned char i; + + if(count > 0){ + while (!(RF1AIFCTL1 & RFINSTRIFG)); // Wait for the Radio to be ready for next instruction + RF1AINSTRW = ((addr | RF_REGWR)<<8 ) + buffer[0]; // Send address + Instruction + + for (i = 1; i < count; i++) { + RF1ADINB = buffer[i]; // Send data + while (!(RFDINIFG & RF1AIFCTL1)); // Wait for TX to finish + } + i = RF1ADOUTB; // Reset RFDOUTIFG flag which contains status byte + } +} + +//! Write to a register in the radio. +void radio_writereg(uint8_t addr, uint8_t value){ + // Wait until the radio is ready. + while (!(RF1AIFCTL1 & RFINSTRIFG)); + + // Send the address and instruction. + RF1AINSTRB = (addr | RF_SNGLREGWR); + // And the value. + RF1ADINB = value; +} + + +//! Strobe a radio register. +uint8_t radio_strobe(uint8_t strobe){ + uint8_t statusByte = 0; + uint16_t count=0; + uint16_t gdo_state; + + + // Check for valid strobe command + if((strobe == 0xBD) || ((strobe >= RF_SRES) && (strobe <= RF_SNOP))){ + // Clear the Status read flag + RF1AIFCTL1 &= ~(RFSTATIFG); + + // Wait for radio to be ready for next instruction + while( !(RF1AIFCTL1 & RFINSTRIFG)); + + + // Write the strobe instruction + if ((strobe > RF_SRES) && (strobe < RF_SNOP)){ + gdo_state = radio_readreg(IOCFG2); // buffer IOCFG2 state + radio_writereg(IOCFG2, 0x29); // chip-ready to GDO2 + + RF1AINSTRB = strobe; + if ( (RF1AIN&0x04)== 0x04 ) { // chip at sleep mode + if ( (strobe == RF_SXOFF) || (strobe == RF_SPWD) || (strobe == RF_SWOR) ) { + + }else{ + /* We'll get stuck in an infinite loop here if the radio + crystal isn't available. + */ + while ((RF1AIN&0x04)== 0x04){ + if(count++>1000){ + //printf("Timeout in radio_strobe. Broken XT2?\n"); + return 0xFF; + } + } + + // Delay for ~810usec at 1.05MHz CPU clock, see the CC430 Family User's + // Guide,ยง 25.3.3.7.1 page 698 in rev E. The delay is to provide time + // for the radio's oscillator to stabilize. + __delay_cycles(850); + } + } + + radio_writereg(IOCFG2, gdo_state); // restore IOCFG2 setting + + while( !(RF1AIFCTL1 & RFSTATIFG) ); + }else{ //Active mode + RF1AINSTRB = strobe; + } + + statusByte = RF1ASTATB; + } + + return statusByte; +} + + +//! Read the radio MARC state. +int radio_getstate(){ + int state; + state=radio_readreg(MARCSTATE); + return state; +} diff --git a/firmware/ota-updater/radio.h b/firmware/ota-updater/radio.h new file mode 100644 index 0000000..d2fdd6b --- /dev/null +++ b/firmware/ota-updater/radio.h @@ -0,0 +1,25 @@ +/*! \file radio.h + \brief RF1A Radio Module Driver + +*/ + +//! Set to 1 if the watch has a radio. +extern int has_radio; + + +//! Read a register from the radio. +uint8_t radio_readreg(uint8_t addr); +//! Write to a register in the radio. +void radio_writereg(uint8_t addr, uint8_t value); + +//! Read multiple bytes from a register. +void radio_readburstreg(uint8_t addr, + uint8_t *buffer, uint8_t count); +//! Write multiple bytes to a register. +void radio_writeburstreg(uint8_t addr, + uint8_t *buffer, uint8_t count); + +//! Strobe a radio register. +uint8_t radio_strobe(uint8_t strobe); + +int radio_getstate();