Statistics
| Branch: | Tag: | Revision:

amiro-blt / Target / Modules / DiWheelDrive_1-1 / Boot / main.c @ 03906dc3

History | View | Annotate | Download (35.957 KB)

1
/************************************************************************************//**
2
* \file         Demo\ARMCM3_STM32_Olimex_STM32P103_GCC\Boot\main.c
3
* \brief        Bootloader application source file.
4
* \ingroup      Boot_ARMCM3_STM32_Olimex_STM32P103_GCC
5
* \internal
6
*----------------------------------------------------------------------------------------
7
*                          C O P Y R I G H T
8
*----------------------------------------------------------------------------------------
9
*   Copyright (c) 2012  by Feaser    http://www.feaser.com    All rights reserved
10
*
11
*----------------------------------------------------------------------------------------
12
*                            L I C E N S E
13
*----------------------------------------------------------------------------------------
14
* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
15
* modify it under the terms of the GNU General Public License as published by the Free
16
* Software Foundation, either version 3 of the License, or (at your option) any later
17
* version.
18
*
19
* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
20
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
21
* PURPOSE. See the GNU General Public License for more details.
22
*
23
* You should have received a copy of the GNU General Public License along with OpenBLT.
24
* If not, see <http://www.gnu.org/licenses/>.
25
*
26
* A special exception to the GPL is included to allow you to distribute a combined work
27
* that includes OpenBLT without being obliged to provide the source code for any
28
* proprietary components. The exception text is included at the bottom of the license
29
* file <license.html>.
30
*
31
* \endinternal
32
****************************************************************************************/
33

    
34
/****************************************************************************************
35
* Include files
36
****************************************************************************************/
37
#include "boot.h"                                /* bootloader generic header          */
38
#include "timer.h"
39
#include "ARMCM3_STM32/types.h"
40
#include "AMiRo/amiroblt.h"
41
#include "helper.h"
42
#include "iodef.h"
43

    
44
/****************************************************************************************
45
* Defines
46
****************************************************************************************/
47
#define RESET_TIMEOUT_MS    100
48

    
49
/****************************************************************************************
50
* Function prototypes
51
****************************************************************************************/
52
static void Init(void);
53

    
54
static void initGpio();
55
static void initExti();
56
void configGpioForShutdown();
57

    
58
ErrorStatus handleColdReset();
59
ErrorStatus handleUartWakeup();
60
ErrorStatus handleAccelWakeup();
61

    
62
ErrorStatus shutdownDisambiguationProcedure(const uint8_t type);
63
void shutdownToTransportation(const blt_bool exec_disambiguation);
64
void shutdownToDeepsleep(const blt_bool exec_disambiguation);
65
void shutdownToHibernate(const blt_bool exec_disambiguation);
66
void shutdownAndRestart(const blt_bool exec_disambiguation);
67

    
68
volatile blBackupRegister_t backup_reg;
69

    
70
/****************************************************************************************
71
* Callback configuration
72
****************************************************************************************/
73
void blCallbackShutdownTransportation(void);
74
void blCallbackShutdownDeepsleep(void);
75
void blCallbackShutdownHibernate(void);
76
void blCallbackShutdownRestart(void);
77
void blCallbackHandleShutdownRequest(void);
78

    
79
const blCallbackTable_t cbtable __attribute__ ((section ("_callback_table"))) = {
80
  .magicNumber = BL_MAGIC_NUMBER,
81
  .vBootloader = {BL_VERSION_ID_AMiRoBLT_Release, BL_VERSION_MAJOR, BL_VERSION_MINOR, 1},
82
  .vSSSP = {BL_VERSION_ID_SSSP, BL_SSSP_VERSION_MAJOR, BL_SSSP_VERSION_MINOR, 0},
83
  .vCompiler = {BL_VERSION_ID_GCC, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__},  // currently only GCC is supported
84
  .cbShutdownHibernate = blCallbackShutdownHibernate,
85
  .cbShutdownDeepsleep = blCallbackShutdownDeepsleep,
86
  .cbShutdownTransportation = blCallbackShutdownTransportation,
87
  .cbShutdownRestart = blCallbackShutdownRestart,
88
  .cbHandleShutdownRequest = blCallbackHandleShutdownRequest,
89
  .cb5 = (void*)0,
90
  .cb6 = (void*)0,
91
  .cb7 = (void*)0,
92
  .cb8 = (void*)0,
93
  .cb9 = (void*)0,
94
  .cb10 = (void*)0,
95
  .cb11 = (void*)0
96
};
97

    
98

    
99
/************************************************************************************//**
100
** \brief     This is the entry point for the bootloader application and is called
101
**            by the reset interrupt vector after the C-startup routines executed.
102
** \return    Program return code.
103
**
104
****************************************************************************************/
105
int main(void)
106
{
107
  /* initialize the microcontroller */
108
  Init();
109

    
110
  /* activate some required clocks */
111
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
112
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
113

    
114
  /* initialize GPIOs and EXTI lines */
115
  initGpio();
116
  setLed(BLT_TRUE);
117
  initExti();
118

    
119
  /* initialize the timer */
120
  TimerInit();
121

    
122
  /* detect the primary reason for this wakeup/restart */
123
  backup_reg.wakeup_pri_reason =
124
      ((RCC_GetFlagStatus(RCC_FLAG_LPWRRST) == SET) ? BL_WAKEUP_PRI_RSN_LPWRRST : 0) |
125
      ((RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET) ? BL_WAKEUP_PRI_RSN_WWDGRST : 0) |
126
      ((RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET) ? BL_WAKEUP_PRI_RSN_IWDGRST : 0) |
127
      ((RCC_GetFlagStatus(RCC_FLAG_SFTRST) == SET) ? BL_WAKEUP_PRI_RSN_SFTRST : 0)   |
128
      ((RCC_GetFlagStatus(RCC_FLAG_PORRST) == SET) ? BL_WAKEUP_PRI_RSN_PORRST : 0)   |
129
      ((RCC_GetFlagStatus(RCC_FLAG_PINRST) == SET) ? BL_WAKEUP_PRI_RSN_PINRST : 0)   |
130
      ((PWR_GetFlagStatus(PWR_FLAG_WU) == SET) ? BL_WAKEUP_PRI_RSN_WKUP : 0);
131

    
132
  /* when woken from standby mode, detect the secondary reason for thiswakeup/reset */
133
  if ( (backup_reg.wakeup_pri_reason & BL_WAKEUP_PRI_RSN_WKUP) && (PWR_GetFlagStatus(PWR_FLAG_SB) == SET) ) {
134
    if (GPIO_ReadInputDataBit(SYS_UART_UP_GPIO, SYS_UART_UP_PIN) == Bit_SET) {
135
      backup_reg.wakeup_sec_reason = BL_WAKEUP_SEC_RSN_UART;
136
    } else {
137
      backup_reg.wakeup_sec_reason = BL_WAKEUP_SEC_RSN_ACCEL;
138
    }
139
  } else {
140
    backup_reg.wakeup_sec_reason = BL_WAKEUP_SEC_RSN_UNKNOWN;
141
  }
142

    
143
  /* clear the flags */
144
  RCC_ClearFlag();
145
  PWR_ClearFlag(PWR_FLAG_WU);
146

    
147
  setLed(BLT_FALSE);
148

    
149
  /* wait 1ms for all signals to become stable */
150
  msleep(1);
151

    
152
  /* handle different wakeup/reset reasons */
153
  ErrorStatus status = ERROR;
154
  if (backup_reg.wakeup_pri_reason & BL_WAKEUP_PRI_RSN_WKUP) {
155
    /* the system was woken via WKUP pin */
156
    /* differenciate between two wakeup types */
157
    switch (backup_reg.wakeup_sec_reason) {
158
      case BL_WAKEUP_SEC_RSN_UART:
159
        status = handleUartWakeup();
160
        break;
161
      case BL_WAKEUP_SEC_RSN_ACCEL:
162
        status = handleAccelWakeup();
163
        break;
164
      default:
165
        status = ERROR;
166
        break;
167
    }
168
  } else if (backup_reg.wakeup_pri_reason & BL_WAKEUP_PRI_RSN_PINRST) {
169
    /* system was woken via NRST pin */
170
    status = handleColdReset();
171
  } else {
172
    /* system was woken/reset for an unexpected reason */
173
    blinkSOS(1);
174
    status = handleColdReset();
175
  }
176

    
177
  /* if something wehnt wrong, signal this failure */
178
  if (status != SUCCESS) {
179
    blinkSOSinf();
180
  }
181

    
182
  return 0;
183
} /*** end of main ***/
184

    
185

    
186
/************************************************************************************//**
187
** \brief     Initializes the microcontroller.
188
** \return    none.
189
**
190
****************************************************************************************/
191
static void Init(void)
192
{
193
  volatile blt_int32u StartUpCounter = 0, HSEStatus = 0;
194
  blt_int32u pll_multiplier;
195
#if (BOOT_FILE_LOGGING_ENABLE > 0) && (BOOT_COM_UART_ENABLE == 0)
196
  GPIO_InitTypeDef  GPIO_InitStruct;
197
  USART_InitTypeDef USART_InitStruct;
198
#endif
199

    
200
  /* reset the RCC clock configuration to the default reset state (for debug purpose) */
201
  /* set HSION bit */
202
  RCC->CR |= (blt_int32u)0x00000001;
203
  /* reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
204
  RCC->CFGR &= (blt_int32u)0xF8FF0000;
205
  /* reset HSEON, CSSON and PLLON bits */
206
  RCC->CR &= (blt_int32u)0xFEF6FFFF;
207
  /* reset HSEBYP bit */
208
  RCC->CR &= (blt_int32u)0xFFFBFFFF;
209
  /* reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
210
  RCC->CFGR &= (blt_int32u)0xFF80FFFF;
211
  /* disable all interrupts and clear pending bits  */
212
  RCC->CIR = 0x009F0000;
213
  /* enable HSE */
214
  RCC->CR |= ((blt_int32u)RCC_CR_HSEON);
215
  /* wait till HSE is ready and if Time out is reached exit */
216
  do
217
  {
218
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
219
    StartUpCounter++;
220
  }
221
  while((HSEStatus == 0) && (StartUpCounter != 1500));
222
  /* check if time out was reached */
223
  if ((RCC->CR & RCC_CR_HSERDY) == RESET)
224
  {
225
    /* cannot continue when HSE is not ready */
226
    ASSERT_RT(BLT_FALSE);
227
  }
228
  /* enable flash prefetch buffer */
229
  FLASH->ACR |= FLASH_ACR_PRFTBE;
230
  /* reset flash wait state configuration to default 0 wait states */
231
  FLASH->ACR &= (blt_int32u)((blt_int32u)~FLASH_ACR_LATENCY);
232
#if (BOOT_CPU_SYSTEM_SPEED_KHZ > 48000)
233
  /* configure 2 flash wait states */
234
  FLASH->ACR |= (blt_int32u)FLASH_ACR_LATENCY_2;
235
#elif (BOOT_CPU_SYSTEM_SPEED_KHZ > 24000)
236
  /* configure 1 flash wait states */
237
  FLASH->ACR |= (blt_int32u)FLASH_ACR_LATENCY_1;
238
#endif
239
  /* HCLK = SYSCLK */
240
  RCC->CFGR |= (blt_int32u)RCC_CFGR_HPRE_DIV1;
241
  /* PCLK2 = HCLK/2 */
242
  RCC->CFGR |= (blt_int32u)RCC_CFGR_PPRE2_DIV2;
243
  /* PCLK1 = HCLK/2 */
244
  RCC->CFGR |= (blt_int32u)RCC_CFGR_PPRE1_DIV2;
245
  /* reset PLL configuration */
246
  RCC->CFGR &= (blt_int32u)((blt_int32u)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | \
247
                                          RCC_CFGR_PLLMULL));
248
  /* assert that the pll_multiplier is between 2 and 16 */
249
  ASSERT_CT((BOOT_CPU_SYSTEM_SPEED_KHZ/BOOT_CPU_XTAL_SPEED_KHZ) >= 2);
250
  ASSERT_CT((BOOT_CPU_SYSTEM_SPEED_KHZ/BOOT_CPU_XTAL_SPEED_KHZ) <= 16);
251
  /* calculate multiplier value */
252
  pll_multiplier = BOOT_CPU_SYSTEM_SPEED_KHZ/BOOT_CPU_XTAL_SPEED_KHZ;
253
  /* convert to register value */
254
  pll_multiplier = (blt_int32u)((pll_multiplier - 2) << 18);
255
  /* set the PLL multiplier and clock source */
256
  RCC->CFGR |= (blt_int32u)(RCC_CFGR_PLLSRC_HSE | pll_multiplier);
257
  /* enable PLL */
258
  RCC->CR |= RCC_CR_PLLON;
259
  /* wait till PLL is ready */
260
  while((RCC->CR & RCC_CR_PLLRDY) == 0)
261
  {
262
  }
263
  /* select PLL as system clock source */
264
  RCC->CFGR &= (blt_int32u)((blt_int32u)~(RCC_CFGR_SW));
265
  RCC->CFGR |= (blt_int32u)RCC_CFGR_SW_PLL;
266
  /* wait till PLL is used as system clock source */
267
  while ((RCC->CFGR & (blt_int32u)RCC_CFGR_SWS) != (blt_int32u)0x08)
268
  {
269
  }
270

    
271
  /* remap JTAG pins */
272
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
273
  AFIO->MAPR &= ~(blt_int32u)((blt_int32u)0x7 << 24);
274
  AFIO->MAPR |=  (blt_int32u)((blt_int32u)0x2 << 24);
275
  /* all input */
276

    
277
#if (BOOT_COM_CAN_ENABLE > 0 || BOOT_GATE_CAN_ENABLE > 0)
278
  /* enable clocks for CAN transmitter and receiver pins (GPIOB and AFIO) */
279
  RCC->APB2ENR |= (blt_int32u)(0x00000004 | 0x00000001);
280
  /* configure CAN Rx (GPIOA11) as alternate function input */
281
  /* first reset the configuration */
282
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 12);
283
  /* CNF8[1:0] = %01 and MODE8[1:0] = %00 */
284
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0x4 << 12);
285
  /* configure CAN Tx (GPIOA12) as alternate function push-pull */
286
  /* first reset the configuration */
287
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 16);
288
  /* CNF9[1:0] = %11 and MODE9[1:0] = %11 */
289
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0xb << 16);
290

    
291
  /* remap CAN1 pins to PortA */
292
  AFIO->MAPR &= ~(blt_int32u)((blt_int32u)0x3 << 13);
293
  AFIO->MAPR |=  (blt_int32u)((blt_int32u)0x0 << 13);
294
#endif
295

    
296
#if (BOOT_COM_UART_ENABLE > 0 || BOOT_GATE_UART_ENABLE > 0)
297
  /* enable clocks for USART1 peripheral, transmitter and receiver pins (GPIOA and AFIO) */
298
  RCC->APB2ENR |= (blt_int32u)(0x00004000 | 0x00000004 | 0x00000001);
299
  /* configure USART1 Tx (GPIOA9) as alternate function push-pull */
300
  /* first reset the configuration */
301
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 4);
302
  /* CNF2[1:0] = %10 and MODE2[1:0] = %11 */
303
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0xb << 4);
304
  /* configure USART1 Rx (GPIOA10) as alternate function input floating */
305
  /* first reset the configuration */
306
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 8);
307
  /* CNF2[1:0] = %01 and MODE2[1:0] = %00 */
308
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0x4 << 8);
309
#endif
310

    
311
} /*** end of Init ***/
312

    
313
/*
314
 * Initializes all GPIO used by the bootloader
315
 */
316
static void initGpio() {
317
  GPIO_InitTypeDef gpio_init;
318

    
319
  /*
320
   * OUTPUTS
321
   */
322

    
323
  /* initialize LED and push it up (inactive) */
324
  GPIO_SetBits(LED_GPIO, LED_PIN);
325
  gpio_init.GPIO_Pin    = LED_PIN;
326
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_PP;
327
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
328
  GPIO_Init(LED_GPIO, &gpio_init);
329

    
330
  /* initialize SYS_PD_N and let it go (inactive) */
331
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
332
  gpio_init.GPIO_Pin    = SYS_PD_N_PIN;
333
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
334
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
335
  GPIO_Init(SYS_PD_N_GPIO, &gpio_init);
336

    
337
  /* initialize SYS_SYNC_N and pull it down (active) */
338
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
339
  gpio_init.GPIO_Pin    = SYS_SYNC_N_PIN;
340
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
341
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
342
  GPIO_Init(SYS_SYNC_N_GPIO, &gpio_init);
343

    
344
  /* initialize SYS_WARMST_N and let it go (active) */
345
  GPIO_SetBits(SYS_WARMRST_N_GPIO, SYS_WARMRST_N_PIN);
346
  gpio_init.GPIO_Pin    = SYS_WARMRST_N_PIN;
347
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
348
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
349
  GPIO_Init(SYS_WARMRST_N_GPIO, &gpio_init);
350

    
351
  /* initialize SYS_UART_UP and let it go (inactive) */
352
  GPIO_SetBits(SYS_UART_UP_GPIO, SYS_UART_UP_PIN);
353
  gpio_init.GPIO_Pin    = SYS_UART_UP_PIN;
354
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
355
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
356
  GPIO_Init(SYS_UART_UP_GPIO, &gpio_init);
357

    
358
  /* initialize PATH_DCEN and pull it down (inactive) */
359
  GPIO_ResetBits(PATH_DCEN_GPIO, PATH_DCEN_PIN);
360
  gpio_init.GPIO_Pin    = PATH_DCEN_PIN;
361
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_PP;
362
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
363
  GPIO_Init(PATH_DCEN_GPIO, &gpio_init);
364

    
365
  /*
366
   * INPUTS
367
   */
368

    
369
  /* initialize the input ACCEL_INT_N */
370
  gpio_init.GPIO_Pin    = ACCEL_INT_N_PIN;
371
  gpio_init.GPIO_Mode   = GPIO_Mode_IN_FLOATING;
372
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
373
  GPIO_Init(ACCEL_INT_N_GPIO, &gpio_init);
374

    
375
  return;
376
} /*** end of initGpio ***/
377

    
378
/*
379
 * Initialize all EXTI lines
380
 */
381
static void initExti() {
382
  /* configure EXTI lines */
383
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource1); // SYS_SYNC_N
384
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource2); // SYS_WARMRST_N
385
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource3); // PATH_DCSTAT
386
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource5); // COMPASS_DRDY
387
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource8); // SYS_PD_N
388
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource9); // SYS_REG_EN
389
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource12); // IR_INT
390
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource13); // GYRO_DRDY
391
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14); // SYS_UART_UP
392
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource15); // ACCEL_INT_N
393

    
394
  return;
395
}
396

    
397
/*
398
 * Signals, which type of low-power mode the system shall enter after the shutdown sequence.
399
 */
400
ErrorStatus shutdownDisambiguationProcedure(const uint8_t type) {
401
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
402
  ErrorStatus ret_val = ERROR;
403

    
404
  switch (type) {
405
    case BL_SHUTDOWN_PRI_RSN_UNKNOWN:
406
    case BL_SHUTDOWN_PRI_RSN_HIBERNATE:
407
    case BL_SHUTDOWN_PRI_RSN_DEEPSLEEP:
408
    case BL_SHUTDOWN_PRI_RSN_TRANSPORT:
409
    {
410
      // broadcast a number of pulses, depending on the argument
411
      uint8_t pulse_counter = 0;
412
      for (pulse_counter = 0; pulse_counter < type; ++pulse_counter) {
413
        msleep(1);
414
        GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
415
        msleep(1);
416
        GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
417
      }
418
      // wait for timeout
419
      msleep(10);
420
      ret_val = SUCCESS;
421
      break;
422
    }
423
    case BL_SHUTDOWN_PRI_RSN_RESTART:
424
    {
425
      // since there is no ambiguity for restart requests, no pulses are generated
426
      msleep(10);
427
      ret_val = SUCCESS;
428
      break;
429
    }
430
    default:
431
      ret_val = ERROR;
432
      break;
433
  }
434

    
435
  return ret_val;
436
} /*** end of shutdownDisambiguationProcedure ***/
437

    
438
/*
439
 * Final shutdown of the system to enter transportation mode.
440
 */
441
void shutdownToTransportation(const blt_bool exec_disambiguation) {
442
  /* configure some criticpal GPIOs as input
443
   * This is required, because otherwise some hardware might be powered through these signals */
444
  configGpioForShutdown();
445

    
446
  /* turn off the motors */
447
  GPIO_ResetBits(POWER_EN_GPIO, POWER_EN_PIN);
448

    
449
  /* deactivate the WKUP pin */
450
  PWR_WakeUpPinCmd(DISABLE);
451

    
452
  /* deactivate any RTC related events */
453
  RTC_ITConfig(RTC_IT_ALR | RTC_IT_OW | RTC_IT_SEC, DISABLE);
454
  RTC_ClearFlag(~0);
455

    
456
  /* disable the IWDG */
457
  IWDG_ReloadCounter();
458

    
459
  /* wait for all boards to be ready for shutdown */
460
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
461
  if (GPIO_ReadInputDataBit(SYS_REG_EN_GPIO, SYS_REG_EN_PIN) == Bit_SET) {
462
    // this must skipped if the pullup voltage (VIO3.3) is not active
463
    setLed(BLT_TRUE);
464
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
465
    setLed(BLT_FALSE);
466
  }
467

    
468
  if (exec_disambiguation == BLT_TRUE) {
469
    /* execute disambiguation procedure and signal all modules to enter transportation mode */
470
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_TRANSPORT) != SUCCESS) {
471
      blinkSOS(1);
472
      msleep(10);
473
    }
474
  }
475

    
476
  /* morse 'OK' via the LED to signal that shutdown was successful */
477
  blinkOK(1);
478

    
479
  /* enter standby mode */
480
  PWR_EnterSTANDBYMode();
481

    
482
  return;
483
} /*** end of shutdownToTransportation ***/
484

    
485
/*
486
 * Final shutdown of the system to enter deepseleep mode.
487
 */
488
void shutdownToDeepsleep(const blt_bool exec_disambiguation) {
489
  /* configure some criticpal GPIOs as input
490
   * This is required, because otherwise some hardware might be powered through these signals */
491
  configGpioForShutdown();
492

    
493
  /* turn off the motors */
494
  GPIO_ResetBits(POWER_EN_GPIO, POWER_EN_PIN);
495

    
496
  /* deactivate the WKUP pin */
497
  PWR_WakeUpPinCmd(ENABLE);
498

    
499
  /*
500
   * Configuration of RTC and IWDG belongs to the OS.
501
   */
502

    
503
  /* wait for all boards to be ready for shutdown */
504
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
505
  if (GPIO_ReadInputDataBit(SYS_REG_EN_GPIO, SYS_REG_EN_PIN) == Bit_SET) {
506
    // this must skipped if the pullup voltage (VIO3.3) is not active
507
    setLed(BLT_TRUE);
508
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
509
    setLed(BLT_FALSE);
510
  }
511

    
512
  if (exec_disambiguation == BLT_TRUE) {
513
    /* execute disambiguation procedure and signal all modules to enter deepsleep mode */
514
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_DEEPSLEEP) != SUCCESS) {
515
      blinkSOS(1);
516
      msleep(10);
517
    }
518
  }
519

    
520
  /* morse 'OK' via the LED to signal that shutdown was successful */
521
  blinkOK(1);
522

    
523
  /* enter standby mode */
524
  PWR_EnterSTANDBYMode();
525

    
526
  return;
527
} /*** end of shutdownToDeepsleep ***/
528

    
529
/*
530
 * Final shutdown of the system to enter hibernate mode.
531
 */
532
void shutdownToHibernate(const blt_bool exec_disambiguation) {
533
  /* configure some criticpal GPIOs as input
534
   * This is required, because otherwise some hardware might be powered through these signals */
535
  configGpioForShutdown();
536

    
537
  /* turn off the motors */
538
  GPIO_ResetBits(POWER_EN_GPIO, POWER_EN_PIN);
539

    
540
  /* deactivate the WKUP pin */
541
  PWR_WakeUpPinCmd(ENABLE);
542

    
543
  /*
544
   * Configuration of RTC and IWDG belongs to the OS.
545
   */
546

    
547
  /* wait for all boards to be ready for shutdown */
548
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
549
  if (GPIO_ReadInputDataBit(SYS_REG_EN_GPIO, SYS_REG_EN_PIN) == Bit_SET) {
550
    // this must skipped if the pullup voltage (VIO3.3) is not active
551
    setLed(BLT_TRUE);
552
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
553
    setLed(BLT_FALSE);
554
  }
555

    
556
  if (exec_disambiguation == BLT_TRUE) {
557
    /* execute disambiguation procedure and signal all modules to enter deepsleep mode */
558
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_HIBERNATE) != SUCCESS) {
559
      blinkSOS(1);
560
      msleep(10);
561
    }
562
  }
563

    
564
  /* morse 'OK' via the LED to signal that shutdown was successful */
565
  blinkOK(1);
566

    
567
  /* enter standby mode */
568
  PWR_EnterSTANDBYMode();
569

    
570
  return;
571
} /* end of shutdownToHibernate ***/
572

    
573
/*
574
 * Final shutdown of the system and restart.
575
 */
576
void shutdownAndRestart(const blt_bool exec_disambiguation) {
577
  /* configure some criticpal GPIOs as input
578
   * This is required, because otherwise some hardware might be powered through these signals */
579
  configGpioForShutdown();
580

    
581
  /* turn off the motors */
582
  GPIO_ResetBits(POWER_EN_GPIO, POWER_EN_PIN);
583

    
584
  /* prepare for low-power mode */
585
  PWR_WakeUpPinCmd(DISABLE); // disable WKUP pin
586
  RTC_ITConfig(RTC_IT_ALR | RTC_IT_OW | RTC_IT_SEC, DISABLE); // unset RTC events
587
  RTC_ClearFlag(~0); // clear pending RTC events
588
  IWDG_ReloadCounter(); // disable IWDG
589

    
590
  /* wait for all boards to be ready for shutdown */
591
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
592
  if (GPIO_ReadInputDataBit(SYS_REG_EN_GPIO, SYS_REG_EN_PIN) == Bit_SET) {
593
    // this must skipped if the pullup voltage (VIO3.3) is not active
594
    setLed(BLT_TRUE);
595
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
596
    setLed(BLT_FALSE);
597
  }
598

    
599
  if (exec_disambiguation == BLT_TRUE) {
600
    /* execute disambiguation procedure and signal all modules to restart in default mode */
601
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_RESTART) != SUCCESS) {
602
      blinkSOS(1);
603
      msleep(10);
604
    }
605
  }
606

    
607
  /* morse 'OK' via the LED to signal that shutdown was successful */
608
  blinkOK(1);
609

    
610
  /* enter standby mode */
611
  PWR_EnterSTANDBYMode();
612

    
613
  /*
614
   * Even though this module will not restart the system by its own, the PowerManagement will reset the system.
615
   */
616

    
617
  return;
618
} /*** end of shutdownAndRestart***/
619

    
620
/*
621
 * Configures some GPIO pins as inputs for safety reasons.
622
 * Under certain circumstances, these pins might power hardware that is supposed to be shut down.
623
 */
624
void configGpioForShutdown() {
625
  /* setup the configuration */
626
  GPIO_InitTypeDef gpio_init;
627
  gpio_init.GPIO_Mode   = GPIO_Mode_IN_FLOATING;
628
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
629

    
630
  /* configure SYS_UART_TX */
631
  gpio_init.GPIO_Pin = SYS_UART_TX_PIN;
632
  GPIO_Init(SYS_UART_TX_GPIO, &gpio_init);
633

    
634
  /* configure CAN_TX */
635
  gpio_init.GPIO_Pin = CAN_TX_PIN;
636
  GPIO_Init(CAN_TX_GPIO, &gpio_init);
637

    
638
  /* configure all MOTION (SPI) signals */
639
  gpio_init.GPIO_Pin = MOTION_SCLK_PIN;
640
  GPIO_Init(MOTION_SCLK_GPIO, &gpio_init);
641
  gpio_init.GPIO_Pin = MOTION_MISO_PIN;
642
  GPIO_Init(MOTION_MISO_GPIO, &gpio_init);
643
  gpio_init.GPIO_Pin = MOTION_MOSI_PIN;
644
  GPIO_Init(MOTION_MOSI_GPIO, &gpio_init);
645
  gpio_init.GPIO_Pin = ACCEL_SS_N_PIN;
646
  GPIO_Init(ACCEL_SS_N_GPIO, &gpio_init);
647
  gpio_init.GPIO_Pin = GYRO_SS_N_PIN;
648
  GPIO_Init(GYRO_SS_N_GPIO, &gpio_init);
649

    
650
  return;
651
} /*** end of configGpioForShutdown ***/
652

    
653
/*
654
 * System was reset via the NRST pin or the reason could not be detected.
655
 * In this case, there are three possibilities how to act:
656
 * 1) When the SYS_WARMRST_N signal becomes inactive, flashing mode is entered and the system will try to load the OS.
657
 * 2) When the SYS_UART_UP signal becomes active (low), the system will enter hibernate mode to enable charging via the pins.
658
 * 3) If none of both happens and a timeout occurs, the system enters deepsleep mode.
659
 */
660
ErrorStatus handleColdReset() {
661
  /* wait until either the SYS_WARMRST_N signal goes up, or SYS_UART_UP goes down */
662
  enum CRST_SIG {CRST_SIG_SYS_WARMRST_N,
663
                 CRST_SIG_SYS_UART_UP,
664
                 CRST_SIG_TIMEOUT
665
                } sig;
666
  uint32_t loopStartTime = 0;
667
  saTimerUpdate(&loopStartTime);
668
  uint32_t currentTime = loopStartTime;
669
  setLed(BLT_TRUE);
670
  while (1) {
671
    /* read the input signals */
672
    if (GPIO_ReadInputDataBit(SYS_REG_EN_GPIO, SYS_REG_EN_PIN) == Bit_SET &&
673
        GPIO_ReadInputDataBit(SYS_WARMRST_N_GPIO, SYS_WARMRST_N_PIN) == Bit_SET) {
674
      sig = CRST_SIG_SYS_WARMRST_N;
675
      break;
676
    }
677
    if (GPIO_ReadInputDataBit(SYS_UART_UP_GPIO, SYS_UART_UP_PIN) == Bit_RESET) {
678
      sig = CRST_SIG_SYS_UART_UP;
679
      break;
680
    }
681

    
682
    /* check for a timeout */
683
    saTimerUpdate(&currentTime);
684
    if (currentTime > loopStartTime + RESET_TIMEOUT_MS) {
685
      sig = CRST_SIG_TIMEOUT;
686
      break;
687
    }
688
  }
689
  setLed(BLT_FALSE);
690

    
691
  /* depending on the signal, react accordingly */
692
  switch (sig) {
693
    /* activation of the slave modules signales to boot the OS */
694
    case CRST_SIG_SYS_WARMRST_N:
695
    {
696
      /* enable CAN clock */
697
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
698

    
699
      /* initialize the bootloader */
700
      BootInit();
701

    
702
      /* start the infinite program loop */
703
      uint32_t loopStartTime = 0;
704
      saTimerUpdate(&loopStartTime);
705
      uint32_t currentTime = loopStartTime;
706
      while (1)
707
      {
708
//        /* make the LED "double-blink" */
709
//        saTimerUpdate(&currentTime);
710
//        if (currentTime < loopStartTime + 50) {
711
//          setLed(BLT_TRUE);
712
//        } else if (currentTime < loopStartTime + 50+100) {
713
//          setLed(BLT_FALSE);
714
//        } else if (currentTime < loopStartTime + 50+100+50) {
715
//          setLed(BLT_TRUE);
716
//        } else if ( currentTime < loopStartTime + 50+100+50+300) {
717
//          setLed(BLT_FALSE);
718
//        } else {
719
//          loopStartTime = currentTime;
720
//        }
721

    
722
        /* run the bootloader task */
723
        BootTask();
724

    
725
        /* check the SYS_PD_N signal */
726
        if (GPIO_ReadInputDataBit(SYS_PD_N_GPIO, SYS_PD_N_PIN) == Bit_RESET) {
727
          blCallbackHandleShutdownRequest();
728
          return SUCCESS;
729
        }
730
      }
731

    
732
      break;
733
    }
734
    /* activation of the UART_UP signal indicates that this module shall enter hibernate mode */
735
    case CRST_SIG_SYS_UART_UP:
736
    {
737
      /* indicate that the MCU is busy */
738
      GPIO_ResetBits(SYS_UART_UP_GPIO, SYS_UART_UP_PIN);
739

    
740
      /* enable the charging pins */
741
      GPIO_SetBits(PATH_DCEN_GPIO, PATH_DCEN_PIN);
742

    
743
      /* wait some time so the systen voltage (VSYS) is stable if it is supplied via the pins */
744
      msleep(10);
745

    
746
      /* indicate that the MCU is not busy anymore */
747
      GPIO_SetBits(SYS_UART_UP_GPIO, SYS_UART_UP_PIN);
748

    
749
      /* configure the accelerometer external interrupt as event */
750
      EXTI_InitTypeDef exti;
751
      exti.EXTI_Line = EXTI_Line15;
752
      exti.EXTI_Mode = EXTI_Mode_Event;
753
      exti.EXTI_Trigger = EXTI_Trigger_Falling;
754
      exti.EXTI_LineCmd = ENABLE;
755
      EXTI_Init(&exti);
756

    
757
      /* sleep until something happens */
758
      __WFE();
759

    
760
      /* clear all pending EXTI events */
761
      EXTI_DeInit();
762
      EXTI_ClearFlag(EXTI_Line15);
763

    
764
      /* handle accelerometer wakeup
765
       * note: In fact, the only events that will occur at this point are an interrupt event from the accelerometer, or a
766
       * system reset from the PowerManagement via the NRST pin. Thus, if the following code is reached, it must have
767
       * been the accelerometer.
768
       */
769

    
770
      /* as as after a normal wakeup from the accelerometer */
771
      return handleAccelWakeup();
772

    
773
      break;
774
    }
775
    /* if a timeout occurred, the system enters deepsleep mode */
776
    case CRST_SIG_TIMEOUT:
777
    {
778
      /* reconfigure the LED_GPIO as input so it will not light up (and thus save energy) */
779
      GPIO_InitTypeDef gpio_init;
780
      gpio_init.GPIO_Pin    = LED_PIN;
781
      gpio_init.GPIO_Mode   = GPIO_Mode_IN_FLOATING;
782
      gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
783
      GPIO_Init(LED_GPIO, &gpio_init);
784

    
785
      /* reconfigure SYS_PD_N as input so the callback will not indicate a shutdown */
786
      gpio_init.GPIO_Pin    = SYS_PD_N_PIN;
787
      gpio_init.GPIO_Mode   = GPIO_Mode_IN_FLOATING;
788
      gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
789
      GPIO_Init(SYS_PD_N_GPIO, &gpio_init);
790

    
791
      blCallbackShutdownDeepsleep();
792
      break;
793
    }
794
    default:
795
      break;
796
  }
797

    
798
  return ERROR;
799
} /*** end of handleColdReset ***/
800

    
801
/*
802
 * System was woken up via the WKUP pin and the SYS_UART_UP signal was found to be responsible.
803
 * In this case, the system starts as after a cold reset.
804
 */
805
ErrorStatus handleUartWakeup() {
806
  return handleColdReset();
807
} /*** end of handleUartWakeup ***/
808

    
809
/*
810
 * System was woken up via the WKUP pin and the ACCEL_INT_N signal was found to be responsible.
811
 * The SYS_UART_UP signal is used to wake the PowerManagement before a normal cold reset is performed.
812
 */
813
ErrorStatus handleAccelWakeup() {
814
  /* wakeup the PowerManegement (ensure that the pulse is detected) */
815
  GPIO_ResetBits(SYS_UART_UP_GPIO, SYS_UART_UP_PIN);
816
  msleep(1);
817
  GPIO_SetBits(SYS_UART_UP_GPIO, SYS_UART_UP_PIN);
818

    
819
  return handleColdReset();
820
} /*** end of handleAccelWakeu ***/
821

    
822
/*
823
 * Callback function that handles the system shutdown and enters transportation mode.
824
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
825
 * In transportation low-power mode the system can only be woken up by pulling down the NRST signal.
826
 * Furthermore, the system can not be charged when in transportation mode.
827
 */
828
void blCallbackShutdownTransportation(void) {
829
  /* make sure that the required clocks are activated */
830
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
831
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
832

    
833
  /* set/keep the SYS_SYNC and SYS_PD signals active */
834
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
835
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
836

    
837
  setLed(BLT_TRUE);
838
  saTimerInit();
839

    
840
  shutdownToTransportation(BLT_TRUE);
841

    
842
  return;
843
} /*** end of blCallbackShutdownTransportation ***/
844

    
845
/*
846
 * Callback function that handles the system shutdown and enters deepsleep mode.
847
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
848
 * In deepsleep low-power mode the system can only be woken up via the NRST or the WKUP signal, or the RTC or IWDG, if configured.
849
 */
850
void blCallbackShutdownDeepsleep(void) {
851
  /* make sure that the required clocks are activated */
852
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
853
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
854

    
855
  /* set/keep the SYS_SYNC and SYS_PD signals active */
856
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
857
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
858

    
859
  saTimerInit();
860

    
861
  shutdownToDeepsleep(BLT_TRUE);
862

    
863
  return;
864
} /*** end of blCallbackShutdownDeepsleep ***/
865

    
866
/*
867
 * Callback function that handles the system shutdown and enters hibernate mode.
868
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
869
 */
870
void blCallbackShutdownHibernate(void) {
871
  /* make sure that the required clocks are activated */
872
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
873
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
874

    
875
  /* set/keep the SYS_SYNC and SYS_PD signals active */
876
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
877
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
878

    
879
  saTimerInit();
880

    
881
  shutdownToHibernate(BLT_TRUE);
882

    
883
  return;
884
} /*** end of blCallbackShutdownHibernate ***/
885

    
886
/*
887
 * Callback function that handles the system shutdown and initializes a restart.
888
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
889
 */
890
void blCallbackShutdownRestart(void) {
891
  /* make sure that the required clocks are activated */
892
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
893
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
894

    
895
  /* set/keep the SYS_SYNC and SYS_PD signal active */
896
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
897
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
898

    
899
  /* ensure that all modules had a chance to detect the pulse on SYS_PD_N */
900
  saTimerInit();
901
  msleep(1);
902
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
903
  msleep(1);
904

    
905
  shutdownAndRestart(BLT_TRUE);
906

    
907
  return;
908
} /*** end of blCallbackRestart ***/
909

    
910
/*
911
 * Callback function that handles a system shutdown/restart request from another module.
912
 * Depending on the result of the disambiguation procedure, the module will enter the according low-power mode or restart.
913
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
914
 */
915
void blCallbackHandleShutdownRequest(void) {
916
  /* make sure that the required clocks are activated */
917
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
918
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
919

    
920
  /* set/keep the SYS_SYNC and SYS_PD signal active */
921
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
922
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
923

    
924
  /* initialized the standalone timer */
925
  saTimerInit();
926

    
927
  setLed(BLT_TRUE);
928

    
929
  /* deactivate SYS_PD_N and ensure that all modules had a chance to detect the falling edge */
930
  msleep(1);
931
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
932
  msleep(1);
933

    
934
  /* wait for all boards to be ready for shutdown */
935
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
936
  if (GPIO_ReadOutputDataBit(SYS_REG_EN_GPIO, SYS_REG_EN_PIN) == Bit_SET) {
937
    // this must skipped if the pullup voltage (VIO3.3) is not active
938
    setLed(BLT_TRUE);
939
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
940
    setLed(BLT_FALSE);
941
  }
942

    
943
  /* check ths SYS_PD_N signal, whether the system shall shutdown or restart */
944
  blt_bool shutdown_nrestart = (GPIO_ReadInputDataBit(SYS_PD_N_GPIO, SYS_PD_N_PIN) == Bit_RESET) ? BLT_TRUE : BLT_FALSE;
945

    
946
  /* disambiguation procedure (passive) */
947
  uint32_t pulse_counter = 0;
948
  while (waitForSignalTimeout(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_RESET, 10)) {
949
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
950
    ++pulse_counter;
951
  }
952

    
953
  /* evaluate and hanlde disambiguation result */
954
  if (shutdown_nrestart == BLT_TRUE) {
955
    /* shutdown request */
956

    
957
    /* handle special cases */
958
    if (pulse_counter == BL_SHUTDOWN_PRI_RSN_UNKNOWN) {
959
      /* no pulse at all was received */
960
      pulse_counter = BL_SHUTDOWN_PRI_RSN_DEFAULT;
961
    } else if (pulse_counter != BL_SHUTDOWN_PRI_RSN_HIBERNATE &&
962
               pulse_counter != BL_SHUTDOWN_PRI_RSN_DEEPSLEEP &&
963
               pulse_counter != BL_SHUTDOWN_PRI_RSN_TRANSPORT) {
964
      /* invalid number of pulses received */
965
      blinkSOS(1);
966
      pulse_counter = BL_SHUTDOWN_PRI_RSN_DEFAULT;
967
    }
968

    
969
    switch (pulse_counter) {
970
      case BL_SHUTDOWN_PRI_RSN_HIBERNATE:
971
        shutdownToHibernate(BLT_FALSE);
972
        break;
973
      case BL_SHUTDOWN_PRI_RSN_DEEPSLEEP:
974
        shutdownToDeepsleep(BLT_FALSE);
975
        break;
976
      case BL_SHUTDOWN_PRI_RSN_TRANSPORT:
977
        shutdownToTransportation(BLT_FALSE);
978
        break;
979
    }
980
  } else {
981
    /* restart request */
982

    
983
    /* there is no ambiguity for restart, so it is ignored */
984
    shutdownAndRestart(BLT_FALSE);
985
  }
986

    
987
  /* if this code is reached, the system did neither shut down, nor restart.
988
   * This must never be the case!
989
   */
990
  blinkSOSinf();
991
  return;
992
} /*** end of blCallbackHandleShutdownRequest ***/
993

    
994
/*********************************** end of main.c *************************************/