Skip to content

Commit b789f11

Browse files
committed
Merge pull request #138 from tekka007/OTA-fix
Sensebender OTA
2 parents 0656b03 + 76493ff commit b789f11

File tree

3 files changed

+193
-112
lines changed

3 files changed

+193
-112
lines changed

libraries/MySensors/MySensor.cpp

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -74,24 +74,21 @@ MySensor::MySensor(MyTransport &_radio, MyHw &_hw
7474

7575

7676
#ifdef MY_OTA_FIRMWARE_FEATURE
77+
7778
// do a crc16 on the whole received firmware
78-
bool MySensor::isValidFirmware() {
79-
void* ptr = 0;
79+
bool MySensor::isValidFirmware() {
80+
// init crc
8081
uint16_t crc = ~0;
81-
int j;
82-
8382
for (uint16_t i = 0; i < fc.blocks * FIRMWARE_BLOCK_SIZE; ++i) {
84-
uint8_t a = flash.readByte((uint16_t) ptr + i + FIRMWARE_START_OFFSET);
85-
crc ^= a;
86-
for (j = 0; j < 8; ++j)
87-
{
83+
crc ^= flash.readByte(i + FIRMWARE_START_OFFSET);
84+
for (int8_t j = 0; j < 8; ++j) {
8885
if (crc & 1)
8986
crc = (crc >> 1) ^ 0xA001;
9087
else
9188
crc = (crc >> 1);
9289
}
93-
}
94-
return crc == fc.crc;
90+
}
91+
return crc == fc.crc;
9592
}
9693

9794
#endif
@@ -722,46 +719,61 @@ boolean MySensor::process() {
722719
// compare with current node configuration, if they differ, start fw fetch process
723720
if (memcmp(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) {
724721
debug(PSTR("fw update\n"));
725-
fwUpdateOngoing = true;
726-
fwBlock = fc.blocks;
727722
// copy new FW config
728723
memcpy(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig));
729724
// Init flash
730725
if (!flash.initialize()) {
731726
debug(PSTR("flash init fail\n"));
727+
fwUpdateOngoing = false;
728+
} else {
729+
// erase lower 32K -> max flash size for ATMEGA328
730+
flash.blockErase32K(0);
731+
// wait until flash erased
732+
while ( flash.busy() );
733+
fwBlock = fc.blocks;
734+
fwUpdateOngoing = true;
735+
// reset flags
736+
fwRetry = MY_OTA_RETRY+1;
737+
fwLastRequestTime = 0;
732738
}
733-
734-
}
739+
return false;
740+
} else debug(PSTR("fw update skipped\n"));
735741
} else if (type == ST_FIRMWARE_RESPONSE) {
736-
// Save block to eeprom
742+
// Save block to flash
737743
debug(PSTR("fw block %d\n"), fwBlock);
738-
744+
// extract FW block
739745
ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)msg.data;
740746
// write to flash
741-
flash.writeBytes(((fwBlock-1)*FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE);
747+
flash.writeBytes( ((fwBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE);
748+
// wait until flash written
749+
while ( flash.busy() );
742750
fwBlock--;
743-
if (fwBlock == 0) {
751+
if (!fwBlock) {
744752
// We're finished! Do a checksum and reboot.
745753
if (isValidFirmware()) {
746754
debug(PSTR("fw checksum ok\n"));
747755
// All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it)
748-
uint16_t fwsize = FIRMWARE_BLOCK_SIZE*fc.blocks;
749756
flash.writeBytes(0, "FLXIMG:", 7);
757+
// FW size in flash
758+
uint16_t fwsize = FIRMWARE_BLOCK_SIZE * fc.blocks;
750759
flash.writeByte(7, fwsize >> 8);
751760
flash.writeByte(8, fwsize);
761+
// end of header
752762
flash.writeByte(9, ':');
753763
// Write the new firmware config to eeprom
754764
hw_writeConfigBlock((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig));
755765
hw_reboot();
756766
} else {
757767
debug(PSTR("fw checksum fail\n"));
768+
fwUpdateOngoing = false;
758769
}
759770
}
771+
// reset flags
772+
fwRetry = MY_OTA_RETRY+1;
773+
fwLastRequestTime = 0;
774+
return false;
760775
}
761-
// Make sure packet request occurs next time process() is called by timing out requestTime.
762-
fwRetry = MY_OTA_RETRY+1;
763-
fwLastRequestTime = 0;
764-
return false;
776+
765777
}
766778
#endif
767779
// Call incoming message callback if available

libraries/MySensors/utility/SPIFlash.cpp

Lines changed: 94 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,40 @@
1-
/*
2-
* Copyright (c) 2013 by Felix Rusu <[email protected]>
3-
* SPI Flash memory library for arduino/moteino.
4-
* This works with 256byte/page SPI flash memory
5-
* For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes)
6-
* Minimal modifications should allow chips that have different page size but modifications
7-
* DEPENDS ON: Arduino SPI library
8-
*
9-
* This file is free software; you can redistribute it and/or modify
10-
* it under the terms of either the GNU General Public License version 2
11-
* or the GNU Lesser General Public License version 2.1, both as
12-
* published by the Free Software Foundation.
13-
*/
1+
// Copyright (c) 2013-2015 by Felix Rusu, LowPowerLab.com
2+
// SPI Flash memory library for arduino/moteino.
3+
// This works with 256byte/page SPI flash memory
4+
// For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes)
5+
// Minimal modifications should allow chips that have different page size but modifications
6+
// DEPENDS ON: Arduino SPI library
7+
// > Updated Jan. 5, 2015, TomWS1, modified writeBytes to allow blocks > 256 bytes and handle page misalignment.
8+
// > Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above)
9+
// > Selective merge by Felix after testing in IDE 1.0.6, 1.6.4
10+
// **********************************************************************************
11+
// License
12+
// **********************************************************************************
13+
// This program is free software; you can redistribute it
14+
// and/or modify it under the terms of the GNU General
15+
// Public License as published by the Free Software
16+
// Foundation; either version 3 of the License, or
17+
// (at your option) any later version.
18+
//
19+
// This program is distributed in the hope that it will
20+
// be useful, but WITHOUT ANY WARRANTY; without even the
21+
// implied warranty of MERCHANTABILITY or FITNESS FOR A
22+
// PARTICULAR PURPOSE. See the GNU General Public
23+
// License for more details.
24+
//
25+
// You should have received a copy of the GNU General
26+
// Public License along with this program.
27+
// If not, see <http://www.gnu.org/licenses/>.
28+
//
29+
// Licence can be viewed at
30+
// http://www.gnu.org/licenses/gpl-3.0.txt
31+
//
32+
// Please maintain this license information along with authorship
33+
// and copyright notices in any redistribution of this code
1434

1535
#include <SPIFlash.h>
1636

17-
byte SPIFlash::UNIQUEID[8];
37+
uint8_t SPIFlash::UNIQUEID[8];
1838

1939
/// IMPORTANT: NAND FLASH memory requires erase before write, because
2040
/// it can only transition from 1s to 0s and only the erase command can reset all 0s to 1s
@@ -32,34 +52,48 @@ SPIFlash::SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID) {
3252

3353
/// Select the flash chip
3454
void SPIFlash::select() {
35-
noInterrupts();
3655
//save current SPI settings
56+
#ifndef SPI_HAS_TRANSACTION
57+
noInterrupts();
58+
#endif
3759
_SPCR = SPCR;
3860
_SPSR = SPSR;
39-
//set FLASH chip SPI settings
61+
62+
#ifdef SPI_HAS_TRANSACTION
63+
SPI.beginTransaction(_settings);
64+
#else
65+
// set FLASH SPI settings
4066
SPI.setDataMode(SPI_MODE0);
4167
SPI.setBitOrder(MSBFIRST);
4268
SPI.setClockDivider(SPI_CLOCK_DIV4); //decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present
4369
SPI.begin();
70+
#endif
4471
digitalWrite(_slaveSelectPin, LOW);
4572
}
4673

4774
/// UNselect the flash chip
4875
void SPIFlash::unselect() {
4976
digitalWrite(_slaveSelectPin, HIGH);
5077
//restore SPI settings to what they were before talking to the FLASH chip
78+
#ifdef SPI_HAS_TRANSACTION
79+
SPI.endTransaction();
80+
#else
81+
interrupts();
82+
#endif
5183
SPCR = _SPCR;
5284
SPSR = _SPSR;
53-
interrupts();
5485
}
5586

5687
/// setup SPI, read device ID etc...
5788
boolean SPIFlash::initialize()
5889
{
59-
SPI.begin();
6090
_SPCR = SPCR;
6191
_SPSR = SPSR;
6292
pinMode(_slaveSelectPin, OUTPUT);
93+
#ifdef SPI_HAS_TRANSACTION
94+
_settings = SPISettings(4000000, MSBFIRST, SPI_MODE0);
95+
#endif
96+
6397
unselect();
6498
wakeup();
6599

@@ -73,15 +107,15 @@ boolean SPIFlash::initialize()
73107
}
74108

75109
/// Get the manufacturer and device ID bytes (as a short word)
76-
word SPIFlash::readDeviceId()
110+
uint16_t SPIFlash::readDeviceId()
77111
{
78112
#if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo
79113
command(SPIFLASH_IDREAD); // Read JEDEC ID
80114
#else
81115
select();
82116
SPI.transfer(SPIFLASH_IDREAD);
83117
#endif
84-
word jedecid = SPI.transfer(0) << 8;
118+
uint16_t jedecid = SPI.transfer(0) << 8;
85119
jedecid |= SPI.transfer(0);
86120
unselect();
87121
return jedecid;
@@ -90,47 +124,47 @@ word SPIFlash::readDeviceId()
90124
/// Get the 64 bit unique identifier, stores it in UNIQUEID[8]. Only needs to be called once, ie after initialize
91125
/// Returns the byte pointer to the UNIQUEID byte array
92126
/// Read UNIQUEID like this:
93-
/// flash.readUniqueId(); for (byte i=0;i<8;i++) { Serial.print(flash.UNIQUEID[i], HEX); Serial.print(' '); }
127+
/// flash.readUniqueId(); for (uint8_t i=0;i<8;i++) { Serial.print(flash.UNIQUEID[i], HEX); Serial.print(' '); }
94128
/// or like this:
95-
/// flash.readUniqueId(); byte* MAC = flash.readUniqueId(); for (byte i=0;i<8;i++) { Serial.print(MAC[i], HEX); Serial.print(' '); }
96-
byte* SPIFlash::readUniqueId()
129+
/// flash.readUniqueId(); uint8_t* MAC = flash.readUniqueId(); for (uint8_t i=0;i<8;i++) { Serial.print(MAC[i], HEX); Serial.print(' '); }
130+
uint8_t* SPIFlash::readUniqueId()
97131
{
98132
command(SPIFLASH_MACREAD);
99133
SPI.transfer(0);
100134
SPI.transfer(0);
101135
SPI.transfer(0);
102136
SPI.transfer(0);
103-
for (byte i=0;i<8;i++)
137+
for (uint8_t i=0;i<8;i++)
104138
UNIQUEID[i] = SPI.transfer(0);
105139
unselect();
106140
return UNIQUEID;
107141
}
108142

109143
/// read 1 byte from flash memory
110-
byte SPIFlash::readByte(long addr) {
144+
uint8_t SPIFlash::readByte(uint32_t addr) {
111145
command(SPIFLASH_ARRAYREADLOWFREQ);
112146
SPI.transfer(addr >> 16);
113147
SPI.transfer(addr >> 8);
114148
SPI.transfer(addr);
115-
byte result = SPI.transfer(0);
149+
uint8_t result = SPI.transfer(0);
116150
unselect();
117151
return result;
118152
}
119153

120154
/// read unlimited # of bytes
121-
void SPIFlash::readBytes(long addr, void* buf, word len) {
155+
void SPIFlash::readBytes(uint32_t addr, void* buf, uint16_t len) {
122156
command(SPIFLASH_ARRAYREAD);
123157
SPI.transfer(addr >> 16);
124158
SPI.transfer(addr >> 8);
125159
SPI.transfer(addr);
126160
SPI.transfer(0); //"dont care"
127-
for (word i = 0; i < len; ++i)
128-
((byte*) buf)[i] = SPI.transfer(0);
161+
for (uint16_t i = 0; i < len; ++i)
162+
((uint8_t*) buf)[i] = SPI.transfer(0);
129163
unselect();
130164
}
131165

132166
/// Send a command to the flash chip, pass TRUE for isWrite when its a write command
133-
void SPIFlash::command(byte cmd, boolean isWrite){
167+
void SPIFlash::command(uint8_t cmd, boolean isWrite){
134168
#if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo
135169
DDRB |= B00000001; // Make sure the SS pin (PB0 - used by RFM12B on MoteinoLeo R1) is set as output HIGH!
136170
PORTB |= B00000001;
@@ -156,19 +190,19 @@ boolean SPIFlash::busy()
156190
/*
157191
select();
158192
SPI.transfer(SPIFLASH_STATUSREAD);
159-
byte status = SPI.transfer(0);
193+
uint8_t status = SPI.transfer(0);
160194
unselect();
161195
return status & 1;
162196
*/
163197
return readStatus() & 1;
164198
}
165199

166200
/// return the STATUS register
167-
byte SPIFlash::readStatus()
201+
uint8_t SPIFlash::readStatus()
168202
{
169203
select();
170204
SPI.transfer(SPIFLASH_STATUSREAD);
171-
byte status = SPI.transfer(0);
205+
uint8_t status = SPI.transfer(0);
172206
unselect();
173207
return status;
174208
}
@@ -177,7 +211,7 @@ byte SPIFlash::readStatus()
177211
/// Write 1 byte to flash memory
178212
/// WARNING: you can only write to previously erased memory locations (see datasheet)
179213
/// use the block erase commands to first clear memory (write 0xFFs)
180-
void SPIFlash::writeByte(long addr, uint8_t byt) {
214+
void SPIFlash::writeByte(uint32_t addr, uint8_t byt) {
181215
command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program
182216
SPI.transfer(addr >> 16);
183217
SPI.transfer(addr >> 8);
@@ -186,20 +220,32 @@ void SPIFlash::writeByte(long addr, uint8_t byt) {
186220
unselect();
187221
}
188222

189-
/// write 1-256 bytes to flash memory
223+
/// write multiple bytes to flash memory (up to 64K)
190224
/// WARNING: you can only write to previously erased memory locations (see datasheet)
191225
/// use the block erase commands to first clear memory (write 0xFFs)
192-
/// WARNING: if you write beyond a page boundary (or more than 256bytes),
193-
/// the bytes will wrap around and start overwriting at the beginning of that same page
194-
/// see datasheet for more details
195-
void SPIFlash::writeBytes(long addr, const void* buf, uint16_t len) {
196-
command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program
197-
SPI.transfer(addr >> 16);
198-
SPI.transfer(addr >> 8);
199-
SPI.transfer(addr);
200-
for (uint16_t i = 0; i < len; i++)
201-
SPI.transfer(((byte*) buf)[i]);
202-
unselect();
226+
/// This version handles both page alignment and data blocks larger than 256 bytes.
227+
///
228+
void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len) {
229+
uint16_t n;
230+
uint16_t maxBytes = 256-(addr%256); // force the first set of bytes to stay within the first page
231+
uint16_t offset = 0;
232+
while (len>0)
233+
{
234+
n = (len<=maxBytes) ? len : maxBytes;
235+
command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program
236+
SPI.transfer(addr >> 16);
237+
SPI.transfer(addr >> 8);
238+
SPI.transfer(addr);
239+
240+
for (uint16_t i = 0; i < n; i++)
241+
SPI.transfer(((uint8_t*) buf)[offset + i]);
242+
unselect();
243+
244+
addr+=n; // adjust the addresses and remaining bytes by what we've just transferred.
245+
offset +=n;
246+
len -= n;
247+
maxBytes = 256; // now we can do up to 256 bytes per loop
248+
}
203249
}
204250

205251
/// erase entire flash memory array
@@ -214,7 +260,7 @@ void SPIFlash::chipErase() {
214260
}
215261

216262
/// erase a 4Kbyte block
217-
void SPIFlash::blockErase4K(long addr) {
263+
void SPIFlash::blockErase4K(uint32_t addr) {
218264
command(SPIFLASH_BLOCKERASE_4K, true); // Block Erase
219265
SPI.transfer(addr >> 16);
220266
SPI.transfer(addr >> 8);
@@ -223,7 +269,7 @@ void SPIFlash::blockErase4K(long addr) {
223269
}
224270

225271
/// erase a 32Kbyte block
226-
void SPIFlash::blockErase32K(long addr) {
272+
void SPIFlash::blockErase32K(uint32_t addr) {
227273
command(SPIFLASH_BLOCKERASE_32K, true); // Block Erase
228274
SPI.transfer(addr >> 16);
229275
SPI.transfer(addr >> 8);

0 commit comments

Comments
 (0)