-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
rebase and add examples/test/app_loader. New app binaries are located…
… in internal/binaries.c. cleaned up and formatted removed old code removed userspace code from a previous implementation that was giving rise to confusion. added comments to app_loader.h added binaries headers and updated code added binaries in external files to make the app file more readable. Added a new subscribe and callback to support the async setup update readme
- Loading branch information
1 parent
84edbac
commit becbef9
Showing
11 changed files
with
1,694 additions
and
5,708 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
2 changes: 1 addition & 1 deletion
2
...les/tests/app_loader/pre_flashed/Makefile → examples/tests/app_loader/Makefile
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# Dynamic App Loader (Helper App) | ||
================================= | ||
|
||
This app waits upon the user to press one of two buttons on the device (if supported). | ||
|
||
When Button 1 (Default user button on boards) is pressed, the app tried to load in the | ||
`blink` app. | ||
|
||
When Button 2 is pressed, the app tries to load in the `adc` app. | ||
|
||
There are three stages to this: | ||
|
||
1. Setup Phase | ||
2. Flash Phase | ||
3. Load Phase | ||
|
||
#### Setup Phase | ||
During the setup phase, the application passes the size of the new app `(blink)/(adc)`'s | ||
binary to the app_loader capsule. | ||
|
||
The capsule returns with either a success or failure. | ||
|
||
On success, the app requests the app_loader capsule to flash the `blink/adc` app. | ||
|
||
On Failure, the app exits logs the reason for failure and exits. | ||
|
||
#### Flash Phase | ||
The app sends the binary of the `blink/adc` app 512 bytes (this is the size of the shared | ||
buffer between the app and the capsule) at a time along with the offset. | ||
|
||
The capsule checks that these values do not violate the bounds dictated by the kernel | ||
and then requests the kernel to flash the app. | ||
|
||
The kernel performs more stringent checking on the request to ensure that memory access | ||
violations do not take place, and flashes the app. | ||
|
||
The capsule then returns with either a success or failure. | ||
|
||
On success, the app requests the app_loader capsule to load the `blink/adc` app. | ||
|
||
On Failure, the app exits logs the reason for failure and exits. | ||
|
||
#### Load Phase | ||
The app requests the capsule to load the new app. There are only two outcomes: | ||
|
||
1. The `blink/adc` app is loaded successfully and functions without requiring a restart. | ||
2. The load process failed somewhere, and the app is erased. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,238 @@ | ||
// \file | ||
|
||
// This is a helper program to test if the dynamic app loading functionality | ||
// of Tock works. This app has another application's (blink) binary pre-programmed | ||
// into it. When the user presses a button on a supported device, the dynamic | ||
// process loader enables the new app to be written to flash and loaded as a new process. | ||
|
||
#include <math.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
#include <app_binaries.h> | ||
#include <app_loader.h> | ||
#include <button.h> | ||
#include <timer.h> | ||
#include <tock.h> | ||
|
||
|
||
#define FLASH_BUFFER_SIZE 512 | ||
#define RETURNCODE_SUCCESS 0 | ||
|
||
static bool setup_done = false; // to check if setup is done | ||
static bool write_done = false; // to check if writing to flash is done | ||
|
||
/****************************************************************************************************** | ||
* Callback functions | ||
* | ||
* 1. Callback to let us know when the capsule is done writing data to flash | ||
* 2. Set button callback to initiate the dynamic app load process on pressing button 1 (on nrf52840dk) | ||
* | ||
******************************************************************************************************/ | ||
|
||
// static void nop_callback(int a __attribute__((unused)), int b __attribute__((unused)), int c __attribute__((unused)), void *d __attribute__((unused))) {} | ||
|
||
static void app_setup_done_callback(__attribute__((unused)) int length, | ||
__attribute__((unused)) int arg1, | ||
__attribute__((unused)) int arg2, | ||
__attribute__((unused)) void *ud) | ||
{ | ||
setup_done = true; | ||
} | ||
|
||
static void app_write_done_callback(__attribute__((unused)) int length, | ||
__attribute__((unused)) int arg1, | ||
__attribute__((unused)) int arg2, | ||
__attribute__((unused)) void *ud) | ||
{ | ||
write_done = true; | ||
} | ||
|
||
static void button_callback(int btn_num, | ||
int val, | ||
__attribute__ ((unused)) int arg2, | ||
__attribute__ ((unused)) void *ud) | ||
{ | ||
// Callback for button presses. | ||
// val: 1 if pressed, 0 if depressed | ||
|
||
// flash and load blink | ||
if (btn_num == BUTTON1 && val == 1) { | ||
|
||
delay_ms(100); // debounce | ||
|
||
if (val == 1) { | ||
|
||
printf("[Event] Button 1 Pressed!\n"); | ||
double app_size = sizeof(blink); | ||
int ret = 0; | ||
int ret1 = 0; | ||
int ret2 = 0; | ||
|
||
ret = app_loader_command_setup(app_size); // asks the capsule to set up for app flash | ||
if (ret != RETURNCODE_SUCCESS) { | ||
printf("[Error] Setup Failed: %d.\n", ret); | ||
printf("[Log] Exiting Application.\n"); | ||
tock_exit(ret); // we failed, so we exit the program. | ||
} else { | ||
yield_for(&setup_done); // wait until the padding app write is done before you send your app, or it will fail during write | ||
setup_done = false; | ||
printf("[Success] Setup successful. Attempting to write app to flash now.\n"); | ||
ret1 = write_app(app_size, blink); // writes app data to flash | ||
if (ret1 != RETURNCODE_SUCCESS) { | ||
printf("[Error] App flash write unsuccessful: %d.\n", ret1); | ||
printf("[Log] Exiting Application.\n"); | ||
tock_exit(ret1); // we failed, so we exit the program. | ||
} else { | ||
printf("[Success] App flashed successfully. Attempting to create a process now.\n"); | ||
ret2 = app_loader_command_load(); // request to load app | ||
if (ret2 != RETURNCODE_SUCCESS) { | ||
printf("[Error] Process creation failed: %d.\n", ret2); | ||
printf("[Log] Exiting Application.\n"); | ||
tock_exit(ret2); // we failed, so we exit the program. | ||
} else { | ||
printf("[Success] Process created successfully.\n"); | ||
} | ||
} | ||
} | ||
app_size = 0; // reset app_size | ||
} | ||
} | ||
// flash and load adc | ||
else if (btn_num == BUTTON2 && val == 1) { | ||
|
||
delay_ms(100); // debounce | ||
|
||
if (val == 1) { | ||
printf("[Event] Button 2 Pressed!\n"); | ||
double app_size = sizeof(adc); | ||
int ret = 0; | ||
int ret1 = 0; | ||
int ret2 = 0; | ||
|
||
ret = app_loader_command_setup(app_size); // asks the capsule to set up for app flash | ||
if (ret != RETURNCODE_SUCCESS) { | ||
printf("[Error] Setup Failed: %d.\n", ret); | ||
printf("[Log] Exiting Application.\n"); | ||
tock_exit(ret); // we failed, so we exit the program. | ||
} else { | ||
// yielding for padding write | ||
printf("[Log] yielding for setup done.\n"); | ||
yield_for(&setup_done); // wait until the padding app write is done before you send your app, or it will fail during write | ||
setup_done = false; | ||
// padding success | ||
printf("[Success] Setup successful. Attempting to write app to flash now.\n"); | ||
ret1 = write_app(app_size, adc); // writes app data to flash | ||
if (ret1 != RETURNCODE_SUCCESS) { | ||
printf("[Error] App flash write unsuccessful: %d.\n", ret1); | ||
printf("[Log] Exiting Application.\n"); | ||
tock_exit(ret1); // we failed, so we exit the program. | ||
} else { | ||
printf("[Success] App flashed successfully. Attempting to create a process now.\n"); | ||
ret2 = app_loader_command_load(); // request to load app | ||
if (ret2 != RETURNCODE_SUCCESS) { | ||
printf("[Error] Process creation failed: %d.\n", ret2); | ||
printf("[Log] Exiting Application.\n"); | ||
tock_exit(ret2); // we failed, so we exit the program. | ||
} else { | ||
printf("[Success] Process created successfully.\n"); | ||
} | ||
} | ||
} | ||
app_size = 0; // reset app_size | ||
} | ||
} | ||
} | ||
|
||
|
||
/****************************************************************************************************** | ||
* | ||
* Function to write the app into the flash | ||
* | ||
* Takes app size and the app binary as arguments | ||
******************************************************************************************************/ | ||
|
||
int write_app(double size, uint8_t binary[]){ | ||
|
||
int ret; | ||
uint32_t write_count = 0; | ||
uint8_t write_buffer[FLASH_BUFFER_SIZE]; | ||
uint32_t flash_offset = 0; | ||
|
||
write_count = ceil(size / FLASH_BUFFER_SIZE); | ||
|
||
ret = app_loader_write_buffer(write_buffer, FLASH_BUFFER_SIZE); // set the write buffer | ||
if (ret != RETURNCODE_SUCCESS) { | ||
printf("[Error] Failed to set the write buffer: %d.\n", ret); | ||
return -1; | ||
} | ||
|
||
for (uint32_t offset = 0; offset < write_count; offset++) { | ||
memcpy(write_buffer, &binary[FLASH_BUFFER_SIZE * offset], FLASH_BUFFER_SIZE); // copy binary to write buffer | ||
flash_offset = (offset * FLASH_BUFFER_SIZE); | ||
ret = app_loader_command_write(flash_offset, FLASH_BUFFER_SIZE); | ||
if (ret != 0) { | ||
printf("[Error] Failed writing data to flash at address: 0x%lx\n", flash_offset); | ||
return -1; | ||
} | ||
yield_for(&write_done); // wait until write done callback | ||
write_done = false; | ||
} | ||
return 0; | ||
} | ||
|
||
|
||
/****************************************************************************************************** | ||
* | ||
* Main | ||
* | ||
******************************************************************************************************/ | ||
|
||
int main(void) { | ||
printf("[Log] Simple test app to load an app dynamically.\n"); | ||
|
||
int count; | ||
int err = button_count(&count); | ||
// Ensure there is a button to use. | ||
if (err < 0) return err; | ||
printf("[Log] There are %d buttons on this board.\n", count); | ||
|
||
// Enable interrupts on each button. | ||
for (int i = 0; i < count; i++) { | ||
button_enable_interrupt(i); | ||
} | ||
|
||
// set up the write done and button press callbacks | ||
int err1 = app_loader_setup_subscribe(app_setup_done_callback, NULL); | ||
if (err1 != 0) { | ||
printf("[Error] Failed to set setup done callback: %d\n", err1); | ||
return err1; | ||
} | ||
|
||
// set up the write done and button press callbacks | ||
int err2 = app_loader_write_subscribe(app_write_done_callback, NULL); | ||
if (err2 != 0) { | ||
printf("[Error] Failed to set flash write done callback: %d\n", err2); | ||
return err2; | ||
} | ||
|
||
int err3 = button_subscribe(button_callback, NULL); | ||
if (err3 != 0) { | ||
printf("[Error] Failed to set button callback: %d.\n", err3); | ||
return err3; | ||
} | ||
|
||
// Check if the app_loader driver exists. | ||
int ret; | ||
ret = app_loader_exists(); | ||
if (ret != RETURNCODE_SUCCESS) { | ||
printf("[Error] Dynamic Apploader driver does not exist.\n"); | ||
return ret; // the driver does not exist, so we cannot load an app anyway. Let us exit the program. | ||
} | ||
|
||
printf("[Log] Waiting for a button press.\n"); | ||
|
||
while (1) { | ||
yield(); | ||
} | ||
} |
Oops, something went wrong.