Statistics
| Branch: | Tag: | Revision:

amiro-os / devices / PowerManagement / main.cpp @ 5b1b6715

History | View | Annotate | Download (41.726 KB)

1
#ifndef IN_CCM
2
/*
3
 * @brief Makro to store data in the core coupled memory (ccm).
4
 *        Example:
5
 *        int compute_buffer[128] IN_CCM;
6
 *
7
 * @note The ccm is not connected to any bus system.
8
 */
9
#define IN_CCM  __attribute__((section(".ccm"))) __attribute__((aligned(4)))
10
#endif
11

    
12
#ifndef IN_ETH
13
/*
14
 * @brief Makro to store data in the ethernet memory (eth).
15
 *        Example:
16
 *        int dma_buffer[128] IN_ETH;
17
 *
18
 * @note The eth is a dedicated memory block with its own DMA controller.
19
 */
20
#define IN_ETH  __attribute__((section(".eth"))) __attribute__((aligned(4)))
21
#endif
22

    
23
#define BL_CALLBACK_TABLE_ADDR  (0x08000000 + 0x01C0)
24
#define BL_MAGIC_NUMBER         ((uint32_t)0xFF669900u)
25

    
26
#define SHUTDOWN_NONE             0
27
#define SHUTDOWN_TRANSPORTATION   1
28
#define SHUTDOWN_DEEPSLEEP        2
29
#define SHUTDOWN_HIBERNATE        3
30
#define SHUTDOWN_RESTART          4
31
#define SHUTDOWN_HANDLE_REQUEST   5
32

    
33
#include <ch.hpp>
34
#include <shell.h>
35
#include <chprintf.h>
36
#include <wakeup.h>
37
#include <cstdlib>
38
#include <cstring>
39
#include <amiro/util/util.h>
40
#include <global.hpp>
41
#include <exti.hpp>
42

    
43
using namespace amiro;
44
using namespace constants::PowerManagement;
45

    
46
Global global;
47

    
48
struct blVersion_t {
49
  const uint8_t identifier;
50
  const uint8_t major;
51
  const uint8_t minor;
52
  const uint8_t patch;
53
} __attribute__((packed));
54

    
55
void shutdownTimeoutISR(void *arg) {
56

    
57
  (void) arg;
58

    
59
}
60

    
61
void systemStop() {
62

    
63
//  VirtualTimer shutdownTimeout;
64
  uint8_t i;
65

    
66
  // tell all boards that it's time to shut down
67
  global.robot.broadcastShutdown();
68

    
69
  global.userThread.requestTerminate();
70
  global.userThread.wait();
71

    
72
  // kill bluetooth
73
  boardBluetoothSetState(0);
74

    
75
  global.adc1_vsys.requestTerminate();
76
  global.adc1_vsys.wait();
77

    
78
  for (i = 0; i < global.vcnl4020.size(); ++i) {
79
    global.vcnl4020[i].requestTerminate();
80
    global.vcnl4020[i].wait();
81
  }
82

    
83
  for (i = 0; i < global.bq27500.size(); ++i) {
84
    global.bq27500[i].requestTerminate();
85
    global.bq27500[i].wait();
86
  }
87

    
88
  for (i = 0; i < global.ina219.size(); ++i) {
89
    global.ina219[i].requestTerminate();
90
    global.ina219[i].wait();
91
  }
92

    
93
//  boardWriteIoPower(0);
94
  global.mpr121.configure(&global.mpr121_stdby_config);
95
  /* cannot shut down touch, b/c we need it to
96
   * clear any interrupt, so WKUP is not blocked
97
   */
98

    
99
  // stop I²C
100
  for (i = 0; i < global.V_I2C1.size(); ++i)
101
    global.V_I2C1[i].stop();
102
  for (i = 0; i < global.V_I2C2.size(); ++i)
103
    global.V_I2C2[i].stop();
104

    
105
  global.mpr121.requestTerminate();
106
  global.mpr121.wait();
107

    
108
  global.HW_I2C2.stop();
109
  global.HW_I2C1.stop();
110

    
111
  // stop all threads
112
  global.robot.terminate();
113

    
114
//  // 60 sec timeout
115
//  palWritePad(GPIOC, GPIOC_SYS_INT_N, PAL_HIGH);
116
//  chVTSet(&shutdownTimeout, MS2ST(60000), shutdownTimeoutISR, NULL);
117
//  // wait for all boards to release SYS_INT_N
118
//  while (palReadPad(GPIOC, GPIOC_SYS_INT_N)!=PAL_HIGH && chVTIsArmedI(&shutdownTimeout)) {
119
//    BaseThread::sleep(MS2ST(1)); /* must sleep for VT, else it will never fire */
120
//  }
121
//  chVTReset(&shutdownTimeout);
122

    
123
//  chprintf((BaseSequentialStream*) &SD1, "Stop\n");
124
//  boardWriteSystemPower(0);
125
//  boardWriteLed(1);
126
//  boardStop(0x00, 0x00);
127

    
128
//  /*
129
//   * HSI-PLL domain now.
130
//   */
131
//  //chprintf((BaseSequentialStream*) &SD1, "After Stop\n");
132
//  boardWriteLed(1);
133

    
134
//  while (true)
135
//    BaseThread::sleep(MS2ST(250));
136

    
137
  return;
138
}
139

    
140
void systemShutdown() {
141

    
142
  VirtualTimer shutdownTimeout;
143
  uint8_t i;
144

    
145
  // tell all boards that it's time to shut down
146
  global.robot.broadcastShutdown();
147

    
148
  // wait a little to make sure all boards got the message and had time to pull their SYS_PD_N pins down
149
  BaseThread::sleep(MS2ST(500));
150

    
151
  // stop the user thread
152
  global.userThread.requestTerminate();
153
  global.userThread.wait();
154

    
155
  // kill bluetooth
156
  boardBluetoothSetState(0);
157

    
158
  // stop all threads
159
  global.robot.terminate();
160

    
161
  global.adc1_vsys.requestTerminate();
162
  global.adc1_vsys.wait();
163

    
164
  for (i = 0; i < global.vcnl4020.size(); ++i) {
165
    global.vcnl4020[i].requestTerminate();
166
    global.vcnl4020[i].wait();
167
  }
168

    
169
  for (i = 0; i < global.bq27500.size(); ++i) {
170
    global.bq27500[i].requestTerminate();
171
    global.bq27500[i].wait();
172
  }
173

    
174
  for (i = 0; i < global.ina219.size(); ++i) {
175
    global.ina219[i].requestTerminate();
176
    global.ina219[i].wait();
177
  }
178

    
179
  // 60 sec timeout
180
  chVTSet(&shutdownTimeout, MS2ST(60000), shutdownTimeoutISR, NULL);
181

    
182
  // wait for all boards to release SYS_PD_N
183
  while (!palReadPad(GPIOC, GPIOC_SYS_PD_N) && chVTIsArmedI(&shutdownTimeout))
184
    BaseThread::sleep(MS2ST(1)); /* must sleep for VT, else it will never fire */
185

    
186
  chVTReset(&shutdownTimeout);
187
  boardWriteIoPower(0);
188
  global.mpr121.configure(&global.mpr121_stdby_config);
189
  /* cannot shut down touch, b/c we need it to
190
   * clear any interrupt, so WKUP is not blocked
191
   */
192

    
193
  // stop I²C
194
  for (i = 0; i < global.V_I2C1.size(); ++i)
195
    global.V_I2C1[i].stop();
196
  for (i = 0; i < global.V_I2C2.size(); ++i)
197
    global.V_I2C2[i].stop();
198

    
199
  boardWriteSystemPower(0);
200
  boardStandby();
201

    
202
}
203

    
204

    
205
void boardPeripheryCheck(BaseSequentialStream *chp) {
206

    
207
#ifndef AMIRO_NSELFTEST
208
  chprintf(chp, "\nCHECK: START\n");
209
  msg_t result = 0;
210

    
211
    // Check the proximitysensors
212
  for (uint8_t i = 0; i < global.vcnl4020.size(); i++) {
213
    result = global.vcnl4020[i].getCheck();
214
    if (result == global.vcnl4020[i].CHECK_OK)
215
      chprintf(chp, "VCNL4020: %d OK\n", i);
216
    else
217
      chprintf(chp, "VCNL4020: %d FAIL\n", i);
218
  }
219
  chprintf(chp, "----------------------------------------\n");
220

    
221
  // check the PowerPath controller
222
  chprintf(chp, "\n");
223
  if (global.ltc4412.isPluggedIn())
224
    chprintf(chp, "LTC4412: plugged in\n");
225
  else
226
    chprintf(chp, "LTC4412: not plugged in\n");
227
  chprintf(chp, "----------------------------------------\n");
228

    
229
  // Check the eeprom
230
  result = global.memory.getCheck();
231
  if ( result != global.memory.OK)
232
    chprintf(chp, "Memory Structure: FAIL\n");
233
  else
234
    chprintf(chp, "Memory Structure: OK\n");
235
  chprintf(chp, "----------------------------------------\n");
236

    
237
  // Check the power monitors
238
  INA219::BusVoltage bus_voltage;
239
  chprintf(chp, "\n");
240
  chprintf(chp, "INA219:\n");
241
  chprintf(chp, "\tVDD (3.3V):\n");
242
  uint8_t result_ina219_vdd = global.ina219[INA_VDD].selftest();
243
  chprintf(chp, "->\t");
244
  if (result_ina219_vdd == BaseSensor<>::NOT_IMPLEMENTED)
245
    chprintf(chp, "not implemented");
246
  else if (result_ina219_vdd != INA219::Driver::ST_OK)
247
    chprintf(chp, "FAIL (error code 0x%02X)", result_ina219_vdd);
248
  else
249
    chprintf(chp, "OK");
250

    
251
  chprintf(chp, "\n\n");
252
  chprintf(chp, "\tVIO1.8:\n");
253
  uint8_t result_ina219_vio18 = global.ina219[INA_VIO18].selftest();
254
  chprintf(chp, "->\t");
255
  if (result_ina219_vio18 == BaseSensor<>::NOT_IMPLEMENTED)
256
    chprintf(chp, "not implemented");
257
  else if (result_ina219_vio18 != INA219::Driver::ST_OK)
258
    chprintf(chp, "FAIL (error code 0x%02X)", result_ina219_vio18);
259
  else
260
    chprintf(chp, "OK");
261

    
262
  chprintf(chp, "\n\n");
263
  chprintf(chp, "\tVIO3.3:\n");
264
  uint8_t result_ina219_vio33 = global.ina219[INA_VIO33].selftest();
265
  chprintf(chp, "->\t");
266
  if (result_ina219_vio33 == BaseSensor<>::NOT_IMPLEMENTED)
267
    chprintf(chp, "not implemented");
268
  else if (result_ina219_vio33 != INA219::Driver::ST_OK)
269
    chprintf(chp, "FAIL (error code 0x%02X)", result_ina219_vio33);
270
  else
271
    chprintf(chp, "OK");
272

    
273
  chprintf(chp, "\n\n");
274
  chprintf(chp, "\tVIO4.2:\n");
275
  uint8_t result_ina219_vio42 = global.ina219[INA_VIO42].selftest();
276
  chprintf(chp, "->\t");
277
  if (result_ina219_vio42 == BaseSensor<>::NOT_IMPLEMENTED)
278
    chprintf(chp, "not implemented");
279
  else if (result_ina219_vio42 != INA219::Driver::ST_OK)
280
    chprintf(chp, "FAIL (error code 0x%02X)", result_ina219_vio42);
281
  else
282
    chprintf(chp, "OK");
283

    
284
  bus_voltage = global.ina219[INA_VIO42].readBusVoltage();
285
  chprintf(chp, "\n\n");
286
  chprintf(chp, "\tVIO5.0:\n");
287
  uint8_t result_ina219_vio50 = global.ina219[INA_VIO50].selftest();
288
  chprintf(chp, "->\t");
289
  if (result_ina219_vio50 == BaseSensor<>::NOT_IMPLEMENTED)
290
    chprintf(chp, "not implemented");
291
  else if (result_ina219_vio50 != INA219::Driver::ST_OK)
292
    chprintf(chp, "FAIL (error code 0x%02X)", result_ina219_vio50);
293
  else
294
    chprintf(chp, "OK");
295

    
296
  chprintf(chp, "\n\n");
297
  result = result_ina219_vdd | result_ina219_vio18 | result_ina219_vio33 | result_ina219_vio42 | result_ina219_vio50;
298
  if (result == BaseSensor<>::NOT_IMPLEMENTED)
299
    chprintf(chp, "->\tINA219: not implemented\n");
300
  else
301
    chprintf(chp, "->\tINA219: %s\n", (result != INA219::Driver::ST_OK)? "FAIL" : "OK");
302
  chprintf(chp, "----------------------------------------\n");
303

    
304
  // check the fuel gauges
305
  chprintf(chp, "\n");
306
  chprintf(chp, "BQ27500:\n");
307
  chprintf(chp, "\tP7:\n");
308
  msg_t result_bq27500_p7 = global.bq27500[BAT_P7].selftest();
309
  chprintf(chp, "->\tP7: ");
310
  if (result == BaseSensor<>::NOT_IMPLEMENTED)
311
    chprintf(chp, "not implemented");
312
  else if (result_bq27500_p7 == BQ27500::Driver::ST_ABORT_NO_BAT)
313
    chprintf(chp, "ABORT (no battery detected)");
314
  else if (result_bq27500_p7 != BQ27500::Driver::ST_OK)
315
    chprintf(chp, "FAIL (error code 0x%02X)", result);
316
  else
317
    chprintf(chp, "OK");
318

    
319
  chprintf(chp, "\n\n");
320
  chprintf(chp, "\tP8:\n");
321
  msg_t result_bq27500_p8 = global.bq27500[BAT_P8].selftest();
322
  chprintf(chp, "->\tP8: ");
323
  if (result == BaseSensor<>::NOT_IMPLEMENTED)
324
    chprintf(chp, "not implemented");
325
  else if (result_bq27500_p8 == BQ27500::Driver::ST_ABORT_NO_BAT)
326
      chprintf(chp, "ABORT (no battery detected)");
327
  else if (result_bq27500_p8 != BQ27500::Driver::ST_OK)
328
    chprintf(chp, "FAIL (error code 0x%02X)", result);
329
  else
330
    chprintf(chp, "OK");
331

    
332
  chprintf(chp, "\n");
333
  result = result_bq27500_p7 | result_bq27500_p8;
334
  if (result == BaseSensor<>::NOT_IMPLEMENTED)
335
    chprintf(chp, "\n->\tBQ27500: not implemented\n");
336
  else
337
    chprintf(chp, "\n->\tBQ27500: %s\n", (result != BQ27500::Driver::ST_OK)? "FAIL" : "OK");
338
  chprintf(chp, "----------------------------------------\n");
339

    
340
  // check the chargers
341
  chprintf(chp, "\n");
342
  chprintf(chp, "BQ24103A:\n");
343
  if (!global.ltc4412.isPluggedIn())
344
    chprintf(chp, "This test is skipped. Rerun when plugged in.\n");
345
  else {
346
    bool status1, status2, status3;
347
    chprintf(chp, "\tP7:\n");
348
    bool status_p7 = global.bq27500[BAT_P7].isBatteryGood();
349
    chprintf(chp, "Battery good: %s\n", (status_p7? "yes" : "no"));
350
    if (!status_p7) {
351
      chprintf(chp, "-> Rerun test with (another) battery!\n");
352
      status_p7 = true;
353
    } else {
354
      status1 = global.bq24103a[BAT_P7]->isCharging();
355
      chprintf(chp, "status:%scharging\n", (status1? " " : " not "));
356
      chprintf(chp, "%sabling charger...\n", (status1? "dis" : "en"));
357
      global.bq24103a[BAT_P7]->enable(!status1);
358
      BaseThread::sleep(MS2ST(1500));
359
      status2 = global.bq24103a[BAT_P7]->isCharging();
360
      chprintf(chp, "status:%scharging\n", (status2? " " : " not "));
361
      chprintf(chp, "%sabling charger...\n", (!status1? "dis" : "en"));
362
      global.bq24103a[BAT_P7]->enable(status1);
363
      BaseThread::sleep(MS2ST(1500));
364
      status3 = global.bq24103a[BAT_P7]->isCharging();
365
      chprintf(chp, "status:%scharging\n", (status3? " " : " not "));
366
      status_p7 = status2 != status1 && status3 == status1;
367
      chprintf(chp, "->\t");
368
      if (status_p7) {
369
        chprintf(chp, "OK");
370
      } else {
371
        chprintf(chp, "FAIL");
372
      }
373
      chprintf(chp, "\n");
374
    }
375
    chprintf(chp, "\n");
376
    chprintf(chp, "\tP8:\n");
377
    bool status_p8 = global.bq27500[BAT_P8].isBatteryGood();
378
    chprintf(chp, "Battery good: %s\n", (status_p8? "yes" : "no"));
379
    if (!status_p8) {
380
      chprintf(chp, "-> Rerun test with (another) battery!\n");
381
      status_p8 = true;
382
    } else {
383
      status1 = global.bq24103a[BAT_P8]->isCharging();
384
      chprintf(chp, "status:%scharging\n", (status1? " " : " not "));
385
      chprintf(chp, "%sabling charger...\n", (status1? "dis" : "en"));
386
      global.bq24103a[BAT_P8]->enable(!status1);
387
      BaseThread::sleep(MS2ST(1500));
388
      status2 = global.bq24103a[BAT_P8]->isCharging();
389
      chprintf(chp, "status:%scharging\n", (status2? " " : " not "));
390
      chprintf(chp, "%sabling charger...\n", (!status1? "dis" : "en"));
391
      global.bq24103a[BAT_P8]->enable(status1);
392
      BaseThread::sleep(MS2ST(1500));
393
      status3 = global.bq24103a[BAT_P8]->isCharging();
394
      chprintf(chp, "status:%scharging\n", (status3? " " : "not "));
395
      status_p8 = status2 != status1 && status3 == status1;
396
      chprintf(chp, "->\t");
397
      if (status_p8)
398
        chprintf(chp, "OK");
399
      else
400
        chprintf(chp, "FAIL");
401
      chprintf(chp, "\n");
402
    }
403
    chprintf(chp, "\n");
404
    chprintf(chp, "->\tBQ24103A: ");
405
    if (status_p7 && status_p8)
406
      chprintf(chp, "OK");
407
    else
408
      chprintf(chp, "FAIL");
409
    chprintf(chp, "\n");
410
  }
411
  chprintf(chp, "----------------------------------------\n");
412

    
413
  // check Bluetooth (TODO: move this check to driver)
414
  chprintf(chp, "\n");
415
  chprintf(chp, "WT12-A-AI:\n");
416

    
417
  chprintf(chp, "testing for MUX mode:\t");
418

    
419
  if (global.wt12.bluetoothIsMuxMode()) {
420
    chprintf(chp, "PASSED\n");
421
  } else {
422
    chprintf(chp, "FAILED -> setting MUX mode now\n");
423
    /* initialise the WT-12 bluetooth chip on AMIRO (Please, run this processes once) */
424
    global.wt12.bluetoothSendCommand("SET BT AUTH *");
425
    global.wt12.bluetoothSendCommand("SET BT PAIR *");
426
    global.wt12.bluetoothSendCommand("SET BT SSP 3 0");
427
    global.wt12.bluetoothEnableMux();
428
    global.wt12.bluetoothReset();
429
  }
430

    
431
  global.wt12.bluetoothSendCommand("TEMP");
432
  global.wt12.bluetoothSendCommand("SET");
433

    
434
  chprintf(chp, "----------------------------------------\n");
435

    
436
  // check the buzzer
437
  chprintf(chp, "\n");
438
  chprintf(chp, "PKLCS1212E4001:\n");
439
  chprintf(chp, "you should hear the buzzer for one second...\n");
440
  pwmEnableChannel(&PWMD3, 1, 50);
441
  BaseThread::sleep(MS2ST(1000));
442
  pwmDisableChannel(&PWMD3, 1);
443
  chprintf(chp, "----------------------------------------\n");
444

    
445
  chprintf(chp, "CHECK: FINISH\n");
446
#endif
447

    
448
  return;
449
}
450

    
451
void shellRequestShutdown(BaseSequentialStream* chp, int __unused argc, char __unused *argv[]) {
452

    
453
  chprintf(chp, "shellRequestShutdown\n");
454

    
455
  /* if no argument was given, print some help text */
456
  if (argc == 0 || strcmp(argv[0],"help") == 0) {
457
    chprintf(chp, "\tUSAGE:\n");
458
    chprintf(chp, "> shutdown <type>\n");
459
    chprintf(chp, "\n");
460
    chprintf(chp, "\ttype\n");
461
    chprintf(chp, "The type of shutdown to perform.\n");
462
    chprintf(chp, "Choose one of the following types:\n");
463
    chprintf(chp, "  transportation - Ultra low-power mode with all wakeups disabled.\n");
464
    chprintf(chp, "                   The robot can not be charged.\n");
465
    chprintf(chp, "  deepsleep      - Ultra low-power mode with several wakeups enabled.\n");
466
    chprintf(chp, "                   The robot can only be charged via the power plug.\n");
467
    chprintf(chp, "  hibernate      - Medium low-power mode, but with full charging capabilities.\n");
468
    chprintf(chp, "  restart        - Performs a system restart.\n");
469
    chprintf(chp, "Alternatively, you can use the shortcuts 't', 'd', 'h', and 'r' respectively.");
470
    chprintf(chp, "\n");
471
    return;
472
  }
473

    
474
  if (strcmp(argv[0],"transportation") == 0 || strcmp(argv[0],"t") == 0) {
475
    shutdown_now = SHUTDOWN_TRANSPORTATION;
476
    chprintf(chp, "shutdown to transportation mode initialized\n");
477
  } else if (strcmp(argv[0],"deepsleep") == 0 || strcmp(argv[0],"d") == 0) {
478
    shutdown_now = SHUTDOWN_DEEPSLEEP;
479
    chprintf(chp, "shutdown to deepsleep mode initialized\n");
480
  } else if (strcmp(argv[0],"hibernate") == 0 || strcmp(argv[0],"h") == 0) {
481
    shutdown_now = SHUTDOWN_HIBERNATE;
482
    chprintf(chp, "shutdown to hibernate mode initialized\n");
483
  } else if (strcmp(argv[0],"restart") == 0 || strcmp(argv[0],"r") == 0) {
484
    chprintf(chp, "restart initialized\n");
485
    shutdown_now = SHUTDOWN_RESTART;
486
  } else {
487
    chprintf(chp, "ERROR: unknown argument!\n");
488
    shutdown_now = SHUTDOWN_NONE;
489
  }
490

    
491
  return;
492
}
493

    
494
void shellRequestResetMemory(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
495
  chprintf(chp, "shellRequestInitMemory\n");
496

    
497
  msg_t res = global.memory.resetMemory();
498

    
499
  if ( res != global.memory.OK)
500
    chprintf(chp, "Memory Init: FAIL\n");
501
  else
502
    chprintf(chp, "Memory Init: OK\n");
503
}
504

    
505
void shellRequestGetBoardId(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
506
  chprintf(chp, "shellRequestGetBoardId\n");
507

    
508
  uint8_t id = 0xFFu;
509
  msg_t res = global.memory.getBoardId(&id);
510
  if (res != global.memory.OK)
511
    chprintf(chp, "Get Board ID: FAIL\n");
512
  else
513
    chprintf(chp, "Get Board ID: %u\n", id);
514
}
515

    
516
void shellRequestSetBoardId(BaseSequentialStream *chp, int argc, char *argv[]) {
517
  chprintf(chp, "shellRequestSetBoardId\n");
518

    
519
  if (argc == 0) {
520
    chprintf(chp, "Usage: %s\n","set_board_id <idx>");
521
  } else {
522
    msg_t res = global.memory.setBoardId(atoi(argv[0]));
523
    if (res != global.memory.OK)
524
      chprintf(chp, "Set Board ID: FAIL\n");
525
    else
526
      chprintf(chp, "Set Board ID: OK\n");
527
  }
528

    
529
}
530

    
531
void shellRequestGetMemoryData(BaseSequentialStream *chp, int argc, char *argv[]) {
532
  enum Type {HEX, U8, U16, U32, S8, S16, S32};
533

    
534
  chprintf(chp, "shellRequestReadData\n");
535

    
536
  if (argc < 2 || strcmp(argv[0],"help") == 0)
537
  {
538
    chprintf(chp, "Usage: %s\n","get_memory_data <type> <start> [<count>]");
539
    chprintf(chp, "\n");
540
    chprintf(chp, "\ttype\n");
541
    chprintf(chp, "The data type as which to interpret the data.\n");
542
    chprintf(chp, "Choose one of the following types:\n");
543
    chprintf(chp, "  hex - one byte as hexadecimal value\n");
544
    chprintf(chp, "  u8  - unsigned integer (8 bit)\n");
545
    chprintf(chp, "  u16 - unsigned integer (16 bit)\n");
546
    chprintf(chp, "  u32 - unsigned integer (32 bit)\n");
547
    chprintf(chp, "  s8  - signed integer (8 bit)\n");
548
    chprintf(chp, "  s16 - signed integer (16 bit)\n");
549
    chprintf(chp, "  s32 - signed integer (32 bit)\n");
550
    chprintf(chp, "\tstart\n");
551
    chprintf(chp, "The first byte to read from the memory.\n");
552
    chprintf(chp, "\tcount [default = 1]\n");
553
    chprintf(chp, "The number of elements to read.\n");
554
    chprintf(chp, "\n");
555
    chprintf(chp, "\tNOTE\n");
556
    chprintf(chp, "Type conversions of this function might fail.\n");
557
    chprintf(chp, "If so, use type=hex and convert by hand.\n");
558
    chprintf(chp, "\n");
559
    return;
560
  }
561

    
562
  uint8_t type_size = 0;
563
  Type type = HEX;
564
  if (strcmp(argv[0],"hex") == 0) {
565
    type_size = sizeof(unsigned char);
566
    type = HEX;
567
  } else if(strcmp(argv[0],"u8") == 0) {
568
    type_size = sizeof(uint8_t);
569
    type = U8;
570
  } else if(strcmp(argv[0],"u16") == 0) {
571
    type_size = sizeof(uint16_t);
572
    type = U16;
573
  } else if(strcmp(argv[0],"u32") == 0) {
574
    type_size = sizeof(uint32_t);
575
    type = U32;
576
  } else if(strcmp(argv[0],"s8") == 0) {
577
    type_size = sizeof(int8_t);
578
    type = S8;
579
  } else if(strcmp(argv[0],"s16") == 0) {
580
    type_size = sizeof(int16_t);
581
    type = S16;
582
  } else if(strcmp(argv[0],"s32") == 0) {
583
    type_size = sizeof(int32_t);
584
    type = S32;
585
  } else {
586
    chprintf(chp, "First argument invalid. Use 'get_memory_data help' for help.\n");
587
    return;
588
  }
589

    
590
  unsigned int start_byte = atoi(argv[1]);
591

    
592
  unsigned int num_elements = 1;
593
  if (argc >= 3) {
594
    num_elements = atoi(argv[2]);
595
  }
596

    
597
  const size_t eeprom_size = EEPROM::getsize(&global.at24c01);
598
  uint8_t buffer[eeprom_size];
599
  if (start_byte + (type_size * num_elements) > eeprom_size) {
600
    num_elements = (eeprom_size - start_byte) / type_size;
601
    chprintf(chp, "Warning: request exceeds eeprom size -> limiting to %u values.\n", num_elements);
602
  }
603

    
604
  chFileStreamSeek((BaseFileStream*)&global.at24c01, start_byte);
605
  uint32_t bytes_read = chSequentialStreamRead((BaseFileStream*)&global.at24c01, buffer, type_size*num_elements);
606

    
607
  if (bytes_read != type_size*num_elements) {
608
    chprintf(chp, "Warning: %u of %u requested bytes were read.\n", bytes_read, type_size*num_elements);
609
  }
610

    
611
  for (unsigned int i = 0; i < num_elements; ++i)
612
  {
613
    switch (type)
614
    {
615
      case HEX:
616
        chprintf(chp, "%02X ", buffer[i]);
617
        break;
618
      case U8:
619
        chprintf(chp, "%03u ", ((uint8_t*)buffer)[i]);
620
        break;
621
      case U16:
622
        chprintf(chp, "%05u ", ((uint16_t*)buffer)[i]);
623
        break;
624
      case U32:
625
        chprintf(chp, "%010u ", ((uint32_t*)buffer)[i]);
626
        break;
627
      case S8:
628
        chprintf(chp, "%+03d ", ((int8_t*)buffer)[i]);
629
        break;
630
      case S16:
631
        chprintf(chp, "%+05d ", ((int16_t*)buffer)[i]);
632
        break;
633
      case S32:
634
        chprintf(chp, "%+010d ", ((int32_t*)buffer)[i]);
635
        break;
636
      default:
637
        break;
638
    }
639
  }
640
  chprintf(chp, "\n");
641

    
642
  return;
643
}
644

    
645
void shellRequestSetVcnlOffset(BaseSequentialStream *chp, int argc, char *argv[]) {
646
  chprintf(chp, "shellRequestSetVcnlOffset\n");
647
  if (argc != 2) {
648
    chprintf(chp, "Usage: %s\n","set_vcnl <idx> <offset>");
649
    return;
650
  }
651

    
652
  uint8_t vcnlIdx = static_cast<uint8_t>(atoi(argv[0]));
653
  uint16_t vcnlOffset = static_cast<uint16_t>(atoi(argv[1]));
654

    
655
  if (vcnlIdx >= global.vcnl4020.size()) {
656
    chprintf((BaseSequentialStream *)&SD1, "Wrong VCNL index: Choose [0 .. %d]\n", global.vcnl4020.size()-1);
657
    return;
658
  }
659

    
660
  msg_t res = global.memory.setVcnl4020Offset(vcnlOffset, vcnlIdx);
661
  if (res != global.memory.OK) {
662
    chprintf(chp, "Set Offset: FAIL\n");
663
  } else {
664
    chprintf(chp, "Set Offset: OK\n");
665
    global.vcnl4020[vcnlIdx].setProximityOffset(vcnlOffset);
666
  }
667
}
668

    
669
void shellRequestResetVcnlOffset(BaseSequentialStream *chp, int argc, char *argv[]) {
670
  msg_t res = global.memory.OK;
671
  for (uint8_t idx = 0; idx < 8; ++idx) {
672
    msg_t r = global.memory.setVcnl4020Offset(0, idx);
673
    if (r == global.memory.OK) {
674
      global.vcnl4020[idx].setProximityOffset(0);
675
    } else {
676
      chprintf(chp, "Reset Offset %u: FAIL\n", idx);
677
      res = r;
678
    }
679
  }
680

    
681
  if (res == global.memory.OK) {
682
    chprintf(chp, "Reset Offset: DONE\n");
683
  }
684

    
685
  return;
686
}
687

    
688
void shellRequestGetVcnlOffset(BaseSequentialStream *chp, int argc, char *argv[]) {
689
  chprintf(chp, "shellRequestGetVcnlOffset\n");
690
  if (argc != 1) {
691
    chprintf(chp, "Usage: %s\n","get_vcnl_offset <idx>");
692
    return;
693
  }
694

    
695
  uint8_t vcnlIdx = static_cast<uint8_t>(atoi(argv[0]));
696

    
697
  if (vcnlIdx >= global.vcnl4020.size()) {
698
    chprintf((BaseSequentialStream *)&SD1, "Wrong VCNL index: Choose [0 .. %d]\n", global.vcnl4020.size()-1);
699
    return;
700
  }
701

    
702
  uint16_t vcnlOffset;
703
  msg_t res = global.memory.getVcnl4020Offset(&vcnlOffset, vcnlIdx);
704
  if (res != global.memory.OK) {
705
    chprintf(chp, "Get Offset: FAIL\n");
706
  } else {
707
    chprintf(chp, "Get Offset: OK \t Offset=%d\n", vcnlOffset);
708
  }
709
}
710

    
711
void shellRequestCheck(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
712
  chprintf(chp, "shellRequestCheck\n");
713
  boardPeripheryCheck(chp);
714

    
715
}
716

    
717
void shellRequestGetVcnl(BaseSequentialStream *chp, int argc, char *argv[]) {
718
  chprintf(chp, "shellRequestGetVcnl\n");
719
  // Print the sensor information
720
  if (argc != 1) {
721
    chprintf(chp, "Usage: %s\n","get_vcnl <rep>");
722
    return;
723
  }
724
  for (int32_t rep = 0x00; rep < atoi(argv[0]); ++rep) {
725
    for (uint8_t idx = 0x00; idx < global.vcnl4020.size(); idx++) {
726
     chprintf(chp, "%d: Ambi %d\tProx raw %d\tProx scaled %d\n", idx, global.vcnl4020[idx].getAmbientLight(), global.vcnl4020[idx].getProximity(), global.vcnl4020[idx].getProximityScaledWoOffset());
727
    }
728
    chprintf(chp, "\n\n");
729
    BaseThread::sleep(MS2ST(250));
730
  }
731
}
732

    
733
void shellRequestCalib(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
734
  chprintf(chp, "shellRequestCalib\n");
735
  global.robot.calibrate();
736

    
737
}
738

    
739
void shellRequestGetRobotId(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
740
  chprintf(chp, "shellRequestGetRobotId\n");
741
  chprintf(chp, "Robot ID: %u\n", global.robot.getRobotID());
742
  if (global.robot.getRobotID() == 0) {
743
    chprintf(chp, "Warning: The ID seems to be uninitialized. Is CAN communication working correctly?\n");
744
  }
745
}
746

    
747
void shellRequestGetSystemLoad(BaseSequentialStream *chp, int argc, char *argv[]) {
748
  chprintf(chp, "shellRequestGetSystemLoad\n");
749
  uint8_t seconds = 1;
750
  if (argc >= 1) {
751
    seconds = atoi(argv[0]);
752
  }
753
  chprintf(chp, "measuring CPU load for %u %s...\n", seconds, (seconds>1)? "seconds" : "second");
754

    
755
  const systime_t before = chThdGetTicks(chSysGetIdleThread());
756
  BaseThread::sleep(S2ST(seconds));
757
  const systime_t after = chThdGetTicks(chSysGetIdleThread());
758
  const float usage = 1.0f - (float(after - before) / float(seconds * CH_FREQUENCY));
759

    
760
  chprintf(chp, "CPU load: %3.2f%%\n", usage * 100);
761
  const uint32_t memory_total = 0x1C000;
762
  const uint32_t memory_load = memory_total - chCoreStatus();
763
  chprintf(chp, "RAM load: %3.2f%% (%u / %u Byte)\n", float(memory_load)/float(memory_total) * 100, memory_load, memory_total);
764
}
765

    
766
void shellRequestSetCharging(BaseSequentialStream *chp, int argc, char *argv[]) {
767
  chprintf(chp, "shellRequestSetCharging\n");
768
  if (argc < 1) {
769
    chprintf(chp, "Usage: %s\n","set_charging <enable>");
770
    chprintf(chp, "\n");
771
    chprintf(chp, "\tenable\n");
772
    chprintf(chp, "Whether to enable (1) or to disable (0) the power path controller of the DiWheelDrive board.\n");
773
    chprintf(chp, "\n");
774
    return;
775
  }
776

    
777
  const bool enable = atoi(argv[0]);
778
  chprintf(chp, "%s power path controller\n", enable ? "enabling" : "disabling");
779
  global.robot.getPowerStatus().charging_flags.content.diwheeldrive_enable_power_path = enable;
780

    
781
  return;
782
}
783

    
784
void shellRequestPrintVCNL(BaseSequentialStream *chp, int argc, char *argv[]) {
785
  chprintf(chp, "shellRequestPrintVCNL\n");
786
  if (argc < 1) {
787
    chprintf(chp, "Warning: no arguments specified.\n");
788
    chprintf(chp, "Using default values (prints one measurement).\n");
789
    chprintf(chp, "Type 'print_vcnl help' for help.\n");
790
    chprintf(chp, "----------------------------------------\n");
791
  }
792

    
793
  if (strcmp(argv[0],"help") == 0) {
794
    chprintf(chp, "Usage: %s\n","print_vcnl [<seconds>] [<frequency>]");
795
    chprintf(chp, "\n");
796
    chprintf(chp, "\tseconds\n");
797
    chprintf(chp, "Number of seconds to print the VCNL values. (default: 1)\n");
798
    chprintf(chp, "\n");
799
    chprintf(chp, "\tfrequency\n");
800
    chprintf(chp, "Number prints per second. (default: 1)\n");
801
    return;
802
  }
803

    
804
  const uint32_t seconds = (argc >= 1) ? atoi(argv[0]) : 1;
805
  const uint32_t freq = (argc >= 2) ? atoi(argv[1]) : 1;
806

    
807
  uint16_t ambient = 0;
808
  uint16_t proximity = 0;
809

    
810
  for (uint32_t loop = 0; loop < seconds*freq; ++loop) {
811
    // Print proximity and ambilight values
812
    for (uint8_t i = 0x00; i < global.vcnl4020.size(); ++i) {
813
      ambient = global.vcnl4020[i].getAmbientLight();
814
      proximity = global.vcnl4020[i].getProximity();
815
      chprintf(chp, "#%d: ambient=0x%04X\tproximity=0x%04X\n", i, ambient, proximity);
816
    }
817
    chprintf(chp, "----------------------------------------\n");
818

    
819
    BaseThread::sleep(US2ST(1000000 / freq));
820
  }
821

    
822
  return;
823
}
824

    
825
void shellSwitchBoardCmd(BaseSequentialStream *chp, int argc, char *argv[]) {
826
  if (argc != 1) {
827
    chprintf(chp, "Call with decimal numbers: shell_board <idx>\n");
828
    return;
829
  }
830
  uint8_t boardIdx = static_cast<uint8_t>(atoi(argv[0]));
831

    
832
  chprintf(chp, "shellSwitchBoardCmd\n");
833
  global.sercanmux1.sendSwitchCmd(boardIdx);
834
}
835

    
836
void shellRequestGetBootloaderInfo(BaseSequentialStream* chp, int argc, char *argv[]) {
837
  // check the magic number
838
  switch (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR))) {
839
    case (('A'<<24) | ('-'<<16) | ('B'<<8) | ('L'<<0)):
840
      chprintf((BaseSequentialStream*) &SD1, "Bootloader %u.%u.%u\n",
841
               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->major,
842
               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->minor,
843
               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->patch);
844
      break;
845

    
846
    case BL_MAGIC_NUMBER:
847
      chprintf((BaseSequentialStream*) &SD1, "Bootloader %u.%u.%u\n",
848
               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))),
849
               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))),
850
               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))));
851
      break;
852

    
853
    default:
854
      chprintf((BaseSequentialStream*) &SD1, "Bootloader incompatible\n");
855
      break;
856
  }
857

    
858
  return;
859
}
860

    
861
void shellRequestWiiSteering(BaseSequentialStream* chp, int argc, char *argv[]) {
862
  // if Wii steering is currently active, stop it
863
  if (global.userThread.getCurrenState() == UserThread::WII_STEERING) {
864
    global.userThread.setNextState(UserThread::IDLE);
865
  }
866
  // check arguments and (try to) enable Wii steering
867
  else {
868
    // if arguments invalid
869
    if (argc < 1 || argc > 2 || global.userThread.setWiiAddress(argv[0]) != RDY_OK) {
870
      chprintf(chp, "Warning: invalid arguments\n");
871
      chprintf(chp, "Usage: %s\n", "wii_steering <address> [<deadzone>]");
872
      chprintf(chp, "\n");
873
      chprintf(chp, "\taddress\n");
874
      chprintf(chp, "bluetooth address of the Wiimote controller to pair with.\n");
875
      chprintf(chp, "\tdeadzone\n");
876
      chprintf(chp, "deadzone to set for the Wiimote controller [default = 10%%].\n");
877
      return;
878
    }
879
    else {
880
      // set deadzone
881
      const float deadzone = global.userThread.setWiiDeadzone((argc == 2) ? std::atof(argv[1]) : 0.1f);
882
      chprintf(chp, "deadzone set to %u%%\n", (unsigned int)(deadzone * 100.0f));
883

    
884
      // start Wii steering behaviour
885
      global.userThread.setNextState(UserThread::WII_STEERING);
886
    }
887
  }
888
  return;
889
}
890

    
891
static const ShellCommand commands[] = {
892
  {"shutdown", shellRequestShutdown},
893
  {"check", shellRequestCheck},
894
  {"reset_memory", shellRequestResetMemory},
895
  {"get_board_id", shellRequestGetBoardId},
896
  {"set_board_id", shellRequestSetBoardId},
897
  {"get_memory_data", shellRequestGetMemoryData},
898
  {"get_vcnl", shellRequestGetVcnl},
899
  {"calib_vcnl_offset", shellRequestCalib},
900
  {"set_vcnl_offset", shellRequestSetVcnlOffset},
901
  {"reset_vcnl_offset", shellRequestResetVcnlOffset},
902
  {"get_vcnl_offset", shellRequestGetVcnlOffset},
903
  {"get_robot_id", shellRequestGetRobotId},
904
  {"get_system_load", shellRequestGetSystemLoad},
905
  {"set_charging", shellRequestSetCharging},
906
  {"print_vcnl", shellRequestPrintVCNL},
907
  {"shell_board", shellSwitchBoardCmd},
908
  {"get_bootloader_info", shellRequestGetBootloaderInfo},
909
  {"wii_steering", shellRequestWiiSteering},
910
  {NULL, NULL}
911
};
912

    
913
static const ShellConfig shell_cfg1 = {
914
  (BaseSequentialStream *) &global.sercanmux1,
915
  commands
916
};
917

    
918
void charger_logic() {
919
  /*
920
   * if supply connected, activate charger, else
921
   * deactivate charger
922
   */
923
  if (global.ltc4412.isPluggedIn()) {
924
    boardChargerSetState(0x03u, 1), chprintf((BaseSequentialStream*) &SD1, "Charging.\n");
925
  } else {
926
    boardChargerSetState(0x03u, 0), chprintf((BaseSequentialStream*) &SD1, "Not charging.\n");
927
  }
928
}
929

    
930
void init_powermonitor(INA219::Driver &ina219, const float shunt_resistance_O, const float max_expected_current_A, const uint16_t current_lsb_uA)
931
{
932
  INA219::CalibData calib_data;
933
  INA219::InitData init_data;
934

    
935
  calib_data.input.configuration.content.brng = INA219::Configuration::BRNG_16V;
936
  calib_data.input.configuration.content.pg = INA219::Configuration::PGA_40mV;
937
  calib_data.input.configuration.content.badc = INA219::Configuration::ADC_68100us;
938
  calib_data.input.configuration.content.sadc = INA219::Configuration::ADC_68100us;
939
  calib_data.input.configuration.content.mode = INA219::Configuration::MODE_ShuntBus_Continuous;
940
  calib_data.input.shunt_resistance_O = shunt_resistance_O;
941
  calib_data.input.max_expected_current_A = max_expected_current_A;
942
  calib_data.input.current_lsb_uA = current_lsb_uA;
943
  if (ina219.calibration(&calib_data) != BaseSensor<>::SUCCESS)
944
    chprintf((BaseSequentialStream*)&SD1, "WARNING: calibration of INA219 failed.\n");
945

    
946
  init_data.configuration.value = calib_data.input.configuration.value;
947
  init_data.calibration = calib_data.output.calibration_value;
948
  init_data.current_lsb_uA = calib_data.output.current_lsb_uA;
949
  if (ina219.init(&init_data) != BaseSensor<>::SUCCESS)
950
    chprintf((BaseSequentialStream*)&SD1, "WARNING: initialization of INA219 failed.\n");
951

    
952
  if (calib_data.input.current_lsb_uA != init_data.current_lsb_uA)
953
  {
954
    chprintf((BaseSequentialStream*)&SD1, "NOTE: LSB for current measurement was limited when initializing INA219 (%u -> %u)", calib_data.input.current_lsb_uA, init_data.current_lsb_uA);
955
  }
956

    
957
  return;
958
}
959

    
960
/*
961
 * Application entry point.
962
 */
963
int main(void) {
964

    
965
  Thread *shelltp = NULL;
966

    
967
  /*
968
   * System initializations.
969
   * - HAL initialization, this also initializes the configured device drivers
970
   *   and performs the board-specific initializations.
971
   * - Kernel initialization, the main() function becomes a thread and the
972
   *   RTOS is active.
973
   */
974
  halInit();
975
  System::init();
976

    
977
  /*
978
   * TODO: detect the reason why the system was started by reading the 1st backup register of the RTC.
979
   *       To do that, it is probably required to extend the RTC LLD by the required methods.
980
   *       For further details, how to interprete the data in the backu register, please have a look at the bootloader project.
981
   */
982

    
983
  /*
984
   * Activates the serial driver 1 using the driver default configuration.
985
   */
986
  sdStart(&SD1, &global.sd1_config);
987

    
988
  chprintf((BaseSequentialStream*) &SD1, "\n");
989
  chprintf((BaseSequentialStream*) &SD1, BOARD_NAME " " BOARD_VERSION "\n");
990
  switch (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR))) {
991
    case (('A'<<24) | ('-'<<16) | ('B'<<8) | ('L'<<0)):
992
      chprintf((BaseSequentialStream*) &SD1, "Bootloader %u.%u.%u\n",
993
               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->major,
994
               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->minor,
995
               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->patch);
996
      break;
997

    
998
    case BL_MAGIC_NUMBER:
999
      chprintf((BaseSequentialStream*) &SD1, "Bootloader %u.%u.%u\n",
1000
               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))),
1001
               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))),
1002
               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))));
1003
      break;
1004

    
1005
    default:
1006
      chprintf((BaseSequentialStream*) &SD1, "Bootloader incompatible\n");
1007
      break;
1008
  }
1009
  chprintf((BaseSequentialStream*) &SD1, "ChibiOS " CH_KERNEL_VERSION "\n");
1010
  // make sure that the info text is completetly printed
1011
  BaseThread::sleep(10);
1012

    
1013
//  boardWriteSystemPower(1);
1014
//  boardWriteIoPower(1);
1015
//  boardWriteWarmRestart(0);
1016

    
1017
  global.robot.start(HIGHPRIO - 1);
1018

    
1019
  pwmStart(&PWMD3, &global.pwm3_config);
1020
  pwmDisableChannel(&PWMD3, 1);
1021

    
1022
  adcStart(&ADCD1, NULL);
1023

    
1024
  extStart(&EXTD1, &extcfg);
1025

    
1026
  boardClearI2CBus(GPIOB_GAUGE_SCL1, GPIOB_GAUGE_SDA1);
1027
  boardClearI2CBus(GPIOB_GAUGE_SCL2, GPIOB_GAUGE_SDA2);
1028

    
1029
  global.HW_I2C1.start(&global.i2c1_config);
1030
  global.HW_I2C2.start(&global.i2c2_config);
1031

    
1032
  uint16_t i2c_test = 0;
1033
  while (global.ina219[INA_VIO18].readRegister(INA219::Driver::REG_BUS_VOLTAGE, i2c_test) != RDY_OK) {
1034
    chprintf((BaseSequentialStream*)&global.sercanmux1, "I2C #1 stalled! trying to clear the bus... (this will take 20 seconds)\n");
1035
    boardWriteLed(1);
1036
    boardResetBQ27500I2C(GPIOB_GAUGE_SCL2, GPIOB_GAUGE_SDA2);
1037
    boardWriteLed(0);
1038
  }
1039
  while (global.ina219[INA_VDD].readRegister(INA219::Driver::REG_BUS_VOLTAGE, i2c_test) != RDY_OK) {
1040
    chprintf((BaseSequentialStream*)&global.sercanmux1, "I2C #2 stalled! trying to clear the bus... (this will take 20 seconds)\n");
1041
    boardWriteLed(1);
1042
    boardResetBQ27500I2C(GPIOB_GAUGE_SCL1, GPIOB_GAUGE_SDA1);
1043
    boardWriteLed(0);
1044
  }
1045

    
1046
  global.memory.init();
1047
  uint8_t i = 0;
1048
  if (global.memory.getBoardId(&i) == fileSystemIo::FileSystemIoBase::OK) {
1049
    chprintf((BaseSequentialStream*) &SD1, "Board ID: %u\n", i);
1050
  } else {
1051
    chprintf((BaseSequentialStream*) &SD1, "Error reading board ID\n");
1052
  }
1053
  chprintf((BaseSequentialStream*) &SD1, "\n");
1054

    
1055
  shelltp = shellCreate(&shell_cfg1, THD_WA_SIZE(1024), NORMALPRIO);
1056

    
1057
  // initialize the power monitors
1058
  init_powermonitor(global.ina219[INA_VDD], 0.1f, 0.075f, 10);
1059
  init_powermonitor(global.ina219[INA_VIO18], 0.01f, 1.5f, 100);
1060
  init_powermonitor(global.ina219[INA_VIO33], 0.01f, 1.5f, 100);
1061
  init_powermonitor(global.ina219[INA_VIO42], 0.01f, 1.5f, 100);
1062
  init_powermonitor(global.ina219[INA_VIO50], 0.01f, 1.5f, 100);
1063

    
1064
  // start the ADC watchdog
1065
  global.adc1_vsys.start(NORMALPRIO);
1066

    
1067
  // start the ina threads
1068
  for (i = 0; i < global.ina219.size(); ++i)
1069
    global.ina219[i].start(NORMALPRIO);
1070

    
1071
//  // calibrate the fuel gauges (TODO)
1072
//  BQ27500::CalibData bq27500_calib_data;
1073
//  bq27500_p7.calibration(&bq27500_calib_data);
1074

    
1075
  // start the fuel gauge threads
1076
  for (i = 0; i < global.bq27500.size(); ++i)
1077
    global.bq27500[i].start(NORMALPRIO);
1078

    
1079
  // start the proximity sensor threads
1080
  for (i = 0; i < global.vcnl4020.size(); ++i) {
1081
    uint16_t buffer;
1082
    global.memory.getVcnl4020Offset(&buffer,i);
1083
    global.vcnl4020[i].setProximityOffset(buffer);
1084
    global.vcnl4020[i].start(NORMALPRIO);
1085
  }
1086

    
1087
  /* Start uart port connecting bluetooth chip */
1088
  global.wt12.bluetoothStart();
1089

    
1090
  global.mpr121.configure(&global.mpr121_run_config);
1091
  global.mpr121.start(NORMALPRIO);
1092

    
1093
  global.userThread.start(NORMALPRIO);
1094

    
1095
  /* let the SYS_SYNC_N pin go, to signal that the initialization of the module is done */
1096
  palWritePad(GPIOC, GPIOC_SYS_INT_N, PAL_HIGH);
1097

    
1098
  /* wait until all modules are done */
1099
  while (palReadPad(GPIOC, GPIOC_SYS_INT_N) == PAL_LOW) {
1100
    continue;
1101
  }
1102

    
1103
  while (true) {
1104

    
1105
    if (!shelltp)
1106
      shelltp = shellCreate(&shell_cfg1, THD_WA_SIZE(1024), NORMALPRIO);
1107
    else if (chThdTerminated(shelltp)) {
1108
      chThdRelease(shelltp); /* Recovers memory of the previous shell. */
1109
      shelltp = NULL; /* Triggers spawning of a new shell.      */
1110
    }
1111

    
1112
    // Let the LED just blink as an alive signal
1113
    boardWriteLed(1);
1114
    BaseThread::sleep(MS2ST(250));
1115
    boardWriteLed(0);
1116
    BaseThread::sleep(MS2ST(250));
1117

    
1118
    /*
1119
     * Charger logic before shutdown logic,
1120
     * so we don't need to call it twice.
1121
     */
1122
    if (pathdc_change) {
1123
      pathdc_change = 0x00u;
1124
//      charger_logic();
1125
    }
1126

    
1127
    /*
1128
     * Shutdown logic before user logic,
1129
     * so user does not get hopes up and
1130
     * prepares wheels to drive into the
1131
     * next wall or something like that.
1132
     */
1133
    if (shutdown_now != SHUTDOWN_NONE) {
1134
      if ((*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) != (('A'<<24) | ('-'<<16) | ('B'<<8) | ('L'<<0))) && (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) != BL_MAGIC_NUMBER)) {
1135
        chprintf((BaseSequentialStream*) &SD1, "ERROR: unable to shut down (bootloader deprecated).\n");
1136
        shutdown_now = SHUTDOWN_NONE;
1137
      } else {
1138
        uint32_t blCallbackPtrAddr = BL_CALLBACK_TABLE_ADDR;
1139
        // handle bootloader version 0.2.x
1140
        if ((*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) == BL_MAGIC_NUMBER) &&
1141
            (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))) == 0 && *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (2*4))) == 2)) {
1142
          switch (shutdown_now) {
1143
            case SHUTDOWN_TRANSPORTATION:
1144
              blCallbackPtrAddr += 6 * 4;
1145
              break;
1146
            case SHUTDOWN_DEEPSLEEP:
1147
              blCallbackPtrAddr += 5 * 4;
1148
              break;
1149
            case SHUTDOWN_HIBERNATE:
1150
              blCallbackPtrAddr += 4 * 4;
1151
              break;
1152
            case SHUTDOWN_HANDLE_REQUEST:
1153
            case SHUTDOWN_RESTART:
1154
              blCallbackPtrAddr += 10 * 4;
1155
              break;
1156
            default:
1157
              blCallbackPtrAddr = 0;
1158
              break;
1159
          }
1160
        }
1161
        // handle bootloader version 0.3.x
1162
        else if ((*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) == BL_MAGIC_NUMBER) &&
1163
                 (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))) == 0 && *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (2*4))) == 3)) {
1164
          switch (shutdown_now) {
1165
            case SHUTDOWN_TRANSPORTATION:
1166
              blCallbackPtrAddr += 6 * 4;
1167
              break;
1168
            case SHUTDOWN_DEEPSLEEP:
1169
              blCallbackPtrAddr += 5 * 4;
1170
              break;
1171
            case SHUTDOWN_HIBERNATE:
1172
              blCallbackPtrAddr += 4 * 4;
1173
              break;
1174
            case SHUTDOWN_RESTART:
1175
              blCallbackPtrAddr += 7 * 4;
1176
              break;
1177
            case SHUTDOWN_HANDLE_REQUEST:
1178
              blCallbackPtrAddr += 8 * 4;
1179
              break;
1180
            default:
1181
              blCallbackPtrAddr = 0;
1182
              break;
1183
          }
1184
        }
1185
        // handle bootloader version 1.0.x and 1.1.x
1186
        else if ((*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) == (('A'<<24) | ('-'<<16) | ('B'<<8) | ('L'<<0))) &&
1187
                 ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->major == 1 && (((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->minor == 0 || ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->minor == 1)) {
1188
          switch (shutdown_now) {
1189
            case SHUTDOWN_TRANSPORTATION:
1190
              blCallbackPtrAddr += 6 * 4;
1191
              break;
1192
            case SHUTDOWN_DEEPSLEEP:
1193
              blCallbackPtrAddr += 5 * 4;
1194
              break;
1195
            case SHUTDOWN_HIBERNATE:
1196
              blCallbackPtrAddr += 4 * 4;
1197
              break;
1198
            case SHUTDOWN_RESTART:
1199
              blCallbackPtrAddr += 7 * 4;
1200
              break;
1201
            case SHUTDOWN_HANDLE_REQUEST:
1202
              blCallbackPtrAddr += 8 * 4;
1203
              break;
1204
            default:
1205
              blCallbackPtrAddr = 0;
1206
              break;
1207
          }
1208
        }
1209

    
1210
        void (*blCallback)(void) = NULL;
1211
        if (blCallbackPtrAddr > BL_CALLBACK_TABLE_ADDR) {
1212
          blCallback = (void (*)(void))(*((uint32_t*)blCallbackPtrAddr));
1213

    
1214
          if (!blCallback) {
1215
            chprintf((BaseSequentialStream*) &SD1, "ERROR: Requested shutdown not supported.\n");
1216
            shutdown_now = SHUTDOWN_NONE;
1217
          } else {
1218
            chprintf((BaseSequentialStream*) &SD1, "initiating shutdown sequence...\n");
1219
            palWritePad(GPIOC, GPIOC_SYS_INT_N, PAL_LOW);
1220
            palWritePad(GPIOC, GPIOC_SYS_PD_N, PAL_LOW);
1221

    
1222
            chprintf((BaseSequentialStream*) &SD1, "stopping all threads and periphery...");
1223
            systemStop();
1224
            chprintf((BaseSequentialStream*) &SD1, "\tdone\n");
1225
            BaseThread::sleep(MS2ST(10)); // sleep to print everything
1226

    
1227
            blCallback();
1228
          }
1229

    
1230
        } else {
1231
          chprintf((BaseSequentialStream*) &SD1, "ERROR: invalid shutdown requested (%u).\n", shutdown_now);
1232
          shutdown_now = SHUTDOWN_NONE;
1233
        }
1234
      }
1235

    
1236
//      shutdown_now = 0x00u;
1237
//      if (palReadPad(GPIOC, GPIOC_PATH_DC))
1238
//        systemStop();
1239
//      else
1240
//        systemShutdown();
1241
//      //boardStop(0x00u, 0x00u);
1242
//      //chprintf((BaseSequentialStream*) &SD1, "Stop exit\n");
1243
    }
1244

    
1245
  }
1246

    
1247
  global.HW_I2C2.stop();
1248
  global.HW_I2C1.stop();
1249

    
1250
  return 0;
1251
}