Added Partial Flashing Service (#9)
* Memory Map + Partial Flash Service * Moved Partial Flash Service to Management Mode * PF Service appears in YT Build not PXT * PF in PXT * Swapped DFU and PF Services * Fixing Flash Writew * write flash via bluetooth * Partial Flash - Fixed Address * Update module.json * Adjust flash pointer * Adjust flash start * Adjust Flash Pointer * Added offset to xfer * Writing to FLASH_END * Writing to FLASH_END * Modified PFS read callback * Reenable BLE Security * removed pf * Check diff * Check diff * Replaced ContextSwitch * PF * Test. Writing Hex File to 0x30000 * Writing to PXT empty space * Reversed byte order * Flash 16 bytes at once * Copy data from static var to local var * blocks -> bytes * Fixed offset * Fixed Offset * Flash to 0x30000 + offset * Bypass scratch page * Changed byte order * Write Without Response * Without Fast BLE * Added fast BLE * Updated Connection Parameters * Iterate through BLE data bytes * Get Hashes From PXT Build * Copy Hash from Flash * Testing FLASH_END * Read Hash From Flash * Read Hash from Flash * Reading correct hash from mem * Endianess * Modified MAGIC * Fix Start Address * Sequence # * Write 0xdeadbeef to 0x36000 on PF Seq # error * Group 4 packet blocks for writing * Added error case * Increased flash write size * Blocks * Fire event to write * Decreased flash time * Reformat * Reduced hash size in MemoryMap * Partial Flashing w/ Notifications * One Characteristic - WRITE/WRITE_WOUT_RESP/NOTIFY * Modified WRITE Notification * Tidied - Moved end of transfer logic * Removed VI Swap files * Added Pairing Mode Event ID * Modified Retransmit behaviour * updateFlash caused stack overflow * Removed flash write from memory map * Instantiate Memory Map where used * Word aligned. Added Status and Reset commands * Fixed: storage. becomes storage-> * Fixed warnings: switch case fall through * Fix Hash * Rebuild Map everytime * Hash Error * Edited animation. Hash testing * persistent memory map issues * Moved EOT * Modified BLE animation. Removed globals from PFS * Updated MM * Added incomplete flash flag * Re added CCS.smaster
parent
2cff906f01
commit
3413d5487d
@ -0,0 +1,106 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 British Broadcasting Corporation.
|
||||
This software is provided by Lancaster University by arrangement with the BBC.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROBIT_PARTIAL_FLASH_SERVICE_H
|
||||
#define MICROBIT_PARTIAL_FLASH_SERVICE_H
|
||||
|
||||
#include "MicroBitConfig.h"
|
||||
#include "MicroBitBLEManager.h"
|
||||
#include "ble/BLE.h"
|
||||
#include "MicroBitMemoryMap.h"
|
||||
|
||||
#include "MicroBitFlash.h"
|
||||
#include "MicroBitStorage.h"
|
||||
|
||||
#include "MicroBitComponent.h"
|
||||
#include "MicroBitEvent.h"
|
||||
#include "MicroBitListener.h"
|
||||
#include "EventModel.h"
|
||||
|
||||
#define PARTIAL_FLASHING_VERSION 0x01
|
||||
|
||||
// UUIDs for our service and characteristics
|
||||
extern const uint8_t MicroBitPartialFlashingServiceUUID[];
|
||||
extern const uint8_t MicroBitPartialFlashingServiceCharacteristicUUID[];
|
||||
|
||||
/**
|
||||
* Class definition for the custom MicroBit Partial Flash Service.
|
||||
* Provides a BLE service to remotely read the memory map and flash the PXT program.
|
||||
*/
|
||||
class MicroBitPartialFlashingService
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a representation of the Partial Flash Service
|
||||
* @param _ble The instance of a BLE device that we're running on.
|
||||
* @param _memoryMap An instance of MicroBiteMemoryMap to interface with.
|
||||
*/
|
||||
MicroBitPartialFlashingService(BLEDevice &_ble, EventModel &_messageBus);
|
||||
|
||||
/**
|
||||
* Callback. Invoked when any of our attributes are written via BLE.
|
||||
*/
|
||||
void onDataWritten(const GattWriteCallbackParams *params);
|
||||
|
||||
/**
|
||||
* Callback. Invoked when any of our attributes are read via BLE.
|
||||
*/
|
||||
void onDataRead(GattReadAuthCallbackParams *params);
|
||||
|
||||
private:
|
||||
// M:B Bluetooth stack and MessageBus
|
||||
BLEDevice &ble;
|
||||
EventModel &messageBus;
|
||||
|
||||
/**
|
||||
* Writing to flash inside MicroBitEvent rather than in the ISR
|
||||
*/
|
||||
void partialFlashingEvent(MicroBitEvent e);
|
||||
|
||||
// The base address to write to. Bit masked: (0xFFFF0000 & region.endAddress) >> 16
|
||||
uint8_t baseAddress = 0x3;
|
||||
|
||||
// Handles to access each characteristic when they are held by Soft Device.
|
||||
GattAttribute::Handle_t partialFlashCharacteristicHandle;
|
||||
|
||||
/**
|
||||
* Process a Partial Flashing data packet
|
||||
*/
|
||||
void flashData(uint8_t *data);
|
||||
|
||||
// Ensure packets are in order
|
||||
uint8_t packetCount = 0;
|
||||
uint8_t blockPacketCount = 0;
|
||||
|
||||
// Keep track of blocks of data
|
||||
uint32_t block[16];
|
||||
uint8_t blockNum = 0;
|
||||
uint16_t offset = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,123 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 British Broadcasting Corporation.
|
||||
This software is provided by Lancaster University by arrangement with the BBC.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROBIT_MEMORY_MAP_H
|
||||
#define MICROBIT_MEMORY_MAP_H
|
||||
|
||||
#include "mbed.h"
|
||||
#include "MicroBitConfig.h"
|
||||
#include "ManagedString.h"
|
||||
#include "ErrorNo.h"
|
||||
|
||||
#define MICROBIT_MEMORY_MAP_MAGIC 0xCA8E
|
||||
|
||||
#define NUMBER_OF_REGIONS 3
|
||||
|
||||
/**
|
||||
* Class definition for the MicroBitMemoryMap class.
|
||||
* This allows reading and writing of regions within the memory map.
|
||||
*
|
||||
* This class maps the different regions used on the flash memory to allow
|
||||
* a region to updated independently of the others AKA Partial Flashing.
|
||||
*/
|
||||
class MicroBitMemoryMap
|
||||
{
|
||||
struct Region
|
||||
{
|
||||
uint8_t regionId;
|
||||
uint32_t startAddress;
|
||||
uint32_t endAddress;
|
||||
uint8_t hash[8];
|
||||
|
||||
Region(uint8_t regionId, uint32_t startAddress, uint32_t endAddress, uint8_t hash[8])
|
||||
{
|
||||
this->regionId = regionId;
|
||||
this->startAddress = startAddress;
|
||||
this->endAddress = endAddress;
|
||||
memmove( this->hash, &hash, 8 );
|
||||
}
|
||||
|
||||
Region(){
|
||||
this->regionId = 0x0;
|
||||
this->startAddress = 0x0;
|
||||
this->endAddress = 0x0;
|
||||
memset( this->hash, 0xDD, 8 );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct MemoryMapStore
|
||||
{
|
||||
Region memoryMap[3];
|
||||
};
|
||||
|
||||
uint8_t regionCount = 0;
|
||||
|
||||
/**
|
||||
* Function to update the flash with the current MemoryMapStore
|
||||
*
|
||||
* @param memoryMapStore The memory map to write to flash
|
||||
*/
|
||||
void updateFlash(MemoryMapStore *store);
|
||||
|
||||
public:
|
||||
|
||||
MemoryMapStore memoryMapStore;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*
|
||||
* Creates an instance of MicroBitMemoryMap
|
||||
*/
|
||||
MicroBitMemoryMap();
|
||||
|
||||
/**
|
||||
* Function for adding a Region to the end of the MemoryMap
|
||||
*
|
||||
* @param region The Region to add to the MemoryMap
|
||||
*
|
||||
* @return MICROBIT_OK on success
|
||||
*
|
||||
*/
|
||||
int pushRegion(Region region);
|
||||
|
||||
/**
|
||||
* Function for updating a Region of the MemoryMap
|
||||
*
|
||||
* @param region The Region to update in the MemoryMap. The name is used as the selector.
|
||||
*
|
||||
* @return MICROBIT_OK success, MICROBIT_NO_DATA if the region is not found
|
||||
*/
|
||||
int updateRegion(Region region);
|
||||
|
||||
/**
|
||||
* Function to fetch hashes from PXT build
|
||||
*
|
||||
* @return int Boolean result of the search. 1 = Hashes Found; 0 = No Hash Found
|
||||
*/
|
||||
void findHashes();
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,322 @@
|
||||
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 British Broadcasting Corporation.
|
||||
This software is provided by Lancaster University by arrangement with the BBC.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class definition for the custom MicroBit Partial Flashing service.
|
||||
* Provides a BLE service to remotely write the user program to the device.
|
||||
*/
|
||||
#include "MicroBitConfig.h"
|
||||
#include "ble/UUID.h"
|
||||
#include "MicroBitPartialFlashingService.h"
|
||||
|
||||
// BLE PF Control Codes
|
||||
#define REGION_INFO 0x00
|
||||
#define FLASH_DATA 0x01
|
||||
#define END_OF_TRANSMISSION 0x02
|
||||
|
||||
// BLE Utilities
|
||||
#define MICROBIT_STATUS 0xEE
|
||||
#define MICROBIT_RESET 0xFF
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a representation of the PartialFlashService
|
||||
* @param _ble The instance of a BLE device that we're running on.
|
||||
* @param _messageBus The instance of a EventModel that we're running on.
|
||||
*/
|
||||
MicroBitPartialFlashingService::MicroBitPartialFlashingService(BLEDevice &_ble, EventModel &_messageBus) :
|
||||
ble(_ble), messageBus(_messageBus)
|
||||
{
|
||||
// Set up partial flashing characteristic
|
||||
uint8_t initCharacteristicValue = 0x00;
|
||||
GattCharacteristic partialFlashCharacteristic(MicroBitPartialFlashingServiceCharacteristicUUID, &initCharacteristicValue, sizeof(initCharacteristicValue),
|
||||
20, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
|
||||
|
||||
// Set default security requirements
|
||||
partialFlashCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
|
||||
|
||||
// Create Partial Flashing Service
|
||||
GattCharacteristic *characteristics[] = {&partialFlashCharacteristic};
|
||||
GattService service(MicroBitPartialFlashingServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic*) );
|
||||
ble.addService(service);
|
||||
|
||||
// Get characteristic handle for future use
|
||||
partialFlashCharacteristicHandle = partialFlashCharacteristic.getValueHandle();
|
||||
ble.gattServer().onDataWritten(this, &MicroBitPartialFlashingService::onDataWritten);
|
||||
|
||||
// Set up listener for SD writing
|
||||
messageBus.listen(MICROBIT_ID_PFLASH_NOTIFICATION, MICROBIT_EVT_ANY, this, &MicroBitPartialFlashingService::partialFlashingEvent);
|
||||
|
||||
// Set up Memory map
|
||||
// This will create the Memory Map and store it in flash
|
||||
MicroBitMemoryMap memoryMap;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback. Invoked when any of our attributes are written via BLE.
|
||||
*/
|
||||
void MicroBitPartialFlashingService::onDataWritten(const GattWriteCallbackParams *params)
|
||||
{
|
||||
// Get data from BLE callback params
|
||||
uint8_t *data = (uint8_t *)params->data;
|
||||
|
||||
if(params->handle == partialFlashCharacteristicHandle && params->len > 0)
|
||||
{
|
||||
// Switch CONTROL byte
|
||||
switch(data[0]){
|
||||
case REGION_INFO:
|
||||
{
|
||||
// Create instance of Memory Map to return info
|
||||
MicroBitMemoryMap memoryMap;
|
||||
|
||||
uint8_t buffer[18];
|
||||
// Response:
|
||||
// Region and Region #
|
||||
buffer[0] = 0x00;
|
||||
buffer[1] = data[1];
|
||||
|
||||
// Start Address
|
||||
buffer[2] = (memoryMap.memoryMapStore.memoryMap[data[1]].startAddress & 0xFF000000) >> 24;
|
||||
buffer[3] = (memoryMap.memoryMapStore.memoryMap[data[1]].startAddress & 0x00FF0000) >> 16;
|
||||
buffer[4] = (memoryMap.memoryMapStore.memoryMap[data[1]].startAddress & 0x0000FF00) >> 8;
|
||||
buffer[5] = (memoryMap.memoryMapStore.memoryMap[data[1]].startAddress & 0x000000FF);
|
||||
|
||||
// End Address
|
||||
buffer[6] = (memoryMap.memoryMapStore.memoryMap[data[1]].endAddress & 0xFF000000) >> 24;
|
||||
buffer[7] = (memoryMap.memoryMapStore.memoryMap[data[1]].endAddress & 0x00FF0000) >> 16;
|
||||
buffer[8] = (memoryMap.memoryMapStore.memoryMap[data[1]].endAddress & 0x0000FF00) >> 8;
|
||||
buffer[9] = (memoryMap.memoryMapStore.memoryMap[data[1]].endAddress & 0x000000FF);
|
||||
|
||||
// Region Hash
|
||||
for(int i = 0; i < 8; ++i)
|
||||
buffer[10+i] = memoryMap.memoryMapStore.memoryMap[data[1]].hash[i];
|
||||
|
||||
// Send BLE Notification
|
||||
ble.gattServer().notify(partialFlashCharacteristicHandle, (const uint8_t *)buffer, 18);
|
||||
|
||||
// Set offset for writing
|
||||
baseAddress = (memoryMap.memoryMapStore.memoryMap[data[1]].startAddress & 0xFFFF0000) >> 16; // Offsets are 16 bit
|
||||
|
||||
// Reset packet count
|
||||
packetCount = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
case FLASH_DATA:
|
||||
{
|
||||
// Process FLASH data packet
|
||||
flashData(data);
|
||||
break;
|
||||
}
|
||||
case END_OF_TRANSMISSION:
|
||||
{
|
||||
/* Start of embedded source isn't always on a page border so client must
|
||||
* inform the micro:bit that it's the last packet.
|
||||
* - Write final packet
|
||||
* The END_OF_TRANSMISSION packet contains no data. Write any data left in the buffer.
|
||||
*/
|
||||
MicroBitEvent evt(MICROBIT_ID_PFLASH_NOTIFICATION, END_OF_TRANSMISSION ,CREATE_AND_FIRE); break;
|
||||
}
|
||||
case MICROBIT_STATUS:
|
||||
{
|
||||
/*
|
||||
* Return the version of the Partial Flashing Service and the current BLE mode (application / pairing)
|
||||
*/
|
||||
uint8_t flashNotificationBuffer[] = {MICROBIT_STATUS, PARTIAL_FLASHING_VERSION, MicroBitBLEManager::manager->getBLEMode()};
|
||||
ble.gattServer().notify(partialFlashCharacteristicHandle, (const uint8_t *)flashNotificationBuffer, sizeof(flashNotificationBuffer));
|
||||
break;
|
||||
}
|
||||
case MICROBIT_RESET:
|
||||
{
|
||||
/*
|
||||
* data[1] determines which mode to reset into: MICROBIT_BLE_MODE_PAIRING or MICROBIT_BLE_MODE_APPLICATION
|
||||
*/
|
||||
switch(data[1]) {
|
||||
case MICROBIT_BLE_MODE_PAIRING:
|
||||
{
|
||||
MicroBitEvent evt(MICROBIT_ID_PFLASH_NOTIFICATION, MICROBIT_RESET ,CREATE_AND_FIRE);
|
||||
break;
|
||||
}
|
||||
case MICROBIT_BLE_MODE_APPLICATION:
|
||||
{
|
||||
microbit_reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param data - A pointer to the data to process
|
||||
*
|
||||
*/
|
||||
void MicroBitPartialFlashingService::flashData(uint8_t *data)
|
||||
{
|
||||
// Receive 16 bytes per packet
|
||||
// Buffer 8 packets - 32 uint32_t // 128 bytes per block
|
||||
// When buffer is full trigger partialFlashingEvent
|
||||
// When write is complete notify app and repeat
|
||||
// +-----------+---------+---------+----------+
|
||||
// | 1 Byte | 2 Bytes | 1 Byte | 16 Bytes |
|
||||
// +-----------+---------+---------+----------+
|
||||
// | COMMAND | OFFSET | PACKET# | DATA |
|
||||
// +-----------+---------+---------+----------+
|
||||
uint8_t packetNum = data[3];
|
||||
/**
|
||||
* Packets with packet num < packet count
|
||||
* Ignore as part of retransmitted block
|
||||
*/
|
||||
if(packetNum < packetCount)
|
||||
return;
|
||||
|
||||
/**
|
||||
* Check packet count
|
||||
* If the packet count doesn't match send a notification to the client
|
||||
* and set the packet count to the next block number
|
||||
*/
|
||||
if(packetNum != ++packetCount)
|
||||
{
|
||||
uint8_t flashNotificationBuffer[] = {FLASH_DATA, 0xAA};
|
||||
ble.gattServer().notify(partialFlashCharacteristicHandle, (const uint8_t *)flashNotificationBuffer, sizeof(flashNotificationBuffer));
|
||||
packetCount = blockPacketCount + 3;
|
||||
blockNum = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Add to block
|
||||
for(int x = 0; x < 4; x++)
|
||||
block[(4*blockNum) + x] = data[(4*x) + 4] | data[(4*x) + 5] << 8 | data[(4*x) + 6] << 16 | data[(4*x) + 7] << 24;
|
||||
|
||||
// Actions
|
||||
switch(blockNum) {
|
||||
// blockNum is 0, set up offset
|
||||
case 0:
|
||||
{
|
||||
offset = ((data[1] << 8) | data[2]);
|
||||
blockPacketCount = packetNum;
|
||||
blockNum++;
|
||||
break;
|
||||
}
|
||||
// blockNum is 7, block is full
|
||||
case 3:
|
||||
{
|
||||
// Fire write event
|
||||
MicroBitEvent evt(MICROBIT_ID_PFLASH_NOTIFICATION, FLASH_DATA ,CREATE_AND_FIRE);
|
||||
// Reset blockNum
|
||||
blockNum = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
blockNum++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write Event
|
||||
* Used the write data to the flash outside of the BLE ISR
|
||||
*/
|
||||
void MicroBitPartialFlashingService::partialFlashingEvent(MicroBitEvent e)
|
||||
{
|
||||
MicroBitFlash flash;
|
||||
|
||||
switch(e.value){
|
||||
case FLASH_DATA:
|
||||
{
|
||||
/*
|
||||
* Set BLE Mode flag if not already set to boot into BLE mode
|
||||
* upon a failed flash.
|
||||
*/
|
||||
MicroBitStorage storage;
|
||||
KeyValuePair* flashIncomplete = storage.get("flashIncomplete");
|
||||
if(flashIncomplete == NULL){
|
||||
uint8_t flashIncomplete = 0x01;
|
||||
storage.put("flashIncomplete", &flashIncomplete, sizeof(flashIncomplete));
|
||||
}
|
||||
|
||||
|
||||
// Flash Pointer
|
||||
uint32_t *flashPointer = (uint32_t *) ((baseAddress << 16) + offset);
|
||||
|
||||
// If the pointer is on a page boundary erase the page
|
||||
if(!((uint32_t)flashPointer % 0x400))
|
||||
flash.erase_page(flashPointer);
|
||||
|
||||
// Create a pointer to the data block
|
||||
uint32_t *blockPointer;
|
||||
blockPointer = block;
|
||||
|
||||
// Write to flash
|
||||
flash.flash_burn(flashPointer, blockPointer, 16);
|
||||
|
||||
// Update flash control buffer to send next packet
|
||||
uint8_t flashNotificationBuffer[] = {FLASH_DATA, 0xFF};
|
||||
ble.gattServer().notify(partialFlashCharacteristicHandle, (const uint8_t *)flashNotificationBuffer, sizeof(flashNotificationBuffer));
|
||||
break;
|
||||
}
|
||||
case END_OF_TRANSMISSION:
|
||||
{
|
||||
// Write one more packet over the next block: if source embed magic was not previously erased, it will be now!
|
||||
uint32_t *blockPointer;
|
||||
uint32_t *flashPointer = (uint32_t *) ((baseAddress << 16) + offset + 0x40);
|
||||
|
||||
blockPointer = block;
|
||||
flash.flash_burn(flashPointer, blockPointer, 16);
|
||||
|
||||
// Once the final packet has been written remove the BLE mode flag and reset
|
||||
// the micro:bit
|
||||
MicroBitStorage storage;
|
||||
storage.remove("flashIncomplete");
|
||||
delete &storage;
|
||||
microbit_reset();
|
||||
break;
|
||||
}
|
||||
case MICROBIT_RESET:
|
||||
{
|
||||
MicroBitBLEManager::manager->restartInBLEMode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const uint8_t MicroBitPartialFlashingServiceUUID[] = {
|
||||
0xe9,0x7d,0xd9,0x1d,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
||||
|
||||
const uint8_t MicroBitPartialFlashingServiceCharacteristicUUID[] = {
|
||||
0xe9,0x7d,0x3b,0x10,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
@ -0,0 +1,179 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 British Broadcasting Corporation.
|
||||
This software is provided by Lancaster University by arrangement with the BBC.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class definition for the MicroBitMemoryMap class.
|
||||
* This allows reading and writing of regions within the memory map.
|
||||
*
|
||||
* This class maps the different regions used on the flash memory to allow
|
||||
* a region to updated independently of the others AKA Partial Flashing.
|
||||
*/
|
||||
|
||||
#include "MicroBitConfig.h"
|
||||
#include "MicroBitMemoryMap.h"
|
||||
#include "MicroBitFlash.h"
|
||||
#include "MicroBitSerial.h"
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*
|
||||
* Creates an instance of MicroBitMemoryMap
|
||||
*/
|
||||
MicroBitMemoryMap::MicroBitMemoryMap()
|
||||
{
|
||||
// Assumes PXT Built program
|
||||
// SD
|
||||
pushRegion(Region(0x00, 0x00, 0x18000, 0x00)); // Soft Device
|
||||
|
||||
// DAL
|
||||
pushRegion(Region(0x01, 0x18000, FLASH_PROGRAM_END, 0x00)); // micro:bit Device Abstractation Layer
|
||||
|
||||
// PXT
|
||||
// PXT will be on the start of the next page
|
||||
// padding to next page = 0x400 - (FLASH_PROGRAM_END % 0x400);
|
||||
pushRegion(Region(0x02, FLASH_PROGRAM_END + (0x400 - (FLASH_PROGRAM_END % 0x400)), 0x3BBFF, 0x00)); // micro:bit PXT
|
||||
|
||||
// Find Hashes if PXT Built Program
|
||||
findHashes();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for adding a Region to the end of the MemoryMap
|
||||
*
|
||||
* @param region The Region to add to the MemoryMap
|
||||
*
|
||||
* @return MICROBIT_OK on success
|
||||
*
|
||||
*/
|
||||
int MicroBitMemoryMap::pushRegion(Region region)
|
||||
{
|
||||
|
||||
// Find next blank Region in map
|
||||
if(regionCount == NUMBER_OF_REGIONS){
|
||||
return MICROBIT_NO_DATA;
|
||||
} else {
|
||||
// Add data
|
||||
memoryMapStore.memoryMap[regionCount].startAddress = region.startAddress;
|
||||
memoryMapStore.memoryMap[regionCount].endAddress = region.endAddress;
|
||||
memcpy(&memoryMapStore.memoryMap[regionCount].hash, ®ion.hash, 8);
|
||||
memoryMapStore.memoryMap[regionCount].regionId = region.regionId;
|
||||
regionCount++;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for updating a Region of the MemoryMap
|
||||
*
|
||||
* @param region The Region to update in the MemoryMap. The name is used as the selector.
|
||||
*
|
||||
* @return MICROBIT_OK success, MICROBIT_NO_DATA if the region is not found
|
||||
*/
|
||||
int MicroBitMemoryMap::updateRegion(Region region)
|
||||
{
|
||||
// Find Region name in map
|
||||
int i = 0;
|
||||
while(memoryMapStore.memoryMap[i].regionId != region.regionId && i < NUMBER_OF_REGIONS) i++;
|
||||
|
||||
if(i == NUMBER_OF_REGIONS){
|
||||
return MICROBIT_NO_DATA;
|
||||
} else {
|
||||
// Add data
|
||||
memoryMapStore.memoryMap[i] = region;
|
||||
updateFlash(&memoryMapStore);
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to update the flash with the current MemoryMapStore
|
||||
*
|
||||
* @param memoryMapStore The memory map to write to flash
|
||||
*/
|
||||
void MicroBitMemoryMap::updateFlash(MemoryMapStore *store)
|
||||
{
|
||||
MicroBitFlash flash;
|
||||
flash.flash_write((uint32_t *)MEMORY_MAP_PAGE, store, (sizeof(MemoryMapStore) / 4));
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to fetch the hashes from a PXT generated build
|
||||
*/
|
||||
void MicroBitMemoryMap::findHashes()
|
||||
{
|
||||
// Iterate through pages to find magic
|
||||
for(int x = 0; x < NRF_FICR->CODESIZE - 1; x++)
|
||||
{
|
||||
|
||||
uint32_t volatile *magicAddress = (uint32_t *)(0x400 * x);
|
||||
|
||||
// Check for first 32 bits of Magic
|
||||
if(*magicAddress == 0x923b8e70)
|
||||
{
|
||||
// Check remaining magic
|
||||
if(
|
||||
*(uint32_t *)(magicAddress + 0x1) == 0x41A815C6 &&
|
||||
*(uint32_t *)(magicAddress + 0x2) == 0xC96698C4 &&
|
||||
*(uint32_t *)(magicAddress + 0x3) == 0x9751EE75
|
||||
)
|
||||
{
|
||||
// If the magic has been found use the hashes follow
|
||||
magicAddress = (uint32_t *)(magicAddress + 0x4);
|
||||
|
||||
memoryMapStore.memoryMap[1].hash[0] = (*magicAddress & 0xFF);
|
||||
memoryMapStore.memoryMap[1].hash[1] = (*magicAddress & 0xFF00) >> 8;
|
||||
memoryMapStore.memoryMap[1].hash[2] = (*magicAddress & 0xFF0000) >> 16;
|
||||
memoryMapStore.memoryMap[1].hash[3] = (*magicAddress & 0xFF000000) >> 24;
|
||||
|
||||
magicAddress = (uint32_t *)(magicAddress + 0x1);
|
||||
|
||||
memoryMapStore.memoryMap[1].hash[4] = (*magicAddress & 0xFF);
|
||||
memoryMapStore.memoryMap[1].hash[5] = (*magicAddress & 0xFF00) >> 8;
|
||||
memoryMapStore.memoryMap[1].hash[6] = (*magicAddress & 0xFF0000) >> 16;
|
||||
memoryMapStore.memoryMap[1].hash[7] = (*magicAddress & 0xFF000000) >> 24;
|
||||
|
||||
magicAddress = (uint32_t *)(magicAddress + 0x1);
|
||||
|
||||
memoryMapStore.memoryMap[2].hash[0] = (*magicAddress & 0xFF);
|
||||
memoryMapStore.memoryMap[2].hash[1] = (*magicAddress & 0xFF00) >> 8;
|
||||
memoryMapStore.memoryMap[2].hash[2] = (*magicAddress & 0xFF0000) >> 16;
|
||||
memoryMapStore.memoryMap[2].hash[3] = (*magicAddress & 0xFF000000) >> 24;
|
||||
|
||||
magicAddress = (uint32_t *)(magicAddress + 0x1);
|
||||
|
||||
memoryMapStore.memoryMap[2].hash[4] = (*magicAddress & 0xFF);
|
||||
memoryMapStore.memoryMap[2].hash[5] = (*magicAddress & 0xFF00) >> 8;
|
||||
memoryMapStore.memoryMap[2].hash[6] = (*magicAddress & 0xFF0000) >> 16;
|
||||
memoryMapStore.memoryMap[2].hash[7] = (*magicAddress & 0xFF000000) >> 24;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in new issue