diff --git a/cpu/stm32w108/Makefile.stm32w108 b/cpu/stm32w108/Makefile.stm32w108 index 34fffb3a9..130c17114 100644 --- a/cpu/stm32w108/Makefile.stm32w108 +++ b/cpu/stm32w108/Makefile.stm32w108 @@ -18,7 +18,7 @@ CONTIKI_CPU_DIRS = . dev hal simplemac hal/micro/cortexm3 hal/micro/cortexm3/stm STM32W_C = leds-arch.c leds.c clock.c watchdog.c uart1.c uart1-putchar.c slip_uart1.c slip.c\ stm32w-radio.c stm32w_systick.c uip_arch.c rtimer-arch.c adc.c micro.c sleep.c \ - micro-common.c micro-common-internal.c clocks.c mfg-token.c nvm.c flash.c rand.c + micro-common.c micro-common-internal.c clocks.c mfg-token.c nvm.c flash.c rand.c system-timer.c STM32W_S = spmr.s79 context-switch.s79 diff --git a/cpu/stm32w108/clock.c b/cpu/stm32w108/clock.c index f40af1ae5..aa47d39c7 100644 --- a/cpu/stm32w108/clock.c +++ b/cpu/stm32w108/clock.c @@ -45,8 +45,14 @@ #include "hal/hal.h" #include "dev/stm32w_systick.h" -#include "sys/clock.h" -#include "sys/etimer.h" +#include "contiki.h" + +#include "uart1.h" +#include "dev/leds.h" +#include "dev/stm32w-radio.h" + +#define DEBUG DEBUG_NONE +#include "net/uip-debug.h" // The value that will be load in the SysTick value register. #define RELOAD_VALUE 24000-1 // 1 ms with a 24 MHz clock @@ -77,9 +83,9 @@ void SysTick_Handler(void) void clock_init(void) { - INTERRUPTS_OFF(); - - //Counts the number of ticks. + ATOMIC( + + //Counts the number of ticks. count = 0; SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); @@ -87,7 +93,8 @@ void clock_init(void) SysTick_ITConfig(ENABLE); SysTick_CounterCmd(SysTick_Counter_Enable); - INTERRUPTS_ON(); + ) + } /*---------------------------------------------------------------------------*/ @@ -128,3 +135,51 @@ unsigned long clock_seconds(void) { return current_seconds; } + +#include + +void sleep_seconds(int seconds) +{ + int32u quarter_seconds = seconds * 4; + uint8_t radio_on; + + + halPowerDown(); + radio_on = stm32w_radio_is_on(); + stm32w_radio_driver.off(); + + halSleepForQsWithOptions(&quarter_seconds, 0); + + + ATOMIC( + + halPowerUp(); + + // Update OS system ticks. + current_seconds += seconds - quarter_seconds / 4 ; // Passed seconds + count += seconds * CLOCK_SECOND - quarter_seconds * CLOCK_SECOND / 4 ; + + if(etimer_pending()) { + etimer_request_poll(); + } + + SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); + SysTick_SetReload(RELOAD_VALUE); + SysTick_ITConfig(ENABLE); + SysTick_CounterCmd(SysTick_Counter_Enable); + + ) + + stm32w_radio_driver.init(); + if(radio_on){ + stm32w_radio_driver.on(); + } + + uart1_init(115200); + leds_init(); + rtimer_init(); + + PRINTF("WakeInfo: %04x\r\n", halGetWakeInfo()); + + +} diff --git a/cpu/stm32w108/dev/stm32w-radio.c b/cpu/stm32w108/dev/stm32w-radio.c index 47e839631..fcbae0480 100644 --- a/cpu/stm32w108/dev/stm32w-radio.c +++ b/cpu/stm32w108/dev/stm32w-radio.c @@ -395,7 +395,11 @@ static int stm32w_radio_on(void) return 1; } - +/*---------------------------------------------------------------------------*/ +int stm32w_radio_is_on(void) +{ + return onoroff == ON; +} /*---------------------------------------------------------------------------*/ @@ -512,7 +516,7 @@ PROCESS_THREAD(stm32w_radio_process, ev, data) NETSTACK_RDC.input(); } if(!RXBUFS_EMPTY()){ - // Some data packet still in rx buffer (this appens because process_poll doesn't queue requests), + // Some data packet still in rx buffer (this happens because process_poll doesn't queue requests), // so stm32w_radio_process need to be called again. process_poll(&stm32w_radio_process); } diff --git a/cpu/stm32w108/dev/stm32w-radio.h b/cpu/stm32w108/dev/stm32w-radio.h index a94e9b016..a2bdc3e54 100644 --- a/cpu/stm32w108/dev/stm32w-radio.h +++ b/cpu/stm32w108/dev/stm32w-radio.h @@ -53,5 +53,7 @@ short last_packet_rssi(); extern const struct radio_driver stm32w_radio_driver; +int stm32w_radio_is_on(void); + #endif /* __STM32W_H__ */ diff --git a/cpu/stm32w108/sleep.h b/cpu/stm32w108/sleep.h new file mode 100644 index 000000000..6b87814e6 --- /dev/null +++ b/cpu/stm32w108/sleep.h @@ -0,0 +1,10 @@ + +/* Enter system in deep sleep 1 (core power domain is fully + * powered down and sleep timer is active). + * Execution is suspended for a given number of seconds. + * + * Pay attention! All system peripherals (including sensors) have + * to be reinitialized before being used again. UART, LEDs and + * real timers are automatically reinitialized. */ + +void sleep_seconds(int seconds); diff --git a/examples/mb851/udp-ipv6-sleep/Makefile b/examples/mb851/udp-ipv6-sleep/Makefile new file mode 100644 index 000000000..476065d4a --- /dev/null +++ b/examples/mb851/udp-ipv6-sleep/Makefile @@ -0,0 +1,8 @@ +all: udp-server udp-client + +UIP_CONF_IPV6=1 + +DEFINES=UIP_CONF_ND6_REACHABLE_TIME=0xffffffff + +CONTIKI = ../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/mb851/udp-ipv6-sleep/README b/examples/mb851/udp-ipv6-sleep/README new file mode 100644 index 000000000..94af770f3 --- /dev/null +++ b/examples/mb851/udp-ipv6-sleep/README @@ -0,0 +1,7 @@ +Thi is an example based on the udp-ipv6 example. A client periodically sends +UDP packets to a fixed server. The client will also go in a deep sleep state +during wich all system peripherals are turned off to save as more energy as +possible. + +To avoid blocking the entire OS for too long time, the system periocally +wakes up to let the OS poll processes and dispatch events. diff --git a/examples/mb851/udp-ipv6-sleep/udp-client.c b/examples/mb851/udp-ipv6-sleep/udp-client.c new file mode 100644 index 000000000..dfae03ddc --- /dev/null +++ b/examples/mb851/udp-ipv6-sleep/udp-client.c @@ -0,0 +1,188 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +#include "contiki.h" +#include "contiki-lib.h" +#include "contiki-net.h" + +#include "sleep.h" +#include "board-mb851.h" + +#include + +#define DEBUG DEBUG_PRINT +#include "net/uip-debug.h" + +#define SEND_INTERVAL 25 * CLOCK_SECOND + +/* Seconds during which the system must be in deep sleep. + * During deep sleep all the OS is frozen. */ +#define SLEEP_INTERVAL_SECONDS 6 +/* System does not go to sleep until AWAKE_INTERVAL is passed. + * This is done to let IP stack receive Neigbhor Advertisements + * and eventual response packets from the server. */ +#define AWAKE_INTERVAL 3 * CLOCK_SECOND +#define MAX_PAYLOAD_LEN 40 + +static struct uip_udp_conn *client_conn; +/*---------------------------------------------------------------------------*/ +PROCESS(udp_client_process, "UDP client process"); +AUTOSTART_PROCESSES(&udp_client_process); +/*---------------------------------------------------------------------------*/ +static void +tcpip_handler(void) +{ + char *str; + + if(uip_newdata()) { + str = uip_appdata; + str[uip_datalen()] = '\0'; + printf("Response from the server: '%s'\n", str); + } +} +/*---------------------------------------------------------------------------*/ +static void +timeout_handler(void) +{ + static int seq_id; + char buf[MAX_PAYLOAD_LEN]; + + printf("Client sending to: "); + PRINT6ADDR(&client_conn->ripaddr); + sprintf(buf, "Hello %d from the client", ++seq_id); + printf(" (msg: %s)\n", buf); +#if SEND_TOO_LARGE_PACKET_TO_TEST_FRAGMENTATION + uip_udp_packet_send(client_conn, buf, UIP_APPDATA_SIZE); +#else /* SEND_TOO_LARGE_PACKET_TO_TEST_FRAGMENTATION */ + uip_udp_packet_send(client_conn, buf, strlen(buf)); +#endif /* SEND_TOO_LARGE_PACKET_TO_TEST_FRAGMENTATION */ +} +/*---------------------------------------------------------------------------*/ +static void +print_local_addresses(void) +{ + int i; + uint8_t state; + + PRINTF("Client IPv6 addresses: "); + for(i = 0; i < UIP_DS6_ADDR_NB; i++) { + state = uip_ds6_if.addr_list[i].state; + if(uip_ds6_if.addr_list[i].isused && + (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) { + PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr); + PRINTF("\n"); + } + } +} +/*---------------------------------------------------------------------------*/ +#if UIP_CONF_ROUTER +static void +set_global_address(void) +{ + uip_ipaddr_t ipaddr; + + uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0); + uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); + uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); +} +#endif /* UIP_CONF_ROUTER */ +/*---------------------------------------------------------------------------*/ +static void +set_connection_address(uip_ipaddr_t *ipaddr) +{ +#define _QUOTEME(x) #x +#define QUOTEME(x) _QUOTEME(x) +#ifdef UDP_CONNECTION_ADDR + if(uiplib_ipaddrconv(QUOTEME(UDP_CONNECTION_ADDR), ipaddr) == 0) { + PRINTF("UDP client failed to parse address '%s'\n", QUOTEME(UDP_CONNECTION_ADDR)); + } +#elif UIP_CONF_ROUTER + uip_ip6addr(ipaddr,0xaaaa,0,0,0,0x0280,0xe102,0x0000,0x008a); +#else + uip_ip6addr(ipaddr,0xfe80,0,0,0,0x0280,0xe102,0x0000,0x008a); +#endif /* UDP_CONNECTION_ADDR */ +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(udp_client_process, ev, data) +{ + static struct etimer et, wake_timer, periodic_timer; + uip_ipaddr_t ipaddr; + + PROCESS_BEGIN(); + PRINTF("UDP client process started\n"); + +#if UIP_CONF_ROUTER + set_global_address(); +#endif + + print_local_addresses(); + + set_connection_address(&ipaddr); + + /* new connection with remote host */ + client_conn = udp_new(&ipaddr, UIP_HTONS(3000), NULL); + udp_bind(client_conn, UIP_HTONS(3001)); + + PRINTF("Created a connection with the server "); + PRINT6ADDR(&client_conn->ripaddr); + PRINTF(" local/remote port %u/%u\n", + UIP_HTONS(client_conn->lport), UIP_HTONS(client_conn->rport)); + + etimer_set(&et, CLOCK_SECOND*10); + PROCESS_WAIT_UNTIL(etimer_expired(&et)); // Wait for DAD and Router Discovery procedure to end. + + etimer_set(&et, SEND_INTERVAL); + etimer_set(&wake_timer, AWAKE_INTERVAL); + etimer_set(&periodic_timer, 1); + + while(1) { + PROCESS_YIELD(); + if(etimer_expired(&wake_timer)){ // if timer hasn't expired do not go in deep sleep, in order to receive a response. + printf("Sleeping...\r\n"); + sensorsPowerDown(); + sleep_seconds(SLEEP_INTERVAL_SECONDS); // Put system in deep sleep mode for a while. + sensorsPowerUp(); + printf("Awake\r\n"); + } + if(etimer_expired(&et)) { + timeout_handler(); + etimer_restart(&et); + etimer_restart(&wake_timer); + } else if(ev == tcpip_event) { + tcpip_handler(); + } + + /* Make the process be called almost immediately, + * so that it can force the system to go into deep sleep. */ + etimer_restart(&periodic_timer); + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/mb851/udp-ipv6-sleep/udp-server.c b/examples/mb851/udp-ipv6-sleep/udp-server.c new file mode 100644 index 000000000..1dc9279a5 --- /dev/null +++ b/examples/mb851/udp-ipv6-sleep/udp-server.c @@ -0,0 +1,117 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +#include "contiki.h" +#include "contiki-lib.h" +#include "contiki-net.h" + +#include + +#define DEBUG DEBUG_PRINT +#include "net/uip-debug.h" + +#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) + +#define MAX_PAYLOAD_LEN 120 + +static struct uip_udp_conn *server_conn; + +PROCESS(udp_server_process, "UDP server process"); +AUTOSTART_PROCESSES(&udp_server_process); +/*---------------------------------------------------------------------------*/ +static void +tcpip_handler(void) +{ + static int seq_id; + char buf[MAX_PAYLOAD_LEN]; + + if(uip_newdata()) { + ((char *)uip_appdata)[uip_datalen()] = 0; + PRINTF("Server received: '%s' from ", (char *)uip_appdata); + PRINT6ADDR(&UIP_IP_BUF->srcipaddr); + PRINTF("\n"); + + uip_ipaddr_copy(&server_conn->ripaddr, &UIP_IP_BUF->srcipaddr); + PRINTF("Responding with message: "); + sprintf(buf, "Hello from the server! (%d)", ++seq_id); + PRINTF("%s\n", buf); + + uip_udp_packet_send(server_conn, buf, strlen(buf)); + /* Restore server connection to allow data from any node */ + memset(&server_conn->ripaddr, 0, sizeof(server_conn->ripaddr)); + } +} +/*---------------------------------------------------------------------------*/ +static void +print_local_addresses(void) +{ + int i; + uint8_t state; + + PRINTF("Server IPv6 addresses: "); + for(i = 0; i < UIP_DS6_ADDR_NB; i++) { + state = uip_ds6_if.addr_list[i].state; + if(uip_ds6_if.addr_list[i].isused && + (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) { + PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr); + PRINTF("\n"); + } + } +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(udp_server_process, ev, data) +{ +#if UIP_CONF_ROUTER + uip_ipaddr_t ipaddr; +#endif /* UIP_CONF_ROUTER */ + + PROCESS_BEGIN(); + PRINTF("UDP server started\n"); + +#if UIP_CONF_ROUTER + uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0); + uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); + uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); +#endif /* UIP_CONF_ROUTER */ + + print_local_addresses(); + + server_conn = udp_new(NULL, UIP_HTONS(3001), NULL); + udp_bind(server_conn, UIP_HTONS(3000)); + + while(1) { + PROCESS_YIELD(); + if(ev == tcpip_event) { + tcpip_handler(); + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/platform/mb851/board-mb851.c b/platform/mb851/board-mb851.c index c66e811bd..e801b4c2e 100644 --- a/platform/mb851/board-mb851.c +++ b/platform/mb851/board-mb851.c @@ -1,16 +1,93 @@ #include PLATFORM_HEADER #include BOARD_HEADER +#include "dev/button-sensor.h" +#include "dev/temperature-sensor.h" +#include "dev/acc-sensor.h" + void halBoardInit(void) { return; } +static uint8_t sensors_status; + +#define BUTTON_STATUS_ACTIVE (1 << 0) +#define TEMP_STATUS_ACTIVE (1 << 1) +#define ACC_STATUS_ACTIVE (1 << 2) + void halBoardPowerDown(void) { + /* Set everything to input value */ + GPIO_PACFGL = (GPIOCFG_IN <