From 040f63b01f0b5c3ad782275a910682d15e04f47c Mon Sep 17 00:00:00 2001 From: Sam Kent <32453267+microbit-sam@users.noreply.github.com> Date: Mon, 4 Jun 2018 16:13:20 +0100 Subject: [PATCH] Changes from code review with Joe F (#10) * Movd MICROBIT_MODE_* defines to MicroBitConfig.h * Search for embedded source and remove magic * Fixed memcpy * Change offset order * Fixed memcpy for data --- inc/bluetooth/MicroBitBLEManager.h | 19 +- .../MicroBitPartialFlashingService.h | 17 +- inc/core/MicroBitComponent.h | 3 +- inc/core/MicroBitConfig.h | 16 +- inc/drivers/MicroBitFlash.h | 16 +- inc/drivers/MicroBitMemoryMap.h | 19 +- module.json | 2 +- source/asm/CortexContextSwitch.s | 293 ------------------ source/bluetooth/MicroBitBLEManager.cpp | 43 ++- .../MicroBitPartialFlashingService.cpp | 104 ++++--- source/drivers/MicroBitFlash.cpp | 47 ++- source/drivers/MicroBitMemoryMap.cpp | 69 +---- 12 files changed, 161 insertions(+), 487 deletions(-) delete mode 100644 source/asm/CortexContextSwitch.s diff --git a/inc/bluetooth/MicroBitBLEManager.h b/inc/bluetooth/MicroBitBLEManager.h index c90a9d2b..f1f0485c 100644 --- a/inc/bluetooth/MicroBitBLEManager.h +++ b/inc/bluetooth/MicroBitBLEManager.h @@ -79,9 +79,6 @@ DEALINGS IN THE SOFTWARE. #define MICROBIT_BLE_STATUS_STORE_SYSATTR 0x02 #define MICROBIT_BLE_STATUS_DISCONNECT 0x04 -#define MICROBIT_BLE_MODE_PAIRING 0x00 -#define MICROBIT_BLE_MODE_APPLICATION 0x01 - extern const int8_t MICROBIT_BLE_POWER_LEVEL[]; struct BLESysAttribute @@ -150,7 +147,7 @@ class MicroBitBLEManager : MicroBitComponent * @param enableBonding If true, the security manager enabled bonding. * * @code - * bleManager.init(uBit.getName(), uBit.getSerial(), uBit.messageBus); + * bleManager.init(uBit.getName(), uBit.getSerial(), uBit.messageBus, true); * @endcode */ void init(ManagedString deviceName, ManagedString serialNumber, EventModel &messageBus, bool enableBonding); @@ -293,10 +290,10 @@ class MicroBitBLEManager : MicroBitComponent /** * Get current BLE mode; application, pairing - * #define MICROBIT_BLE_MODE_PAIRING 0x00 - * #define MICROBIT_BLE_MODE_APPLICATION 0x01 + * #define MICROBIT_MODE_PAIRING 0x00 + * #define MICROBIT_MODE_APPLICATION 0x01 */ - uint8_t getBLEMode(); + uint8_t getCurrentMode(); private: /** @@ -320,7 +317,13 @@ class MicroBitBLEManager : MicroBitComponent int pairingStatus; ManagedString passKey; ManagedString deviceName; - uint8_t bleMode = MICROBIT_BLE_MODE_APPLICATION; + + /* + * Default to Application Mode + * This variable will be set to MICROBIT_MODE_PAIRING if pairingMode() is executed. + */ + uint8_t currentMode = MICROBIT_MODE_APPLICATION; + }; #endif diff --git a/inc/bluetooth/MicroBitPartialFlashingService.h b/inc/bluetooth/MicroBitPartialFlashingService.h index b714e562..64a1d5bb 100644 --- a/inc/bluetooth/MicroBitPartialFlashingService.h +++ b/inc/bluetooth/MicroBitPartialFlashingService.h @@ -1,8 +1,7 @@ /* The MIT License (MIT) -Copyright (c) 2016 British Broadcasting Corporation. -This software is provided by Lancaster University by arrangement with the BBC. +This class has been written by Sam Kent for the Microbit Educational Foundation. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -41,6 +40,15 @@ DEALINGS IN THE SOFTWARE. #define PARTIAL_FLASHING_VERSION 0x01 +// 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 + // UUIDs for our service and characteristics extern const uint8_t MicroBitPartialFlashingServiceUUID[]; extern const uint8_t MicroBitPartialFlashingServiceCharacteristicUUID[]; @@ -80,9 +88,6 @@ class MicroBitPartialFlashingService */ 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; @@ -98,7 +103,7 @@ class MicroBitPartialFlashingService // Keep track of blocks of data uint32_t block[16]; uint8_t blockNum = 0; - uint16_t offset = 0; + uint32_t offset = 0; }; diff --git a/inc/core/MicroBitComponent.h b/inc/core/MicroBitComponent.h index 8af4c1c6..c9436474 100644 --- a/inc/core/MicroBitComponent.h +++ b/inc/core/MicroBitComponent.h @@ -68,8 +68,7 @@ DEALINGS IN THE SOFTWARE. #define MICROBIT_ID_MULTIBUTTON_ATTACH 31 #define MICROBIT_ID_SERIAL 32 -#define MICROBIT_ID_PFLASH_NOTIFICATION 33 -#define MICROBIT_ID_PAIRING_MODE 34 +#define MICROBIT_ID_PARTIAL_FLASHING 33 #define MICROBIT_ID_MESSAGE_BUS_LISTENER 1021 // Message bus indication that a handler for a given ID has been registered. #define MICROBIT_ID_NOTIFY_ONE 1022 // Notfication channel, for general purpose synchronisation diff --git a/inc/core/MicroBitConfig.h b/inc/core/MicroBitConfig.h index a395d5a9..60b99efa 100644 --- a/inc/core/MicroBitConfig.h +++ b/inc/core/MicroBitConfig.h @@ -86,14 +86,9 @@ DEALINGS IN THE SOFTWARE. #define BLE_BOND_DATA_PAGE (PAGE_SIZE * (NRF_FICR->CODESIZE - 18)) #endif -#ifndef MEMORY_MAP_PAGE -#define MEMORY_MAP_PAGE (PAGE_SIZE * (NRF_FICR->CODESIZE - 19)) -#endif - -// Scratch moved from page 19 to page 20 // MicroBitFileSystem uses DEFAULT_SCRATCH_PAGE to mark end of FileSystem #ifndef DEFAULT_SCRATCH_PAGE -#define DEFAULT_SCRATCH_PAGE (PAGE_SIZE * (NRF_FICR->CODESIZE - 20)) +#define DEFAULT_SCRATCH_PAGE (PAGE_SIZE * (NRF_FICR->CODESIZE - 19)) #endif // Address of the end of the current program in FLASH memory. @@ -441,6 +436,15 @@ extern uint32_t __etext; #define MICROBIT_DAL_VERSION "unknown" #endif +// micro:bit Modes +// The micro:bit may be in different states: running a user's application or into BLE pairing mode +// These modes can be representeded using these #defines +#ifndef MICROBIT_MODE_PAIRING +#define MICROBIT_MODE_PAIRING 0 +#endif +#ifndef MICROBIT_MODE_APPLICATION +#define MICROBIT_MODE_APPLICATION 1 +#endif // // Helper macro used by the micro:bit runtime to determine if a boolean configuration option is set. diff --git a/inc/drivers/MicroBitFlash.h b/inc/drivers/MicroBitFlash.h index 187a3f1d..0b04b959 100644 --- a/inc/drivers/MicroBitFlash.h +++ b/inc/drivers/MicroBitFlash.h @@ -42,7 +42,7 @@ class MicroBitFlash * @return non-zero if erase required, zero otherwise. */ int need_erase(uint8_t* source, uint8_t* flash_addr, int len); - + public: /** * Default constructor. @@ -53,12 +53,12 @@ class MicroBitFlash * Writes the given number of bytes to the address in flash specified. * Neither address nor buffer need be word-aligned. * @param address location in flash to write to. - * @param buffer location in memory to write from. + * @param buffer location in memory to write from. * @length number of bytes to burn - * @param scratch_addr if specified, scratch page to use. Use default + * @param scratch_addr if specified, scratch page to use. Use default * otherwise. * @return non-zero on sucess, zero on error. - * + * * Example: * @code * MicroBitFlash flash(); @@ -66,20 +66,20 @@ class MicroBitFlash * flash.flash_write((uint8_t*)0x38000, &word, sizeof(word)) * @endcode */ - int flash_write(void* address, void* buffer, int length, + int flash_write(void* address, void* buffer, int length, void* scratch_addr = NULL); /** * Erase an entire page. * @param page_address address of first word of page. */ - uint8_t erase_page(uint32_t* page_address); + void erase_page(uint32_t* page_address); /** * Write to flash memory, assuming that a write is valid * (using need_erase). - * - * @param page_address address of memory to write to. + * + * @param page_address address of memory to write to. * Must be word aligned. * @param buffer address to write from, must be word-aligned. * @param len number of uint32_t words to write. diff --git a/inc/drivers/MicroBitMemoryMap.h b/inc/drivers/MicroBitMemoryMap.h index 7bc3b2c2..6494c85c 100644 --- a/inc/drivers/MicroBitMemoryMap.h +++ b/inc/drivers/MicroBitMemoryMap.h @@ -1,8 +1,7 @@ /* The MIT License (MIT) -Copyright (c) 2016 British Broadcasting Corporation. -This software is provided by Lancaster University by arrangement with the BBC. +This class has been written by Sam Kent for the Microbit Educational Foundation. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -31,8 +30,6 @@ DEALINGS IN THE SOFTWARE. #include "ManagedString.h" #include "ErrorNo.h" -#define MICROBIT_MEMORY_MAP_MAGIC 0xCA8E - #define NUMBER_OF_REGIONS 3 /** @@ -56,32 +53,25 @@ class MicroBitMemoryMap this->regionId = regionId; this->startAddress = startAddress; this->endAddress = endAddress; - memmove( this->hash, &hash, 8 ); + memcpy( this->hash, hash, 8 ); } Region(){ this->regionId = 0x0; this->startAddress = 0x0; this->endAddress = 0x0; - memset( this->hash, 0xDD, 8 ); + memset( this->hash, 0x00, 8 ); } }; struct MemoryMapStore { - Region memoryMap[3]; + Region memoryMap[NUMBER_OF_REGIONS]; }; 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; @@ -115,7 +105,6 @@ class MicroBitMemoryMap /** * Function to fetch hashes from PXT build * - * @return int Boolean result of the search. 1 = Hashes Found; 0 = No Hash Found */ void findHashes(); }; diff --git a/module.json b/module.json index 2ac2befc..adf834cc 100644 --- a/module.json +++ b/module.json @@ -1,6 +1,6 @@ { "name": "microbit-dal", - "version": "2.0.0-pf", + "version": "2.0.0-rc9", "license": "MIT", "description": "The runtime library for the BBC micro:bit, developed by Lancaster University", "keywords": [ diff --git a/source/asm/CortexContextSwitch.s b/source/asm/CortexContextSwitch.s deleted file mode 100644 index bd7deecc..00000000 --- a/source/asm/CortexContextSwitch.s +++ /dev/null @@ -1,293 +0,0 @@ -; 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. - - AREA asm_func, CODE, READONLY - -; Export our context switching subroutine as a C function for use in mbed - EXPORT swap_context - EXPORT save_context - EXPORT save_register_context - EXPORT restore_register_context - - ALIGN - -; R0 Contains a pointer to the TCB of the fibre being scheduled out. -; R1 Contains a pointer to the TCB of the fibre being scheduled in. -; R2 Contains a pointer to the base of the stack of the fibre being scheduled out. -; R3 Contains a pointer to the base of the stack of the fibre being scheduled in. - -swap_context - - ; Write our core registers into the TCB - ; First, store the general registers - - ; Skip this is we're given a NULL parameter for the TCB - CMP R0, #0 - BEQ store_context_complete - - STR R0, [R0,#0] - STR R1, [R0,#4] - STR R2, [R0,#8] - STR R3, [R0,#12] - STR R4, [R0,#16] - STR R5, [R0,#20] - STR R6, [R0,#24] - STR R7, [R0,#28] - - ; Now the high general purpose registers - MOV R4, R8 - STR R4, [R0,#32] - MOV R4, R9 - STR R4, [R0,#36] - MOV R4, R10 - STR R4, [R0,#40] - MOV R4, R11 - STR R4, [R0,#44] - MOV R4, R12 - STR R4, [R0,#48] - - ; Now the Stack and Link Register. - ; As this context is only intended for use with a fiber scheduler, - ; we don't need the PC. - MOV R6, SP - STR R6, [R0,#52] - MOV R4, LR - STR R4, [R0,#56] - -store_context_complete - ; Finally, Copy the stack. We do this to reduce RAM footprint, as stack is usually very small at the point - ; of scheduling, but we need a lot of capacity for interrupt handling and other functions. - - ; Skip this is we're given a NULL parameter for the stack. - CMP R2, #0 - BEQ store_stack_complete - - LDR R4, [R0,#60] ; Load R4 with the fiber's defined stack_base. -store_stack - SUBS R4, #4 - SUBS R2, #4 - - LDR R5, [R4] - STR R5, [R2] - - CMP R4, R6 - BNE store_stack - -store_stack_complete - - ; - ; Now page in the new context. - ; Update all registers except the PC. We can also safely ignore the STATUS register, as we're just a fiber scheduler. - ; - LDR R4, [R1, #56] - MOV LR, R4 - LDR R6, [R1, #52] - MOV SP, R6 - - ; Copy the stack in. - ; n.b. we do this after setting the SP to make comparisons easier. - - ; Skip this is we're given a NULL parameter for the stack. - CMP R3, #0 - BEQ restore_stack_complete - - LDR R4, [R1,#60] ; Load R4 with the fiber's defined stack_base. - -restore_stack - SUBS R4, #4 - SUBS R3, #4 - - LDR R5, [R3] - STR R5, [R4] - - CMP R4, R6 - BNE restore_stack - -restore_stack_complete - LDR R4, [R1, #48] - MOV R12, R4 - LDR R4, [R1, #44] - MOV R11, R4 - LDR R4, [R1, #40] - MOV R10, R4 - LDR R4, [R1, #36] - MOV R9, R4 - LDR R4, [R1, #32] - MOV R8, R4 - - LDR R7, [R1, #28] - LDR R6, [R1, #24] - LDR R5, [R1, #20] - LDR R4, [R1, #16] - LDR R3, [R1, #12] - LDR R2, [R1, #8] - LDR R0, [R1, #0] - LDR R1, [R1, #4] - - ; Return to caller (scheduler). - BX LR - - -; R0 Contains a pointer to the TCB of the fibre to snapshot -; R1 Contains a pointer to the base of the stack of the fibre being snapshotted - -save_context - - ; Write our core registers into the TCB - ; First, store the general registers - - STR R0, [R0,#0] - STR R1, [R0,#4] - STR R2, [R0,#8] - STR R3, [R0,#12] - STR R4, [R0,#16] - STR R5, [R0,#20] - STR R6, [R0,#24] - STR R7, [R0,#28] - - ; Now the high general purpose registers - MOV R4, R8 - STR R4, [R0,#32] - MOV R4, R9 - STR R4, [R0,#36] - MOV R4, R10 - STR R4, [R0,#40] - MOV R4, R11 - STR R4, [R0,#44] - MOV R4, R12 - STR R4, [R0,#48] - - ; Now the Stack and Link Register. - ; As this context is only intended for use with a fiber scheduler, - ; we don't need the PC. - MOV R6, SP - STR R6, [R0,#52] - MOV R4, LR - STR R4, [R0,#56] - - ; Finally, Copy the stack. We do this to reduce RAM footprint, as stackis usually very small at the point - ; of sceduling, but we need a lot of capacity for interrupt handling and other functions. - - LDR R4, [R0,#60] ; Load R4 with the fiber's defined stack_base. - -store_stack1 - SUBS R4, #4 - SUBS R1, #4 - - LDR R5, [R4] - STR R5, [R1] - - CMP R4, R6 - BNE store_stack1 - - ; Restore scratch registers. - - LDR R7, [R0, #28] - LDR R6, [R0, #24] - LDR R5, [R0, #20] - LDR R4, [R0, #16] - - ; Return to caller (scheduler). - BX LR - - -; R0 Contains a pointer to the TCB of the fiber to snapshot -save_register_context - - ; Write our core registers into the TCB - ; First, store the general registers - - STR R0, [R0,#0] - STR R1, [R0,#4] - STR R2, [R0,#8] - STR R3, [R0,#12] - STR R4, [R0,#16] - STR R5, [R0,#20] - STR R6, [R0,#24] - STR R7, [R0,#28] - - ; Now the high general purpose registers - MOV R4, R8 - STR R4, [R0,#32] - MOV R4, R9 - STR R4, [R0,#36] - MOV R4, R10 - STR R4, [R0,#40] - MOV R4, R11 - STR R4, [R0,#44] - MOV R4, R12 - STR R4, [R0,#48] - - ; Now the Stack Pointer and Link Register. - ; As this context is only intended for use with a fiber scheduler, - ; we don't need the PC. - MOV R4, SP - STR R4, [R0,#52] - MOV R4, LR - STR R4, [R0,#56] - - ; Restore scratch registers. - LDR R4, [R0, #16] - - ; Return to caller (scheduler). - BX LR - - -restore_register_context - - ; - ; Now page in the new context. - ; Update all registers except the PC. We can also safely ignore the STATUS register, as we're just a fiber scheduler. - ; - LDR R4, [R0, #56] - MOV LR, R4 - LDR R4, [R0, #52] - MOV SP, R4 - - ; High registers... - LDR R4, [R0, #48] - MOV R12, R4 - LDR R4, [R0, #44] - MOV R11, R4 - LDR R4, [R0, #40] - MOV R10, R4 - LDR R4, [R0, #36] - MOV R9, R4 - LDR R4, [R0, #32] - MOV R8, R4 - - ; Low registers... - LDR R7, [R0, #28] - LDR R6, [R0, #24] - LDR R5, [R0, #20] - LDR R4, [R0, #16] - LDR R3, [R0, #12] - LDR R2, [R0, #8] - LDR R0, [R0, #0] - LDR R1, [R0, #4] - - ; Return to caller (normally the scheduler). - BX LR - - ALIGN - END diff --git a/source/bluetooth/MicroBitBLEManager.cpp b/source/bluetooth/MicroBitBLEManager.cpp index c1d31fac..9e65dd7e 100644 --- a/source/bluetooth/MicroBitBLEManager.cpp +++ b/source/bluetooth/MicroBitBLEManager.cpp @@ -642,13 +642,11 @@ void MicroBitBLEManager::pairingMode(MicroBitDisplay &display, MicroBitButton &a ManagedString namePostfix("]"); ManagedString BLEName = namePrefix + deviceName + namePostfix; - ManagedString msg("M M!"); - int timeInPairingMode = 0; int brightness = 255; int fadeDirection = 0; - bleMode = MICROBIT_BLE_MODE_PAIRING; + currentMode = MICROBIT_MODE_PAIRING; ble->gap().stopAdvertising(); @@ -677,9 +675,6 @@ void MicroBitBLEManager::pairingMode(MicroBitDisplay &display, MicroBitButton &a // Stop any running animations on the display display.stopAnimation(); - // Replaced by animation TODO remove - //display.scroll(msg); - fiber_add_idle_component(this); showManagementModeAnimation(display); @@ -786,11 +781,11 @@ void MicroBitBLEManager::showManagementModeAnimation(MicroBitDisplay &display) const int mgmt_animation_h = 5; const uint8_t mgmt_animation[] = { - 1,1,1,1,1, 1,1,1,1,1, 1,1,0,1,1, 1,0,0,0,1, - 1,1,1,1,1, 1,1,0,1,1, 1,0,0,0,1, 0,0,0,0,0, - 1,1,0,1,1, 1,0,0,0,1, 0,0,0,0,0, 0,0,0,0,0, - 1,1,1,1,1, 1,1,0,1,1, 1,0,0,0,1, 0,0,0,0,0, - 1,1,1,1,1, 1,1,1,1,1, 1,1,0,1,1, 1,0,0,0,1 + 255,255,255,255,255, 255,255,255,255,255, 255,255, 0,255,255, 255, 0, 0, 0,255, + 255,255,255,255,255, 255,255, 0,255,255, 255, 0, 0, 0,255, 0, 0, 0, 0, 0, + 255,255, 0,255,255, 255, 0, 0, 0,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 255,255,255,255,255, 255,255, 0,255,255, 255, 0, 0, 0,255, 0, 0, 0, 0, 0, + 255,255,255,255,255, 255,255,255,255,255, 255,255, 0,255,255, 255, 0, 0, 0,255 }; MicroBitImage mgmt(mgmt_animation_w,mgmt_animation_h,mgmt_animation); @@ -798,11 +793,11 @@ void MicroBitBLEManager::showManagementModeAnimation(MicroBitDisplay &display) const uint8_t bt_icon_raw[] = { - 255,255,255,0 ,255, - 255,0 ,255,255,0 , - 255,255,255,0 ,0 , - 255,0 ,255,255,0 , - 255,255,255,0 ,255 + 255,255,255, 0,255, + 255, 0,255,255, 0, + 255,255,255, 0, 0, + 255, 0,255,255, 0, + 255,255,255, 0,255 }; MicroBitImage bt_icon(5,5,bt_icon_raw); @@ -843,15 +838,15 @@ void MicroBitBLEManager::showNameHistogram(MicroBitDisplay &display) } /** - * Restarts in BLE Mode + * Restarts into BLE Mode * */ void MicroBitBLEManager::restartInBLEMode(){ - KeyValuePair* BLEMode = storage->get("BLEMode"); - if(BLEMode == NULL){ - uint8_t BLEMode = 0x01; - storage->put("BLEMode", &BLEMode, sizeof(BLEMode)); - delete &BLEMode; + KeyValuePair* RebootMode = storage->get("RebootMode"); + if(RebootMode == NULL){ + uint8_t RebootModeValue = MICROBIT_MODE_PAIRING; + storage->put("RebootMode", &RebootModeValue, sizeof(RebootMode)); + delete RebootMode; } microbit_reset(); } @@ -859,6 +854,6 @@ void MicroBitBLEManager::showNameHistogram(MicroBitDisplay &display) /** * Get BLE mode. Returns the current mode: application, pairing mode */ -uint8_t MicroBitBLEManager::getBLEMode(){ - return bleMode; +uint8_t MicroBitBLEManager::getCurrentMode(){ + return currentMode; } diff --git a/source/bluetooth/MicroBitPartialFlashingService.cpp b/source/bluetooth/MicroBitPartialFlashingService.cpp index a20d8451..223b4796 100644 --- a/source/bluetooth/MicroBitPartialFlashingService.cpp +++ b/source/bluetooth/MicroBitPartialFlashingService.cpp @@ -32,15 +32,6 @@ DEALINGS IN THE SOFTWARE. #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 @@ -68,11 +59,7 @@ MicroBitPartialFlashingService::MicroBitPartialFlashingService(BLEDevice &_ble, 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; + messageBus.listen(MICROBIT_ID_PARTIAL_FLASHING, MICROBIT_EVT_ANY, this, &MicroBitPartialFlashingService::partialFlashingEvent); } @@ -113,17 +100,16 @@ void MicroBitPartialFlashingService::onDataWritten(const GattWriteCallbackParams 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]; + memcpy(&buffer[10], &memoryMap.memoryMapStore.memoryMap[data[1]].hash, 8); // 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; + blockPacketCount = 0; + blockNum = 0; + offset = 0; break; } @@ -140,29 +126,30 @@ void MicroBitPartialFlashingService::onDataWritten(const GattWriteCallbackParams * - 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; + MicroBitEvent evt(MICROBIT_ID_PARTIAL_FLASHING, END_OF_TRANSMISSION); + 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()}; + uint8_t flashNotificationBuffer[] = {MICROBIT_STATUS, PARTIAL_FLASHING_VERSION, MicroBitBLEManager::manager->getCurrentMode()}; 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 + * data[1] determines which mode to reset into: MICROBIT_MODE_PAIRING or MICROBIT_MODE_APPLICATION */ switch(data[1]) { - case MICROBIT_BLE_MODE_PAIRING: + case MICROBIT_MODE_PAIRING: { - MicroBitEvent evt(MICROBIT_ID_PFLASH_NOTIFICATION, MICROBIT_RESET ,CREATE_AND_FIRE); + MicroBitEvent evt(MICROBIT_ID_PARTIAL_FLASHING, MICROBIT_RESET ); break; } - case MICROBIT_BLE_MODE_APPLICATION: + case MICROBIT_MODE_APPLICATION: { microbit_reset(); break; @@ -183,7 +170,7 @@ void MicroBitPartialFlashingService::onDataWritten(const GattWriteCallbackParams void MicroBitPartialFlashingService::flashData(uint8_t *data) { // Receive 16 bytes per packet - // Buffer 8 packets - 32 uint32_t // 128 bytes per block + // Buffer 4 packets // When buffer is full trigger partialFlashingEvent // When write is complete notify app and repeat // +-----------+---------+---------+----------+ @@ -214,24 +201,40 @@ void MicroBitPartialFlashingService::flashData(uint8_t *data) } // 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; + // Something dodgy going on here! + // memcpy(block + (blockNum * 16), data + 4, 16); + memcpy(block + (4*blockNum), data + 4, 16); + + + /* + block[(4*blockNum) + 0] = data[ 4] | data[ 5] << 8 | data[ 6] << 16 | data[ 7] << 24; + block[(4*blockNum) + 1] = data[ 8] | data[ 9] << 8 | data[10] << 16 | data[11] << 24; + block[(4*blockNum) + 2] = data[12] | data[13] << 8 | data[14] << 16 | data[15] << 24; + block[(4*blockNum) + 3] = data[16] | data[17] << 8 | data[18] << 16 | data[19] << 24; + */ // Actions switch(blockNum) { - // blockNum is 0, set up offset + // blockNum is 0: set up offset case 0: { - offset = ((data[1] << 8) | data[2]); + offset = ((data[1] << 8) | data[2] << 0); blockPacketCount = packetNum; blockNum++; break; } - // blockNum is 7, block is full + // blockNum is 1: complete the offset + case 1: + { + offset |= ((data[1] << 24) | data[2] << 16); + blockNum++; + break; + } + // blockNum is 3, block is full case 3: { // Fire write event - MicroBitEvent evt(MICROBIT_ID_PFLASH_NOTIFICATION, FLASH_DATA ,CREATE_AND_FIRE); + MicroBitEvent evt(MICROBIT_ID_PARTIAL_FLASHING, FLASH_DATA ); // Reset blockNum blockNum = 0; break; @@ -242,6 +245,7 @@ void MicroBitPartialFlashingService::flashData(uint8_t *data) break; } } + } @@ -257,19 +261,18 @@ void MicroBitPartialFlashingService::partialFlashingEvent(MicroBitEvent e) case FLASH_DATA: { /* - * Set BLE Mode flag if not already set to boot into BLE mode + * Set flashIncomplete 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)); + uint8_t flashIncompleteVal = 0x01; + storage.put("flashIncomplete", &flashIncompleteVal, sizeof(flashIncompleteVal)); } + delete flashIncomplete; - - // Flash Pointer - uint32_t *flashPointer = (uint32_t *) ((baseAddress << 16) + offset); + uint32_t *flashPointer = (uint32_t *)(offset); // If the pointer is on a page boundary erase the page if(!((uint32_t)flashPointer % 0x400)) @@ -289,18 +292,37 @@ void MicroBitPartialFlashingService::partialFlashingEvent(MicroBitEvent e) } case END_OF_TRANSMISSION: { - // Write one more packet over the next block: if source embed magic was not previously erased, it will be now! + // Write final packet uint32_t *blockPointer; - uint32_t *flashPointer = (uint32_t *) ((baseAddress << 16) + offset + 0x40); + uint32_t *flashPointer = (uint32_t *) offset; blockPointer = block; flash.flash_burn(flashPointer, blockPointer, 16); + // Search for and remove embedded source magic (if it exists!) + // Move to next page + flashPointer = flashPointer + 0x400; + + // Iterate through until reaching the scratch page + while(flashPointer < (uint32_t *)DEFAULT_SCRATCH_PAGE) + { + // Check for embedded source magic + if(*flashPointer == 0x41140EF && *(uint32_t *)(flashPointer + 0x1) == 0xB82FA2BB) + { + // Embedded Source Found! + uint8_t blank = 0x00; + flash.flash_write(flashPointer, &blank, sizeof(blank)); + } + + // Next 16 byte alignment + flashPointer = flashPointer + 0x2; + } + + // 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; } diff --git a/source/drivers/MicroBitFlash.cpp b/source/drivers/MicroBitFlash.cpp index d6b93088..fff1354c 100644 --- a/source/drivers/MicroBitFlash.cpp +++ b/source/drivers/MicroBitFlash.cpp @@ -55,13 +55,6 @@ extern "C" void btle_set_user_evt_handler(void (*func)(uint32_t)); static bool evt_handler_registered = false; static volatile bool flash_op_complete = false; -/* - * static void SWI1_IRQHandler(uint32_t evt) -{ - flash_op_complete = true; -} -*/ - static void nvmc_event_handler(uint32_t evt) { if(evt == NRF_EVT_FLASH_OPERATION_SUCCESS) @@ -71,7 +64,7 @@ static void nvmc_event_handler(uint32_t evt) /** * Default Constructor */ -MicroBitFlash::MicroBitFlash() +MicroBitFlash::MicroBitFlash() { if (!evt_handler_registered) { @@ -91,13 +84,13 @@ MicroBitFlash::MicroBitFlash() * @param len number of uint8_t to check. * @return non-zero if erase required, zero otherwise. */ -int MicroBitFlash::need_erase(uint8_t* source, uint8_t* flash_addr, int len) +int MicroBitFlash::need_erase(uint8_t* source, uint8_t* flash_addr, int len) { // Erase is necessary if for any byte: // O & ~N != 0 // Where O = original, and N = new byte. - for(;len>0;len--) + for(;len>0;len--) { if((~*(flash_addr++) & *(source++)) != 0x00) return 1; } @@ -108,19 +101,16 @@ int MicroBitFlash::need_erase(uint8_t* source, uint8_t* flash_addr, int len) * Erase an entire page * @param page_address address of first word of page */ -uint8_t MicroBitFlash::erase_page(uint32_t* pg_addr) +void MicroBitFlash::erase_page(uint32_t* pg_addr) { if (ble_running()) { flash_op_complete = false; while(1) { - uint8_t ret = sd_flash_page_erase(((uint32_t)pg_addr)/PAGE_SIZE); - if (ret == NRF_SUCCESS) { + if (sd_flash_page_erase(((uint32_t)pg_addr)/PAGE_SIZE) == NRF_SUCCESS) break; - } else { - return ret; - } + wait_ms(10); } @@ -142,7 +132,7 @@ uint8_t MicroBitFlash::erase_page(uint32_t* pg_addr) while (NRF_NVMC->READY == NVMC_READY_READY_Busy) { } } } - + /** * Write to flash memory, assuming that a write is valid * (using need_erase). @@ -152,8 +142,8 @@ uint8_t MicroBitFlash::erase_page(uint32_t* pg_addr) * @param buffer address to write from, must be word-aligned. * @param len number of uint32_t words to write. */ -void MicroBitFlash::flash_burn(uint32_t* addr, uint32_t* buffer, int size) -{ +void MicroBitFlash::flash_burn(uint32_t* addr, uint32_t* buffer, int size) +{ if (ble_running()) { // Schedule SoftDevice to write this memory for us, and wait for it to complete. @@ -177,7 +167,7 @@ void MicroBitFlash::flash_burn(uint32_t* addr, uint32_t* buffer, int size) NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos); while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {}; - for(int i=0;iREADY == NVMC_READY_READY_Busy) {}; @@ -188,7 +178,7 @@ void MicroBitFlash::flash_burn(uint32_t* addr, uint32_t* buffer, int size) while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {}; } } - + /** * Writes the given number of bytes to the address in flash specified. * Neither address nor buffer need be word-aligned. @@ -206,7 +196,7 @@ void MicroBitFlash::flash_burn(uint32_t* addr, uint32_t* buffer, int size) * flash.flash_write((uint8_t*)0x38000, &word, sizeof(word)) * @endcode */ -int MicroBitFlash::flash_write(void* address, void* from_buffer, +int MicroBitFlash::flash_write(void* address, void* from_buffer, int length, void* scratch_addr) { // If no scratch_addr has been supplied use the default @@ -215,7 +205,7 @@ int MicroBitFlash::flash_write(void* address, void* from_buffer, // Ensure that scratch_addr is aligned on a page boundary. - if((uint32_t)scratch_addr & 0x3FF) + if((uint32_t)scratch_addr & 0x3FF) return MICROBIT_INVALID_PARAMETER; // Locate the hardware FLASH page used by this operation. @@ -231,7 +221,7 @@ int MicroBitFlash::flash_write(void* address, void* from_buffer, int erase = need_erase((uint8_t *)from_buffer, (uint8_t *)address, length); // Preserve the data by writing to the scratch page. - if(erase) + if(erase) { if (!scratch_addr) return MICROBIT_INVALID_PARAMETER; @@ -247,21 +237,21 @@ int MicroBitFlash::flash_write(void* address, void* from_buffer, uint32_t writeWord = 0; - for(int i=start;i= offset && i < (offset + length)) + if(i >= offset && i < (offset + length)) { // Write from buffer. writeWord |= (((uint8_t *)from_buffer)[i-offset] << ((byteOffset)*8)); } - else + else { writeWord |= (writeFrom[i] << ((byteOffset)*8)); } - if( ((i+1)%4) == 0) + if( ((i+1)%4) == 0) { this->flash_burn(pgAddr + (i/4), &writeWord, 1); writeWord = 0; @@ -270,4 +260,3 @@ int MicroBitFlash::flash_write(void* address, void* from_buffer, return MICROBIT_OK; } - diff --git a/source/drivers/MicroBitMemoryMap.cpp b/source/drivers/MicroBitMemoryMap.cpp index f70a0f19..3e6e2b6e 100644 --- a/source/drivers/MicroBitMemoryMap.cpp +++ b/source/drivers/MicroBitMemoryMap.cpp @@ -73,14 +73,13 @@ int MicroBitMemoryMap::pushRegion(Region region) // Find next blank Region in map if(regionCount == NUMBER_OF_REGIONS){ - return MICROBIT_NO_DATA; + return MICROBIT_NO_RESOURCES; } 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++; + //memcpy(&memoryMapStore.memoryMap[regionCount].hash, ®ion.hash, 8); + memoryMapStore.memoryMap[regionCount++].regionId = region.regionId; return MICROBIT_OK; } } @@ -90,7 +89,7 @@ int MicroBitMemoryMap::pushRegion(Region region) * * @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 + * @return MICROBIT_OK success, MICROBIT_NO_RESOURCES if the region is not found */ int MicroBitMemoryMap::updateRegion(Region region) { @@ -99,79 +98,41 @@ int MicroBitMemoryMap::updateRegion(Region region) while(memoryMapStore.memoryMap[i].regionId != region.regionId && i < NUMBER_OF_REGIONS) i++; if(i == NUMBER_OF_REGIONS){ - return MICROBIT_NO_DATA; + return MICROBIT_NO_RESOURCES; } 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++) + for(uint8_t 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 - ) - { + // memcmp(magicAddress, magic, 16); + if(*magicAddress == 0x923b8e70 && + *(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); + memcpy(memoryMapStore.memoryMap[1].hash, (uint8_t *)magicAddress, 8); - 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; + magicAddress = (uint32_t *)(magicAddress + 0x2); + memcpy(memoryMapStore.memoryMap[2].hash, (uint8_t *)magicAddress, 8); return; - } }