Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (36.264 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 and static variables
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_Beta, BL_VERSION_MAJOR, BL_VERSION_MINOR, 3},
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
** \brief     This is the entry point for the bootloader application and is called
100
**            by the reset interrupt vector after the C-startup routines executed.
101
** \return    Program return code.
102
**
103
****************************************************************************************/
104
int main(void)
105
{
106
  /* initialize the microcontroller */
107
  Init();
108

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

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

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

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

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

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

    
146
  setLed(BLT_FALSE);
147

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

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

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

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

    
184

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

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

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

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

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

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

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

    
317
  /*
318
   * OUTPUTS
319
   */
320

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

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

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

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

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

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

    
363
  /*
364
   * INPUTS
365
   */
366

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

    
373
  return;
374
} /*** end of initGpio ***/
375

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

    
392
  return;
393
} /*** end of initExti ***/
394

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

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

    
433
  return ret_val;
434
} /*** end of shutdownDisambiguationProcedure ***/
435

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

    
444
  /* turn off the motors */
445
  GPIO_ResetBits(POWER_EN_GPIO, POWER_EN_PIN);
446

    
447
  /* deactivate the WKUP pin */
448
  PWR_WakeUpPinCmd(DISABLE);
449

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

    
454
  /* disable the IWDG */
455
  IWDG_ReloadCounter();
456

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

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

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

    
477
  /* enter standby mode */
478
  PWR_EnterSTANDBYMode();
479

    
480
  return;
481
} /*** end of shutdownToTransportation ***/
482

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

    
491
  /* turn off the motors */
492
  GPIO_ResetBits(POWER_EN_GPIO, POWER_EN_PIN);
493

    
494
  /* deactivate the WKUP pin */
495
  PWR_WakeUpPinCmd(ENABLE);
496

    
497
  /*
498
   * Configuration of RTC and IWDG belongs to the OS.
499
   */
500

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

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

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

    
521
  /* enter standby mode */
522
  PWR_EnterSTANDBYMode();
523

    
524
  return;
525
} /*** end of shutdownToDeepsleep ***/
526

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

    
535
  /* turn off the motors */
536
  GPIO_ResetBits(POWER_EN_GPIO, POWER_EN_PIN);
537

    
538
  /* deactivate the WKUP pin */
539
  PWR_WakeUpPinCmd(ENABLE);
540

    
541
  /*
542
   * Configuration of RTC and IWDG belongs to the OS.
543
   */
544

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

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

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

    
565
  /* enter standby mode */
566
  PWR_EnterSTANDBYMode();
567

    
568
  return;
569
} /*** end of shutdownToHibernate ***/
570

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

    
579
  /* turn off the motors */
580
  GPIO_ResetBits(POWER_EN_GPIO, POWER_EN_PIN);
581

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

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

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

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

    
608
  /* enter standby mode */
609
  PWR_EnterSTANDBYMode();
610

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

    
615
  return;
616
} /*** end of shutdownAndRestart ***/
617

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

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

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

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

    
648
  return;
649
} /*** end of configGpioForShutdown ***/
650

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

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

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

    
697
      /* initialize the bootloader */
698
      BootInit();
699

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

    
720
        /* run the bootloader task */
721
        BootTask();
722

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

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

    
738
      /* enable the charging pins */
739
      GPIO_SetBits(PATH_DCEN_GPIO, PATH_DCEN_PIN);
740

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

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

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

    
755
      /* sleep until something happens */
756
      __WFE();
757

    
758
      /* clear all pending EXTI events */
759
      EXTI_DeInit();
760
      EXTI_ClearFlag(EXTI_Line15);
761

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

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

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

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

    
789
      blCallbackShutdownDeepsleep();
790
      break;
791
    }
792
    default:
793
      break;
794
  }
795

    
796
  return ERROR;
797
} /*** end of handleColdReset ***/
798

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

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

    
817
  return handleColdReset();
818
} /*** end of handleAccelWakeu ***/
819

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

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

    
835
  /* initialized the standalone timer */
836
  saTimerInit();
837

    
838
  setLed(BLT_TRUE);
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
  /* initialized the standalone timer */
860
  saTimerInit();
861

    
862
  setLed(BLT_TRUE);
863

    
864
  shutdownToDeepsleep(BLT_TRUE);
865

    
866
  return;
867
} /*** end of blCallbackShutdownDeepsleep ***/
868

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

    
878
  /* set/keep the SYS_SYNC and SYS_PD signals active */
879
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
880
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
881

    
882
  /* initialized the standalone timer */
883
  saTimerInit();
884

    
885
  setLed(BLT_TRUE);
886

    
887
  shutdownToHibernate(BLT_TRUE);
888

    
889
  return;
890
} /*** end of blCallbackShutdownHibernate ***/
891

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

    
901
  /* set/keep the SYS_SYNC and SYS_PD signals active */
902
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
903
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
904

    
905
  /* initialized the standalone timer */
906
  saTimerInit();
907

    
908
  setLed(BLT_TRUE);
909

    
910
  /* deactivate SYS_PD_N and ensure that all modules had a chance to detect the falling edge */
911
  msleep(1);
912
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
913
  msleep(1);
914

    
915
  shutdownAndRestart(BLT_TRUE);
916

    
917
  return;
918
} /*** end of blCallbackRestart ***/
919

    
920
/*
921
 * Callback function that handles a system shutdown/restart request from another module.
922
 * Depending on the result of the disambiguation procedure, the module will enter the according low-power mode or restart.
923
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
924
 */
925
void blCallbackHandleShutdownRequest(void) {
926
  /* make sure that the required clocks are activated */
927
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
928
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
929

    
930
  /* set/keep the SYS_SYNC and SYS_PD signals active */
931
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
932
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
933

    
934
  /* initialized the standalone timer */
935
  saTimerInit();
936

    
937
  setLed(BLT_TRUE);
938

    
939
  /* deactivate SYS_PD_N and ensure that all modules had a chance to detect the falling edge */
940
  msleep(1);
941
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
942
  msleep(1);
943

    
944
  /* wait for all boards to be ready for shutdown */
945
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
946
  if (GPIO_ReadOutputDataBit(SYS_REG_EN_GPIO, SYS_REG_EN_PIN) == Bit_SET) {
947
    // this must be skipped if the pullup voltage (VIO3.3) is not active
948
    setLed(BLT_TRUE);
949
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
950
    setLed(BLT_FALSE);
951
  }
952

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

    
956
  /* disambiguation procedure (passive) */
957
  uint32_t pulse_counter = 0;
958
  while (waitForSignalTimeout(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_RESET, 10)) {
959
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
960
    ++pulse_counter;
961
  }
962

    
963
  /* evaluate and hanlde disambiguation result */
964
  if (shutdown_nrestart == BLT_TRUE) {
965
    /* shutdown request */
966

    
967
    /* handle special cases */
968
    if (pulse_counter == BL_SHUTDOWN_PRI_RSN_UNKNOWN) {
969
      /* no pulse at all was received */
970
      pulse_counter = BL_SHUTDOWN_PRI_RSN_DEFAULT;
971
    } else if (pulse_counter != BL_SHUTDOWN_PRI_RSN_HIBERNATE &&
972
               pulse_counter != BL_SHUTDOWN_PRI_RSN_DEEPSLEEP &&
973
               pulse_counter != BL_SHUTDOWN_PRI_RSN_TRANSPORT) {
974
      /* invalid number of pulses received */
975
      blinkSOS(1);
976
      pulse_counter = BL_SHUTDOWN_PRI_RSN_DEFAULT;
977
    }
978

    
979
    switch (pulse_counter) {
980
      case BL_SHUTDOWN_PRI_RSN_HIBERNATE:
981
        shutdownToHibernate(BLT_FALSE);
982
        break;
983
      case BL_SHUTDOWN_PRI_RSN_DEEPSLEEP:
984
        shutdownToDeepsleep(BLT_FALSE);
985
        break;
986
      case BL_SHUTDOWN_PRI_RSN_TRANSPORT:
987
        shutdownToTransportation(BLT_FALSE);
988
        break;
989
    }
990
  } else {
991
    /* restart request */
992

    
993
    /* there is no ambiguity for restart, so it is ignored */
994
    shutdownAndRestart(BLT_FALSE);
995
  }
996

    
997
  /* if this code is reached, the system did neither shut down, nor restart.
998
   * This must never be the case!
999
   */
1000
  blinkSOSinf();
1001
  return;
1002
} /*** end of blCallbackHandleShutdownRequest ***/
1003

    
1004
/*********************************** end of main.c *************************************/