Contiki-NG
platform.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, SICS Swedish ICT.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following
12  * disclaimer in the documentation and/or other materials provided
13  * with the distribution.
14  * 3. The name of the author may not be used to endorse or promote
15  * products derived from this software without specific prior
16  * written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * This file is part of the Contiki OS
31  *
32  */
33 
34 /**
35  * \file
36  * Contiki main for NXP JN516X platform
37  *
38  * \author
39  * Beshr Al Nahas <beshr@sics.se>
40  * Atis Elsts <atis.elsts@sics.se>
41  */
42 
43 #include <stdio.h>
44 #include <string.h>
45 #include <unistd.h>
46 
47 #include "dev/watchdog.h"
48 #include <AppHardwareApi.h>
49 #include <BbcAndPhyRegs.h>
50 #include <recal.h>
51 #include "dev/uart0.h"
52 #include "dev/uart-driver.h"
53 
54 #include "contiki.h"
55 #include "sys/energest.h"
56 #include "net/netstack.h"
57 
58 #include "dev/serial-line.h"
59 
60 #include "dev/leds.h"
61 
62 #include "lib/random.h"
63 #include "sys/node-id.h"
64 #include "sys/platform.h"
65 #include "rtimer-arch.h"
66 
67 #if NETSTACK_CONF_WITH_IPV6
68 #include "net/ipv6/uip-ds6.h"
69 #endif /* NETSTACK_CONF_WITH_IPV6 */
70 
71 #include "dev/micromac-radio.h"
72 #include "MMAC.h"
73 /* Includes depending on connected sensor boards */
74 #if SENSOR_BOARD_DR1175
75 #include "light-sensor.h"
76 #include "ht-sensor.h"
77 SENSORS(&light_sensor, &ht_sensor);
78 #elif SENSOR_BOARD_DR1199
79 #include "button-sensor.h"
80 #include "pot-sensor.h"
81 SENSORS(&pot_sensor, &button_sensor);
82 #else
83 #include "dev/button-sensor.h"
84 /* #include "dev/pir-sensor.h" */
85 /* #include "dev/vib-sensor.h" */
86 /* &pir_sensor, &vib_sensor */
87 SENSORS(&button_sensor);
88 #endif
89 unsigned char node_mac[8];
90 
91 /* Symbol defined by the linker script
92  * marks the end of the stack taking into account the used heap */
93 extern uint32_t heap_location;
94 
95 #ifdef EXPERIMENT_SETUP
96 #include "experiment-setup.h"
97 #endif
98 
99 /* _EXTRA_LPM is the sleep mode, _LPM is the doze mode */
100 #define ENERGEST_TYPE_EXTRA_LPM ENERGEST_TYPE_LPM
101 
102 extern int main(void);
103 
104 #if DCOSYNCH_CONF_ENABLED
105 static unsigned long last_dco_calibration_time;
106 #endif
107 static uint64_t sleep_start;
108 static uint32_t sleep_start_ticks;
109 /*---------------------------------------------------------------------------*/
110 /* Log configuration */
111 #include "sys/log.h"
112 #define LOG_MODULE "JN516x"
113 #define LOG_LEVEL LOG_LEVEL_MAIN
114 /*---------------------------------------------------------------------------*/
115 /* Reads MAC from SoC
116  * Must be called before network addresses initialization */
117 static void
118 init_node_mac(void)
119 {
120  tuAddr psExtAddress;
121  vMMAC_GetMacAddress(&psExtAddress.sExt);
122  node_mac[7] = psExtAddress.sExt.u32L;
123  node_mac[6] = psExtAddress.sExt.u32L >> (uint32_t)8;
124  node_mac[5] = psExtAddress.sExt.u32L >> (uint32_t)16;
125  node_mac[4] = psExtAddress.sExt.u32L >> (uint32_t)24;
126  node_mac[3] = psExtAddress.sExt.u32H;
127  node_mac[2] = psExtAddress.sExt.u32H >> (uint32_t)8;
128  node_mac[1] = psExtAddress.sExt.u32H >> (uint32_t)16;
129  node_mac[0] = psExtAddress.sExt.u32H >> (uint32_t)24;
130 }
131 /*---------------------------------------------------------------------------*/
132 static void
133 set_linkaddr(void)
134 {
135  linkaddr_t addr;
136  memset(&addr, 0, LINKADDR_SIZE);
137 
138 #if NETSTACK_CONF_WITH_IPV6
139  memcpy(addr.u8, node_mac, sizeof(addr.u8));
140 #else
141  int i;
142  for(i = 0; i < LINKADDR_SIZE; ++i) {
143  addr.u8[i] = node_mac[LINKADDR_SIZE - 1 - i];
144  }
145 #endif
146  linkaddr_set_node_addr(&addr);
147 }
148 /*---------------------------------------------------------------------------*/
149 bool_t
150 xosc_init(void)
151 {
152  /* The internal 32kHz RC oscillator is used by default;
153  * Initialize and enable the external 32.768kHz crystal.
154  */
155  vAHI_Init32KhzXtal();
156  /* Switch to the 32.768kHz crystal.
157  * This will block and wait up to 1 sec for it to stabilize. */
158  return bAHI_Set32KhzClockMode(E_AHI_XTAL);
159 }
160 /*---------------------------------------------------------------------------*/
161 void
163 {
164  /* Set stack overflow address for detecting overflow in runtime */
165  vAHI_SetStackOverflow(TRUE, ((uint32_t *)&heap_location)[0]);
166 
167  /* Initialize random with a seed from the SoC random generator.
168  * This must be done before selecting the high-precision external oscillator.
169  */
170  vAHI_StartRandomNumberGenerator(E_AHI_RND_SINGLE_SHOT, E_AHI_INTS_DISABLED);
171  random_init(u16AHI_ReadRandomNumber());
172 
173  clock_init();
174  rtimer_init();
175 
176 #if JN516X_EXTERNAL_CRYSTAL_OSCILLATOR
177  /* initialize the 32kHz crystal and wait for ready */
178  xosc_init();
179  /* need to reinitialize because the wait-for-ready process uses system timers */
180  clock_init();
181  rtimer_init();
182 #endif
183 
184  leds_init();
185  leds_on(LEDS_ALL);
186  init_node_mac();
187 }
188 /*---------------------------------------------------------------------------*/
189 void
191 {
192  uart0_init(UART_BAUD_RATE); /* Must come before first PRINTF */
193 
194  /* check for reset source */
195  if(bAHI_WatchdogResetEvent()) {
196  LOG_INFO("Init: Watchdog timer has reset device!\r\n");
197  }
198  set_linkaddr();
199 }
200 /*---------------------------------------------------------------------------*/
201 void
203 {
204 #ifndef UIP_FALLBACK_INTERFACE
205  uart0_set_input(serial_line_input_byte);
206  serial_line_init();
207 #endif /* UIP_FALLBACK_INTERFACE */
208 
209 #if TIMESYNCH_CONF_ENABLED
210  timesynch_init();
211  timesynch_set_authority_level((linkaddr_node_addr.u8[0] << 4) + 16);
212 #endif /* TIMESYNCH_CONF_ENABLED */
213 
214  /* need this to reliably generate the first rtimer callback and callbacks in other
215  auto-start processes */
216  (void)u32AHI_Init();
217 
219 }
220 /*---------------------------------------------------------------------------*/
221 void
223 {
224  clock_time_t time_to_etimer;
225  rtimer_clock_t ticks_to_rtimer;
226 
227 #if DCOSYNCH_CONF_ENABLED
228  /* Calibrate the DCO every DCOSYNCH_PERIOD
229  * if we have more than 500uSec until next rtimer
230  * PS: Calibration disables interrupts and blocks for 200uSec.
231  * */
232  if(clock_seconds() - last_dco_calibration_time > DCOSYNCH_PERIOD) {
233  if(rtimer_arch_time_to_rtimer() > RTIMER_SECOND / 2000) {
234  /* PRINTF("ContikiMain: Calibrating the DCO\n"); */
235  eAHI_AttemptCalibration();
236  /* Patch to allow CpuDoze after calibration */
237  vREG_PhyWrite(REG_PHY_IS, REG_PHY_INT_VCO_CAL_MASK);
238  last_dco_calibration_time = clock_seconds();
239  }
240  }
241 #endif /* DCOSYNCH_CONF_ENABLED */
242 
243  /* flush standard output before sleeping */
244  uart_driver_flush(E_AHI_UART_0, TRUE, FALSE);
245 
246  /* calculate the time to the next etimer and rtimer */
247  time_to_etimer = clock_arch_time_to_etimer();
248  ticks_to_rtimer = rtimer_arch_time_to_rtimer();
249 
250 #if JN516X_SLEEP_ENABLED
251  /* we can sleep only up to the next rtimer/etimer */
252  rtimer_clock_t max_sleep_time = ticks_to_rtimer;
253  if(max_sleep_time >= JN516X_MIN_SLEEP_TIME) {
254  /* also take into account etimers */
255  uint64_t ticks_to_etimer = ((uint64_t)time_to_etimer * RTIMER_SECOND) / CLOCK_SECOND;
256  max_sleep_time = MIN(ticks_to_etimer, ticks_to_rtimer);
257  }
258 
259  if(max_sleep_time >= JN516X_MIN_SLEEP_TIME) {
260  max_sleep_time -= JN516X_SLEEP_GUARD_TIME;
261  /* bound the sleep time to 1 second */
262  max_sleep_time = MIN(max_sleep_time, JN516X_MAX_SLEEP_TIME);
263 
264 #if !RTIMER_USE_32KHZ
265  /* convert to 32.768 kHz oscillator ticks */
266  max_sleep_time = (uint64_t)max_sleep_time * JN516X_XOSC_SECOND / RTIMER_SECOND;
267 #endif
268  vAHI_WakeTimerEnable(WAKEUP_TIMER, TRUE);
269  /* sync with the tick timer */
270  WAIT_FOR_EDGE(sleep_start);
271  sleep_start_ticks = u32AHI_TickTimerRead();
272 
273  vAHI_WakeTimerStartLarge(WAKEUP_TIMER, max_sleep_time);
274  ENERGEST_SWITCH(ENERGEST_TYPE_CPU, ENERGEST_TYPE_EXTRA_LPM);
275  vAHI_Sleep(E_AHI_SLEEP_OSCON_RAMON);
276  } else {
277 #else
278  {
279 #endif /* JN516X_SLEEP_ENABLED */
280  clock_arch_schedule_interrupt(time_to_etimer, ticks_to_rtimer);
281  ENERGEST_SWITCH(ENERGEST_TYPE_CPU, ENERGEST_TYPE_LPM);
282  vAHI_CpuDoze();
283  watchdog_start();
284  ENERGEST_SWITCH(ENERGEST_TYPE_LPM, ENERGEST_TYPE_CPU);
285  }
286 }
287 /*---------------------------------------------------------------------------*/
288 void
290 {
291  int r;
292 
293  while(1) {
294  do {
295  /* Reset watchdog. */
297  r = process_run();
298  } while(r > 0);
299  /*
300  * Idle processing.
301  */
302  platform_idle();
303  }
304 }
305 /*---------------------------------------------------------------------------*/
306 void
307 AppColdStart(void)
308 {
309  /* After reset or sleep with memory off */
310  main();
311 }
312 /*---------------------------------------------------------------------------*/
313 void
314 AppWarmStart(void)
315 {
316  /* Wakeup after sleep with memory on.
317  * Need to initialize devices but not the application state.
318  * Note: the actual time this function is called is
319  * ~8 ticks (32kHz timer) later than the scheduled sleep end time.
320  */
321  uint32_t sleep_ticks;
322  uint64_t sleep_end;
323  rtimer_clock_t sleep_ticks_rtimer;
324 
325  clock_arch_calibrate();
326  leds_init();
327  uart0_init(UART_BAUD_RATE); /* Must come before first PRINTF */
328  NETSTACK_RADIO.init();
329  watchdog_init();
330  watchdog_stop();
331 
332  WAIT_FOR_EDGE(sleep_end);
333  sleep_ticks = (uint32_t)(sleep_start - sleep_end) + 1;
334 
335 #if RTIMER_USE_32KHZ
336  sleep_ticks_rtimer = sleep_ticks;
337 #else
338  {
339  static uint32_t remainder;
340  uint64_t t = (uint64_t)sleep_ticks * RTIMER_SECOND + remainder;
341  sleep_ticks_rtimer = (uint32_t)(t / JN516X_XOSC_SECOND);
342  remainder = t - sleep_ticks_rtimer * JN516X_XOSC_SECOND;
343  }
344 #endif
345 
346  /* reinitialize rtimers */
347  rtimer_arch_reinit(sleep_start_ticks, sleep_ticks_rtimer);
348 
349  ENERGEST_SWITCH(ENERGEST_TYPE_EXTRA_LPM, ENERGEST_TYPE_CPU);
350 
351  watchdog_start();
352 
353  /* reinitialize clock */
354  clock_arch_init(1);
355  /* schedule etimer interrupt */
356  clock_arch_schedule_interrupt(clock_arch_time_to_etimer(), rtimer_arch_time_to_rtimer());
357 
358 #if DCOSYNCH_CONF_ENABLED
359  /* The radio is recalibrated on wakeup */
360  last_dco_calibration_time = clock_seconds();
361 #endif
362 
364 }
365 /*---------------------------------------------------------------------------*/
SENSORS & button_sensor
Exports global symbols for the sensor API.
Definition: z1-sensors.c:46
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:107
Header file for the energy estimation mechanism
void platform_main_loop()
The platform&#39;s main loop, if provided.
Definition: platform.c:188
void platform_init_stage_two()
Stage 2 of platform driver initialisation.
Definition: platform.c:123
void platform_idle()
The platform&#39;s idle/sleep function.
Definition: platform.c:185
void leds_init(void)
Initialise the LED HAL.
Definition: minileds.c:44
Node-id (simple 16-bit identifiers) handling.
Header file for the Contiki-NG main routine.
unsigned long clock_seconds(void)
Get the current value of the platform seconds.
Definition: clock.c:130
void leds_on(unsigned char leds)
Turn on multiple LEDs.
Definition: minileds.c:63
#define LEDS_ALL
The OR mask representation of all device LEDs.
Definition: leds.h:195
void leds_off(unsigned char leds)
Turn off multiple LEDs.
Definition: minileds.c:69
Header file for IPv6-related data structures.
linkaddr_t linkaddr_node_addr
The link-layer address of the node.
Definition: linkaddr.c:48
int serial_line_input_byte(unsigned char c)
Get one byte of input from the serial driver.
Definition: serial-line.c:65
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
void uart0_init(unsigned long ubr)
Initalize the RS232 port.
Definition: uart0.c:139
void watchdog_start(void)
Starts the WDT in watchdog mode if enabled by user configuration, maximum interval.
Definition: watchdog.c:72
MICROMAC_RADIO driver header file
void platform_init_stage_three()
Final stage of platform driver initialisation.
Definition: platform.c:169
void random_init(unsigned short seed)
Seed the cc2538 random number generator.
Definition: random.c:84
void watchdog_init(void)
Initialisation function for the WDT.
Definition: watchdog.c:63
Generic serial I/O process header filer.
Include file for the Contiki low-layer network stack (NETSTACK)
void watchdog_periodic(void)
Writes the WDT clear sequence.
Definition: watchdog.c:85
Header file for the logging system
Header file for the LED HAL.
void rtimer_init(void)
Initialize the real-time scheduler.
Definition: rtimer.c:61
int process_run(void)
Run the system once - call poll handlers and process one event.
Definition: process.c:302
void clock_init(void)
Arch-specific implementation of clock_init for the cc2538.
Definition: clock.c:93
void platform_init_stage_one(void)
Basic (Stage 1) platform driver initialisation.
Definition: platform.c:114
void linkaddr_set_node_addr(linkaddr_t *t)
Set the address of the current node.
Definition: linkaddr.c:75
void watchdog_stop(void)
Stops the WDT such that it won&#39;t timeout and cause MCU reset.