/
main.c
435 lines (402 loc) · 13.6 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
/* Copyright (c) 2016 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is property of Nordic Semiconductor ASA.
* Terms and conditions of usage are described in detail in NORDIC
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information. NO
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
* the file.
*
*/
/** @file
*
* @defgroup bootloader_secure main.c
* @{
* @ingroup dfu_bootloader_api
* @brief Bootloader project main file for secure DFU.
*
*/
#include <stdint.h>
#include "platform_config.h"
#include "jsutils.h"
#include "hardware.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "nrf_mbr.h"
#include "nrf_bootloader.h"
#include "nrf_bootloader_app_start.h"
#include "nrf_dfu.h"
#include "nrf_dfu_types.h"
#include "nrf_dfu_settings.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "app_error.h"
#include "app_error_weak.h"
#include "app_timer.h"
#include "nrf_bootloader_info.h"
#include "lcd.h"
#ifdef ESPR_BOOTLOADER_SPIFLASH
#include "flash.h"
#endif
#if NRF_SD_BLE_API_VERSION < 5
#include "dfu_status.h"
#endif
// LEDs to use are defined in set_led_state in hardware.h
/// Set up when DFU is connected to
static bool dfuIsConnected = false;
/// Did we just power on, or did we reset because of a software reset?
static bool dfuIsColdBoot = false;
void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) {
/* NRF_LOG_ERROR("received a fault! id: 0x%08x, pc: 0x&08x\r\n", id, pc);
NVIC_SystemReset();*/
}
void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name) {
/*(void)error_code;
NRF_LOG_ERROR("received an error: 0x%08x at %s:%d!\r\n", error_code, p_file_name?p_file_name:"?", line_num);
NVIC_SystemReset();*/
}
void app_error_handler_bare(uint32_t error_code) {
/* (void)error_code;
NRF_LOG_ERROR("received an error: 0x%08x!\r\n", error_code);
NVIC_SystemReset();*/
}
void ble_app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name) {
/*lcd_println("NRF ERROR");
nrf_delay_ms(10000);
NVIC_SystemReset();*/
}
void turn_off() {
lcd_kill();
#ifdef SPIFLASH_SLEEP_CMD
flashPowerDown(); // Put the SPI Flash into deep power-down
#endif
#ifdef VIBRATE_PIN
jshPinOutput(VIBRATE_PIN,1); // vibrate on
#endif
#if defined(BTN2_PININDEX)
while (get_btn1_state() || get_btn2_state()) {}; // wait for BTN1 and BTN2 to be released
#else
while (get_btn1_state()) {}; // wait for BTN1 and BTN2 to be released
#endif
#ifdef VIBRATE_PIN
jshPinSetValue(VIBRATE_PIN,0); // vibrate off
#endif
#ifdef DICKENS
NRF_P0->OUT=0x03300f04; // 00000011 00110000 00001111 00000100 - high pins: D2, D8, SDA, SCL, LCD_CS, FLASH_CS, FLASH_WP, FLASH_RST, FLASH_SCK
//NRF_P0->OUT=0x03300e00; // 00000011 00110000 00001110 00000000 - high pins: SDA, SCL, LCD_CS, FLASH_CS, FLASH_WP, FLASH_RST, FLASH_SCK
if (pinInfo[LCD_BL].port&JSH_PIN_NEGATED) // if backlight negated
NRF_P1->OUT=0x00000001; // High pins: LCD_BL
else
NRF_P1->OUT=0x00000000;
for (uint8_t pin=0; pin<48; pin++) {
NRF_GPIO_PIN_CNF(pin,0x00000004); // Set all pins as input with pulldown
}
NRF_GPIO_PIN_CNF(BAT_PIN_VOLTAGE,0x00000002); // D4 = battery voltage measurement (no pull, input buffer disconnected)
NRF_GPIO_PIN_CNF(ACCEL_PIN_SDA,0x0000060d); // D9 = SDA open-drain output
NRF_GPIO_PIN_CNF(ACCEL_PIN_SCL,0x0000060d); // D10 = SCL open-drain output
NRF_GPIO_PIN_CNF(LCD_SPI_MISO,0x0000000c); // D27 = LCD_MISO input with pullup
if (pinInfo[LCD_BL].port&JSH_PIN_NEGATED) // if backlight negated
NRF_GPIO_PIN_CNF(LCD_BL,0x00000003); // D32 = LCD backlight pin
//NRF_GPIO_PIN_CNF(BTN2_PININDEX,0x0003000c); // D28 = BTN2 input (with pullup and low-level sense)
//NRF_GPIO_PIN_CNF(BTN3_PININDEX,0x0003000c); // D29 = BTN3 input (with pullup and low-level sense)
//NRF_GPIO_PIN_CNF(31,0x00000003); // D31 = Debug output pin (brought out to external header on)
//NRF_GPIO_PIN_CNF(BTN4_PININDEX,0x0003000c); // D42 = BTN4 input (with pullup and low-level sense)
NRF_GPIO_PIN_CNF(BTN1_PININDEX,0x0003000c); // D46 = BTN1 input (with pullup and low-level sense)
#else // !DICKENS
set_led_state(0,0);
#if defined(BTN2_PININDEX)
nrf_gpio_cfg_sense_set(BTN2_PININDEX, NRF_GPIO_PIN_NOSENSE);
nrf_gpio_cfg_sense_set(BTN3_PININDEX, NRF_GPIO_PIN_NOSENSE);
#endif
nrf_gpio_cfg_sense_input(pinInfo[BTN1_PININDEX].pin, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW);
nrf_gpio_cfg_sense_set(pinInfo[BTN1_PININDEX].pin, NRF_GPIO_PIN_SENSE_LOW);
#endif
NRF_POWER->TASKS_LOWPWR = 1;
NRF_POWER->SYSTEMOFF = 1;
while (true) {};
}
// Override Weak version
#if NRF_SD_BLE_API_VERSION < 5
bool nrf_dfu_enter_check(void) {
#else
// dfu_enter_check must be modified to add the __WEAK keyword
bool dfu_enter_check(void) {
#endif
bool dfu_start;
#ifdef BTN1_PININDEX
dfu_start = get_btn1_state();
#else
dfu_start = dfuIsColdBoot; // if no button, enter bootloader if it's a cold boot, then exit after a few seconds
#endif
#ifdef BUTTONPRESS_TO_REBOOT_BOOTLOADER
// if DFU looks invalid, go straight to bootloader
if (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_INVALID) {
lcd_println("BANK0 INVALID");
if (!dfu_start) return true;
}
#endif
// If button is held down for 3 seconds, don't start bootloader.
// This means that we go straight to Espruino, where the button is still
// pressed and can be used to stop execution of the sent code.
if (dfu_start) {
#if defined(BUTTONPRESS_TO_REBOOT_BOOTLOADER) && defined(BTN2_PININDEX)
lcd_print("RELEASE BTN1 FOR DFU\r\nBTN1 TO BOOT\r\nBTN1 + BTN2 TURN OFF\r\n\r\n< >\r");
#else
lcd_print("RELEASE BTN1 FOR DFU\r\nBTN1 TO BOOT\r\n\r\n< >\r");
#endif
#ifdef BTN1_PININDEX
int count = 20;
#ifdef BANGLEJS_F18
while (get_btn1_state() && --count) {
// the screen update takes long enough that
// we don't need a delay
lcd_print("=");
}
#else
count *= 128;
while (get_btn1_state() && count) {
nrf_delay_us(999);
set_led_state((count&3)==0, false);
if ((count&127)==0) lcd_print("=");
count--;
}
#endif
#else
// no button, ensure we enter bootloader
int count=1;
#endif
if (!count) {
dfu_start = false;
#if defined(BUTTONPRESS_TO_REBOOT_BOOTLOADER) && defined(BTN2_PININDEX)
if (jshPinGetValue(BTN2_PININDEX)) {
turn_off();
//NVIC_SystemReset(); // just in case!
}
#endif
} else {
lcd_clear();
lcd_println("DFU START");
}
set_led_state(true, true);
}
if (!dfu_start) {
#ifdef LCD
lcd_println("\r\nBOOTING...");
#ifdef BANGLEJS
nrf_delay_us(100000);
#endif
#endif
#ifdef BUTTONPRESS_TO_REBOOT_BOOTLOADER
// turn on watchdog - bootloader should override this if it starts,
// but if we go straight through to run code then if the code fails to boot
// we'll restart.
NRF_WDT->CONFIG = (WDT_CONFIG_HALT_Pause << WDT_CONFIG_HALT_Pos) | ( WDT_CONFIG_SLEEP_Run << WDT_CONFIG_SLEEP_Pos);
NRF_WDT->CRV = (int)(5*32768); // 5 seconds
NRF_WDT->RREN |= WDT_RREN_RR0_Msk; // Enable reload register 0
NRF_WDT->TASKS_START = 1;
NRF_WDT->RR[0] = 0x6E524635; // Kick...
#endif
}
return dfu_start;
}
#if defined(BUTTONPRESS_TO_REBOOT_BOOTLOADER) || !defined(BTN1_PININDEX)
#define REBOOT_TIMER
APP_TIMER_DEF(m_reboot_timer_id);
int rebootCounter = 0;
void reboot_check_handler() {
#ifdef BUTTONPRESS_TO_REBOOT_BOOTLOADER
if (get_btn1_state()) rebootCounter++;
else rebootCounter=0;
if (rebootCounter>10) {
NVIC_SystemReset();
}
// We enabled the watchdog, so we must kick it (as it stays set even after restart)
NRF_WDT->RR[0] = 0x6E524635;
#endif
#ifndef BTN1_PININDEX
if (dfuIsConnected)
rebootCounter = 0;
else {
rebootCounter++;
if (rebootCounter>50) {
// After 5 seconds of not being connected force reboot.
// We'll then see that it wasn't a cold boot
// and will start up normally
NVIC_SystemReset();
}
}
#endif
#if NRF_SD_BLE_API_VERSION>=5
// not quite sure why this doesn't repeat in SDK15 when we
// asked it to - maybe DFU kills all timers?
app_timer_start(m_reboot_timer_id,
APP_TIMER_TICKS(100),
NULL);
#endif
}
#endif
void dfu_evt_init() {
set_led_state(true,false);
#ifdef REBOOT_TIMER
uint32_t err_code;
err_code = app_timer_create(&m_reboot_timer_id,
APP_TIMER_MODE_REPEATED,
reboot_check_handler);
err_code = app_timer_start(m_reboot_timer_id,
#if NRF_SD_BLE_API_VERSION<5
APP_TIMER_TICKS(100, 0),
#else
APP_TIMER_TICKS(100),
#endif
NULL);
#endif
#ifdef BUTTONPRESS_TO_REBOOT_BOOTLOADER
lcd_println("BTN1 = REBOOT");
#endif
}
void dfu_evt_connected() {
lcd_println("CONNECT");
set_led_state(false,true);
dfuIsConnected = true;
}
void dfu_evt_disconnected() {
lcd_println("DISCONNECT");
dfuIsConnected = false;
}
#if NRF_SD_BLE_API_VERSION < 5
extern void dfu_set_status(DFUStatus status) {
switch (status) {
case DFUS_ADVERTISING_START:
dfu_evt_init();
break;
/* case DFUS_ADVERTISING_STOP:
break;*/
case DFUS_CONNECTED:
dfu_evt_connected();
break;
case DFUS_DISCONNECTED:
dfu_evt_disconnected();
break;
}
}
#else
static void dfu_observer(nrf_dfu_evt_type_t evt_type)
{
switch (evt_type)
{
case NRF_DFU_EVT_DFU_INITIALIZED:
dfu_evt_init();
break;
case NRF_DFU_EVT_DFU_FAILED:
case NRF_DFU_EVT_DFU_ABORTED:
lcd_println("ERROR");
set_led_state(true,false);
break;
case NRF_DFU_EVT_TRANSPORT_ACTIVATED:
dfu_evt_connected();
break;
case NRF_DFU_EVT_TRANSPORT_DEACTIVATED:
dfu_evt_disconnected();
break;
case NRF_DFU_EVT_DFU_STARTED:
lcd_println("STARTED");
break;
default:
break;
}
}
#endif
/**@brief Function for application main entry.
*/
int main(void)
{
uint32_t ret_val;
(void) NRF_LOG_INIT(NULL);
NRF_LOG_INFO("Inside main\r\n");
hardware_init();
// Did we just power on? If not (we watchdog/softreset) RESETREAS will be nonzero
/* NRF_POWER->RESETREAS reset reason flags:
* 0x000001 : RESETPIN Reset pin
* 0x000002 : DOG Watchdog
* 0x000004 : SREQ Software reset
* 0x000008 : LOCKUP CPU lock-up
* 0x010000 : OFF Woke up from system OFF via GPIO DETECT
* 0x020000 : LPCOMP Woke up from system OFF via LPCOMP ANADETECT
* 0x040000 : DIF Woke up from system OFF into debug inteface mode
* 0x080000 : NFC Woke up from system OFF by NFC field detector
* 0x100000 : VBUS Woke up from system OFF by VBUS rising into valid range
*/
int r = NRF_POWER->RESETREAS;
dfuIsColdBoot = (r&0xF)==0;
#if defined(DICKENS) || defined(BANGLEJS)
// On smartwatches, turn on only if BTN1 held for >1 second
// This may help in cases where battery is TOTALLY flat
if ((r&0b1011)==0) {
// if not watchdog, lockup, or reset pin...
if ((r&0xF)==0) { // Bangle.softOff causes 'SW RESET' after 1 sec, so r==4
nrf_delay_ms(1000);
}
if (!get_btn1_state() && (r&0xF)==0) { // Don't turn off after a SW reset, to avoid user input needed during reflashing
turn_off();
} else {
#ifdef DICKENS
// DICKENS: Enter bootloader only if BTN2 held as well
if (!get_btn2_state()) {
// Clear reset reason flags
NRF_POWER->RESETREAS = 0xFFFFFFFF;
#ifdef ESPR_BOOTLOADER_SPIFLASH
lcd_init();
lcd_println("DFU " JS_VERSION "\n");
// Check if we should reflash new firmware
flashCheckAndRun();
#endif
// Run the main application.
nrf_bootloader_app_start();
} else {
}
#endif // DICKENS
}
}
#endif
#ifdef LCD
lcd_init();
const char *reasons = "PIN\0WATCHDOG\0SW RESET\0LOCKUP\0OFF\0";
while (*reasons) {
if (r&1)
lcd_println(reasons);
r>>=1;
while (*reasons) reasons++;
reasons++;
}
// Clear reset reason flags
NRF_POWER->RESETREAS = 0xFFFFFFFF;
lcd_println("DFU " JS_VERSION "\n");
#ifdef ESPR_BOOTLOADER_SPIFLASH
if (!get_btn1_state()) flashCheckAndRun();
#endif
#ifdef BANGLEJS
nrf_delay_us(500000); // 500ms delay
#endif
#endif
#if NRF_SD_BLE_API_VERSION < 5
ret_val = nrf_bootloader_init();
APP_ERROR_CHECK(ret_val);
// Either there was no DFU functionality enabled in this project or the DFU module detected
// no ongoing DFU operation and found a valid main application.
// Boot the main application.
nrf_bootloader_app_start(MAIN_APPLICATION_START_ADDR);
#else
ret_val = nrf_bootloader_init(dfu_observer);
APP_ERROR_CHECK(ret_val);
// Either there was no DFU functionality enabled in this project or the DFU module detected
// no ongoing DFU operation and found a valid main application.
// Boot the main application.
nrf_bootloader_app_start();
#endif
// Should never be reached.
NRF_LOG_INFO("After main\r\n");
}
/**
* @}
*/