SingingCat 0
application
powersave.c
Go to the documentation of this file.
1#include "powersave.h"
2#include "networkif.h"
3#include "main-header.h"
4#include "streams.h"
5#include "powerup.h"
6#include <platform-header.h>
7#include "led.h"
8
19// powersave variables for mainloop condition evaluation
20#define SECS_AFTER_BOOT_BEFORE_POWERSAFE 120
21#define SECS_AFTER_WAKE_BEFORE_POWERSAFE 10
22
23// wait some time after the last command was sent or the last stream was closed before sleeping
24#define SECS_AFTER_LASTCOM_BEFORE_POWERSAFE 3
25
26// #define MAX_SECS_BEFORE_SCHEDULED_WAKEUP 300
27static long throttle_after_fast = 0; // if something makes the cpu go fast, do not throttle immediately, wait a few secs
28static long powersave_afterwake = 0;
29static long powersave_aftercom = 0;
30static byte powermode = 0;
31static byte booted = 0;
32//static int powermodectr = 15;// only go into powersave mode if this counter hits 0
33static void power_mcusleep();
34static void trigger_send_powering_down();
35// store a previous power_state
36typedef struct power_state {
37 byte wifi_on;
38 byte ti1101_on;
39 byte lora_on;
41
42struct power_state prev_state;
43
44int power_set_connectivity(struct power_state *ps, int turnon) {
45 if (turnon) {
46 printf("[power] Turning connectivity on...\r\n");
47 if (ps->wifi_on) {
49 }
50 // TODO - make this an interator
51 if (ps->ti1101_on) {
52 start_nic_by_type(SOURCE_RADIO);
53 }
54 if (ps->lora_on) {
55 start_nic_by_type(SOURCE_LORA);
56 }
58 send_routing_update_now();
59 } else {
60 trigger_send_powering_down();
61 printf("[power] Turning connectivity off...\r\n");
62 ps->wifi_on = esp8266_is_enabled();
64 ps->ti1101_on = stop_nic_by_type(SOURCE_RADIO);
65 ps->lora_on = stop_nic_by_type(SOURCE_LORA);
66 }
67 return 0;
68}
69/*
70 * \brief set power level (state is a combination of flags of what ought to be enabled)
71 * returns 0 if ok, otherwise error
72 */
73int set_mcu_power_mode(int state) {
74 // struct power_state *ps = &prev_state;
75 struct cnw_config *cfg = config_get_ram_struct();
76
77 //power_set_connectivity(ps, state & (1 << POWER_CONNECTIVITY));
78 if (state == 0) {
79 led_set_machine_managed();
80 led_indicate(LED_POWERSAVE);
81 } else {
82 led_set_user_managed();
83 }
84 if (state == 0) {
85 printf("[power] Going to low power mode for %i secs...\r\n\r\n", cfg->sleep_duration); // extra CR because last byte might get eaten by sleep
86 mculib_sleep(0, cfg->sleep_duration); //seconds to sleep, returns after this number of seconds
87 state = 0xFF; //wakeup
88 // it does not print after startup oddly
89 /*
90 * int i;
91 * for (i=0;i<100;i++) {
92 * printf("[power] %i Woke up from low power mode...\r\n",i);
93 * }
94 */
95 //power_set_connectivity(ps, state & (1 << POWER_CONNECTIVITY));
96 }
97 return 0;
98}
99
100/*
101 * \brief set power level to the most appropriate
102 */
103void calc_power_mode() {
104}
105
106// called in main loop. might block for a long time (when it determines it is time to sleep)
107void power_main_loop() {
108 // if disabled, do not do anything
109 if (!config_get_flag(CONFIG_FLAGS_POWER_SAVE)) {
110 return;
111 }
112 // if powerup has not been delivered, do not do anything
113 if (!powerup_delivered()) {
114 return;
115 }
116
117 // on first boot, we wait with going to sleep
118 if (!booted) {
119 if (mculib_has_time_passed(SECS_AFTER_BOOT_BEFORE_POWERSAFE, &powersave_afterwake) == 0) {
120 return;
121 }
122 booted = 1;
123 }
124 struct cnw_config *cfg = config_get_ram_struct();
125
126 if (cfg == NULL) {
127 // no config? do not powersave. this is highly odd
128 return;
129 }
130 if (config_get_powermode_flag(CONFIG_POWERFLAG_THROTTLE)) {
131 if (mculib_has_time_passed(10, &throttle_after_fast)) {
132 power_set_speed(1);
133 }
134 }
135 // deal with mcu sleep
136 power_mcusleep();
137 return;
138}
139// this might put the mcu to sleep, so it might not return until mcu wakes up some seconds later
140void power_mcusleep() {
141 struct cnw_config *cfg = config_get_ram_struct();
142
143 if ((cfg->sleep_duration == 0) || (cfg->nonsleep_duration == 0)) {
144 // if sleep/nonsleep is 0, do not sleep, that's a misconfiguration of sort
145 return;
146 }
147
148 // powermode starts as '0'.
149 // powermode == 1 means that the module is trying to get to sleep (e.g. after last com was sent)
150 // powermode == 0 means that the module has just woken up and won't go to sleep for a certain duration
151
152 if (powermode == 0) {
153 if (mculib_has_time_passed(cfg->nonsleep_duration, &powersave_afterwake) == 0) {
154 // still staying awake until time has passed.
155 return;
156 }
157 mculib_has_time_passed(0, &powersave_aftercom); // reset timer
158 // mark that it is time to go to sleep
159 powermode = 1;
160 return;
161 }
162
163
164 if (powermode == 1) {
166 // don't go to sleep, we still got outbound commands or open streams
167 mculib_has_time_passed(0, &powersave_aftercom); // reset timer
168 return;
169 }
170 if (mculib_has_time_passed(SECS_AFTER_LASTCOM_BEFORE_POWERSAFE, &powersave_aftercom) == 0) {
171 // too soon after command or openstream, don't sleep just yet
172 return;
173 }
174 }
175
176 // printf("[power] Powerdue counter: %i, secs_since_boot: %i\r\n",(int)powersave_due,(int)mculib_get_seconds_since_boot());
177 powermode = 0;
178 set_mcu_power_mode(0); // got to sleep
179 // we do this with the assumption that it will return true, because we slept for >1 second
180 // the (important) side-effect is that it will set the powersave_due counter, so that
181 // next time we check if we got to go to powersave mode we won't immediately activate it
182 mculib_has_time_passed(0, &powersave_aftercom); // reset timer
183 mculib_has_time_passed(0, &powersave_afterwake); // reset timer
184 //printf("[power] Powerdue counter: %i, secs_since_boot: %i\r\n",(int)powersave_due,(int)mculib_get_seconds_since_boot());
185}
186
187static void trigger_send_powering_down() {
188 int r = 0;
189 int z;
190 struct command *com;
191
192 // send to server
193 com = alloc_command();
194 if (com != NULL) {
195 com->com = 60; //powerinfo
196 com->target = CLOUD_SERVER;
197 command_add_arg(com, "powerstate=low");
198 for (z = 0; z < 10; z++) {
199 r = send_command(com);
200 if (r == 0) {
201 break;
202 }
203 }
205 }
206 printf("[power] Result of sending powerinfo to server: %i\r\n", r);
207
208 // send to broadcast
209 com = alloc_command();
210 if (com != NULL) {
211 com->com = 60; //powerinfo
212 com->target = BROADCAST;
213 command_add_arg(com, "powerstate=low");
214 for (z = 0; z < 10; z++) {
215 r = send_command(com);
216 if (r == 0) {
217 break;
218 }
219 }
221 }
222 printf("[power] Result of sending powerinfo broadcast: %i\r\n", r);
223}
224
225void power_set_speed(int speed) {
226 if (speed != 1) {
227 mculib_has_time_passed(0, &throttle_after_fast); // reset timer
228 }
229 /*
230 * printf("[power] not changing speed, because usart dies if we do, and so does usb\r\n");
231 * return;
232 */
233 if (!config_get_flag(CONFIG_FLAGS_POWER_SAVE)) {
234 return;
235 }
236
237 if (mculib_get_speed() == speed) {
238 return;
239 }
240 printf("[power] setting mculib speed to %i\r\n", speed);
241 mculib_set_speed(speed);
242 /*
243 * mculib_serialport_enable(MAIN_MCULIBHANDLE, USART_CONSOLE, 115200);
244 * mculib_serialport_enable(MAIN_MCULIBHANDLE, USART_ESP8266, esp8266_get_operational_baudrate());
245 */
246}
247
248
249typedef struct powersavething {
251
252void init_powersavething(struct powersavething *pst) {
253}
254
255// mark this thing as "in use" right now
256void mark_last_in_use(struct powersavething *pst) {
257}
void esp8266_enable()
enable the esp8266 (switch it on)
Definition: esp8266.c:1442
int send_command(struct command *com)
send a command to another module (or broadcast)
Definition: queue.c:374
void free_command(struct command *com)
free a command
Definition: queue.c:200
void remove_stale_routes()
"old" routes are being removed this is the route garbage collector
Definition: routing.c:264
void command_add_arg(struct command *com, const char *format,...)
adds an arg to a partially initialised command structure
int get_outbound_command_count_important()
return number of commands to be delivered (apart from announce/noop)
Definition: queue.c:813
int count_open_streams()
count number of open streams
Definition: streams.c:624
void esp8266_disable()
disable the esp8266 (switch it off)
Definition: esp8266.c:1446
struct command * alloc_command()
allocate a free command
Definition: queue.c:173
int com
Definition: command.h:22