Mercurial > ~darius > hgwebdir.cgi > sprink
comparison sprink.c @ 5:951277329ee6
Use splitargv instead of rolling our own.
Fix WDT tripping continuously on self reset (disable WDT on startup).
Pretty up startup message.
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Sun, 15 Feb 2015 16:16:54 +1030 |
parents | 1188042ddc2f |
children | 78983502a4e9 |
comparison
equal
deleted
inserted
replaced
4:1188042ddc2f | 5:951277329ee6 |
---|---|
34 #include <ctype.h> | 34 #include <ctype.h> |
35 #include <stdlib.h> | 35 #include <stdlib.h> |
36 #include <util/delay.h> | 36 #include <util/delay.h> |
37 #include <avr/wdt.h> | 37 #include <avr/wdt.h> |
38 | 38 |
39 #include "1wire.h" | |
39 #include "bitstring.h" | 40 #include "bitstring.h" |
40 #include "cons.h" | 41 #include "cons.h" |
41 #include "ds1307.h" | 42 #include "ds1307.h" |
42 #include "1wire.h" | 43 #include "splitargv.h" |
43 #include "water.h" | 44 #include "water.h" |
45 | |
46 #define MAXARGS 10 | |
44 | 47 |
45 /* | 48 /* |
46 ** Fuse bits should be set as follows | 49 ** Fuse bits should be set as follows |
47 ** | 50 ** |
48 ** EFUSE - BOD 4.3V -> xxxxx100 -> 0xfc | 51 ** EFUSE - BOD 4.3V -> xxxxx100 -> 0xfc |
88 int | 91 int |
89 main(void) { | 92 main(void) { |
90 /* Disable interrupts while we frob stuff */ | 93 /* Disable interrupts while we frob stuff */ |
91 cli(); | 94 cli(); |
92 | 95 |
96 /* Disable watchdog in case it was previously on */ | |
97 wdt_disable(); | |
98 | |
93 /* Init UART */ | 99 /* Init UART */ |
94 cons_init(); | 100 cons_init(); |
95 | 101 |
102 printf_P(PSTR("\r\n\r\n===============\r\n")); | |
103 | |
96 /* Init TWI etc */ | 104 /* Init TWI etc */ |
97 ds1307_init(); | 105 ds1307_init(); |
98 | 106 |
99 /* Set up the one wire stuff */ | 107 /* Set up the one wire stuff */ |
100 OWInit(); | 108 OWInit(); |
101 | 109 |
102 /* Init water control state machine */ | |
103 water_init(); | |
104 | |
105 /* Analogue input is PA0:7 */ | 110 /* Analogue input is PA0:7 */ |
106 DDRA = 0x00; | 111 DDRA = 0x00; |
107 PORTA = 0x00; | 112 PORTA = 0x00; |
108 DIDR0 = 0xff; /* Disable digital input buffers */ | 113 DIDR0 = 0xff; /* Disable digital input buffers */ |
109 #ifdef PRR | 114 #ifdef PRR |
110 PRR &= ~_BV(PRADC); /* Power ADC on - note that the | 115 PRR &= ~_BV(PRADC); /* Power ADC on - note that the |
111 * datasheet says this is already 0 at | 116 * datasheet says this is already 0 at |
112 * power on.. */ | 117 * power on.. */ |
113 #endif | 118 #endif |
114 | 119 |
115 /* PB0 Used for 1-wire bus | 120 /* PB0 Used for 1-wire bus |
116 * PB4:7 Used for relay board */ | 121 * PB4:7 Used for relay board */ |
117 DDRB = 0xf0; | 122 DDRB = 0xf0; |
118 PORTB = 0x00; | 123 PORTB = 0x00; |
119 | 124 |
123 | 128 |
124 /* USART (0:1) */ | 129 /* USART (0:1) */ |
125 DDRD = 0x03; | 130 DDRD = 0x03; |
126 PORTD = 0x03; | 131 PORTD = 0x03; |
127 | 132 |
128 printf_P(PSTR("\r\n\r\n===============\r\n" | 133 fputs_P(PSTR("Reset cause: "), stdout); |
129 "Inited!\r\n\r\n")); | |
130 | |
131 if ((mcucsr & _BV(PORF)) == _BV(PORF)) | 134 if ((mcucsr & _BV(PORF)) == _BV(PORF)) |
132 printf_P(PSTR("Power on\r\n")); | 135 printf_P(PSTR("Power on\r\n")); |
133 | 136 |
134 if ((mcucsr & _BV(EXTRF)) == _BV(EXTRF)) | 137 if ((mcucsr & _BV(EXTRF)) == _BV(EXTRF)) |
135 printf_P(PSTR("External\r\n")); | 138 printf_P(PSTR("External\r\n")); |
146 #endif | 149 #endif |
147 | 150 |
148 /* Ready to go! */ | 151 /* Ready to go! */ |
149 sei(); | 152 sei(); |
150 | 153 |
154 /* Init water control state machine */ | |
155 water_init(); | |
156 | |
151 /* | 157 /* |
152 * Enable the watchdog with the largest prescaler. Will cause a | 158 * Enable the watchdog with the largest prescaler. Will cause a |
153 * watchdog reset after approximately 2 s @ Vcc = 5 V | 159 * watchdog reset after approximately 2 s @ Vcc = 5 V |
154 * | |
155 * Gets reset in the loop below and in the tempctrl.c timer IRQ | |
156 */ | 160 */ |
157 wdt_enable(WDTO_2S); | 161 wdt_enable(WDTO_2S); |
158 | 162 |
159 printf_P(PSTR("> ")); | 163 printf_P(PSTR("> ")); |
160 cmd.state = 0; | 164 cmd.state = 0; |
161 | 165 |
162 /* Wait for user input or an "interrupt" */ | 166 /* Wait for user input or an "interrupt" */ |
163 while (1) { | 167 while (1) { |
164 wdt_reset(); | 168 wdt_reset(); |
165 | 169 |
166 water_update(); | 170 water_update(); |
167 | 171 |
168 if (cmd.state == 255) { | 172 if (cmd.state == 255) { |
169 process_cmd(); | 173 process_cmd(); |
170 printf_P(PSTR("> ")); | 174 printf_P(PSTR("> ")); |
171 /* Allow new characters to be processed */ | 175 /* Allow new characters to be processed */ |
172 cmd.state = 0; | 176 cmd.state = 0; |
174 } | 178 } |
175 } | 179 } |
176 | 180 |
177 void | 181 void |
178 process_cmd(void) { | 182 process_cmd(void) { |
183 int argc; | |
184 char *argv[MAXARGS]; | |
185 | |
179 /* User just pressed enter */ | 186 /* User just pressed enter */ |
180 if (cmd.len == 0) | 187 if (cmd.len == 0) |
181 return; | 188 return; |
182 | 189 |
183 if (!strcasecmp_P((char *)cmd.buf, PSTR("?")) || | 190 /* Split buffer into argv/argc (and de-volatilise) */ |
184 !strcasecmp_P((char *)cmd.buf, PSTR("help"))) { | 191 splitargv((char *)cmd.buf, 0, argv, MAXARGS, &argc); |
192 | |
193 if (argc == 0) | |
194 return; | |
195 | |
196 if (!strcasecmp_P(argv[0], PSTR("?")) || | |
197 !strcasecmp_P(argv[0], PSTR("help"))) { | |
185 puts_P(PSTR("help This help\r\n" | 198 puts_P(PSTR("help This help\r\n" |
186 "wa all dly time Water all regions for time minutes after dly minutes\r\n" | 199 "wa all dly time Water all regions for time minutes after dly minutes\r\n" |
187 "gc Get time of day\r\n" | 200 "gc Get time of day\r\n" |
188 "sc time Set time of day (time is YYYY/MM/DD HH:MM:SS)\r\n" | 201 "sc time Set time of day (time is YYYY/MM/DD HH:MM:SS)\r\n" |
189 "in port Read from a port\r\n" | 202 "in port Read from a port\r\n" |
197 "rc Read byte from 1-wire bus\r\n" | 210 "rc Read byte from 1-wire bus\r\n" |
198 "wb bit Write bit to 1-wire bus\r\n" | 211 "wb bit Write bit to 1-wire bus\r\n" |
199 "wc byte Write byte to 1-wire bus\r\n" | 212 "wc byte Write byte to 1-wire bus\r\n" |
200 "zz Reset micro\r\n")); | 213 "zz Reset micro\r\n")); |
201 return; | 214 return; |
202 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wa"), 2)) { | 215 } else if (!strcasecmp_P(argv[0], PSTR("wa"))) { |
203 water_cmd((char *)cmd.buf); | 216 water_cmd(argc - 1, argv + 1); |
204 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("gc"), 2)) { | 217 } else if (!strcasecmp_P(argv[0], PSTR("an"))) { |
205 ds1307_printnow(PSTR(""), PSTR("\r\n")); | |
206 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("sc"), 2)) { | |
207 if (cmd.len < 17) { | |
208 printf_P(PSTR("Invalid TOD\r\n")); | |
209 } else { | |
210 if (ds1307_settod((char *)cmd.buf + 3) != 1) | |
211 printf_P(PSTR("Unable to set TOD\r\n")); | |
212 } | |
213 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("in"), 2)) { | |
214 uint8_t inp; | |
215 | |
216 switch (tolower(cmd.buf[3])) { | |
217 case 'a': | |
218 inp = PINA; | |
219 break; | |
220 | |
221 case 'b': | |
222 inp = PINB; | |
223 break; | |
224 | |
225 case 'c': | |
226 inp = PINC; | |
227 break; | |
228 | |
229 case 'd': | |
230 inp = PIND; | |
231 break; | |
232 | |
233 default: | |
234 printf_P(PSTR("Unknown port\r\n")); | |
235 return; | |
236 } | |
237 printf_P(PSTR("PORT %c <= 0x%02x\r\n"), toupper(cmd.buf[3]), inp); | |
238 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("an"), 2)) { | |
239 uint16_t res; | 218 uint16_t res; |
240 int pin; | 219 int pin; |
241 | 220 char *eptr; |
242 if (sscanf_P((char *)cmd.buf, PSTR("an %d"), &pin) != 1) { | 221 |
222 if (argc != 2) { | |
223 printf_P(PSTR("Bad usage\r\n")); | |
224 return; | |
225 } | |
226 | |
227 pin = strtol(argv[1], &eptr, 0); | |
228 if (eptr == argv[1]) { | |
243 printf_P(PSTR("Unable to parse\r\n")); | 229 printf_P(PSTR("Unable to parse\r\n")); |
244 return; | 230 return; |
245 } | 231 } |
246 if (pin < 0 || pin > 7) { | 232 if (pin < 0 || pin > 7) { |
247 printf_P(PSTR("Unknown pin\r\n")); | 233 printf_P(PSTR("Unknown pin\r\n")); |
248 return; | 234 return; |
249 } | 235 } |
250 | 236 |
251 /* Select desired pin, use AVREF */ | 237 /* Select desired pin, use AVREF */ |
252 ADMUX = _BV(pin); | 238 ADMUX = _BV(pin); |
253 | 239 |
254 /* Enable ADC, start conversion, set divisor to 64 | 240 /* Enable ADC, start conversion, set divisor to 64 |
255 * (8e6 / 64 => 125kHz (max is 200kHz) | 241 * (8e6 / 64 => 125kHz (max is 200kHz) |
256 */ | 242 */ |
257 ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADPS2) | _BV(ADPS1); | 243 ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADPS2) | _BV(ADPS1); |
258 | 244 |
262 res = ADCL | (ADCH << 8); | 248 res = ADCL | (ADCH << 8); |
263 printf_P(PSTR("Pin %d <= %hhd\r\n"), pin, res); | 249 printf_P(PSTR("Pin %d <= %hhd\r\n"), pin, res); |
264 | 250 |
265 /* Disable ADC */ | 251 /* Disable ADC */ |
266 ADCSRA = 0; | 252 ADCSRA = 0; |
267 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("ou"), 2)) { | 253 } else if (!strcasecmp_P(argv[0], PSTR("ou"))) { |
268 char port; | |
269 int val; | 254 int val; |
270 | 255 char *eptr; |
271 if (sscanf_P((char *)cmd.buf, PSTR("ou %c %x"), &port, &val) != 2) { | 256 |
272 printf_P(PSTR("Unable to parse\r\n")); | 257 if (argc != 3) { |
273 return; | 258 printf_P(PSTR("Bad usage\r\n")); |
274 } | 259 return; |
275 | 260 } |
276 switch (port) { | 261 |
262 val = strtol(argv[2], &eptr, 0); | |
263 if (eptr == argv[2]) { | |
264 printf_P(PSTR("Unable to parse val\r\n")); | |
265 return; | |
266 } | |
267 | |
268 switch (argv[1][0]) { | |
277 case 'a': | 269 case 'a': |
278 PORTA = val & 0xff; | 270 PORTA = val & 0xff; |
279 break; | 271 break; |
280 | 272 |
281 case 'b': | 273 case 'b': |
282 PORTB = val & 0xff; | 274 PORTB = val & 0xff; |
283 break; | 275 break; |
284 | 276 |
285 case 'c': | 277 case 'c': |
286 PORTC = val & 0xff; | 278 PORTC = val & 0xff; |
287 break; | 279 break; |
288 | 280 |
289 case 'd': | 281 case 'd': |
290 PORTD = val & 0xff; | 282 PORTD = val & 0xff; |
291 break; | 283 break; |
292 | 284 |
293 default: | 285 default: |
294 printf_P(PSTR("Unknown port\r\n")); | 286 printf_P(PSTR("Unknown port\r\n")); |
295 return; | 287 return; |
296 } | 288 } |
297 printf_P(PSTR("PORT%c <= 0x%02x\r\n"), toupper(port), val); | 289 printf_P(PSTR("PORT%c <= 0x%02x\r\n"), toupper(argv[1][0]), val); |
298 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("dd"), 2)) { | 290 } else if (!strcasecmp_P(argv[0], PSTR("dd"))) { |
299 char port; | |
300 uint8_t val; | 291 uint8_t val; |
301 int num; | 292 char *eptr; |
302 | 293 |
303 num = sscanf_P((char *)cmd.buf, PSTR("dd %c %x"), &port, &val); | 294 if (argc != 2 && argc != 3) { |
304 | 295 printf_P(PSTR("Bad usage\r\n")); |
305 if (num != 1 && num != 2) { | 296 return; |
306 printf_P(PSTR("Unable to parse dd arguments\r\n")); | 297 } |
307 return; | 298 |
308 } | 299 if (argc == 1) { |
309 | 300 switch (argv[1][0]) { |
310 if (num == 1) { | |
311 switch (port) { | |
312 case 'a': | 301 case 'a': |
313 DDRA = val; | 302 DDRA = val; |
314 break; | 303 break; |
315 | 304 |
316 case 'b': | 305 case 'b': |
318 break; | 307 break; |
319 | 308 |
320 case 'c': | 309 case 'c': |
321 DDRC = val; | 310 DDRC = val; |
322 break; | 311 break; |
323 | 312 |
324 case 'd': | 313 case 'd': |
325 DDRD = val; | 314 DDRD = val; |
326 break; | 315 break; |
327 | 316 |
328 default: | 317 default: |
329 printf_P(PSTR("Unknown port\r\n")); | 318 printf_P(PSTR("Unknown port\r\n")); |
330 return; | 319 return; |
331 } | 320 } |
332 printf_P(PSTR("DDR%c => 0x%02x\r\n"), toupper(port), val); | 321 printf_P(PSTR("DDR%c => 0x%02x\r\n"), toupper(argv[1][0]), val); |
333 } else { | 322 } else { |
334 switch (port) { | 323 val = strtol(argv[2], &eptr, 0); |
324 if (eptr == argv[2]) { | |
325 printf_P(PSTR("Unable to parse val\r\n")); | |
326 return; | |
327 } | |
328 | |
329 switch (argv[1][0]) { | |
335 case 'a': | 330 case 'a': |
336 DDRA = val & 0xff; | 331 DDRA = val & 0xff; |
337 break; | 332 break; |
338 | 333 |
339 case 'b': | 334 case 'b': |
340 DDRB = val & 0xff; | 335 DDRB = val & 0xff; |
341 break; | 336 break; |
342 | 337 |
343 case 'c': | 338 case 'c': |
344 DDRC = val & 0xff; | 339 DDRC = val & 0xff; |
345 break; | 340 break; |
346 | 341 |
347 case 'd': | 342 case 'd': |
348 DDRD = val & 0xff; | 343 DDRD = val & 0xff; |
349 break; | 344 break; |
350 | 345 |
351 default: | 346 default: |
352 printf_P(PSTR("Unknown port\r\n")); | 347 printf_P(PSTR("Unknown port\r\n")); |
353 return; | 348 return; |
354 } | 349 } |
355 printf_P(PSTR("DDR%c <= 0x%02x\r\n"), toupper(port), val); | 350 printf_P(PSTR("DDR%c <= 0x%02x\r\n"), toupper(argv[1][0]), val); |
356 } | 351 } |
357 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("zz"), 2)) { | 352 } else if (!strcasecmp_P(argv[0], PSTR("zz"))) { |
358 cli(); | 353 cli(); |
359 wdt_enable(WDTO_15MS); | 354 wdt_enable(WDTO_15MS); |
360 for (;;) | 355 for (;;) |
361 ; | 356 ; |
362 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("sr"), 2)) { | 357 } else if (!strcasecmp_P(argv[0], PSTR("sr"))) { |
363 uint8_t ROM[8]; | 358 uint8_t ROM[8]; |
364 int8_t i; | 359 int8_t i; |
365 | |
366 memset(ROM, 0, 8); | |
367 | 360 |
368 i = OWFirst(ROM, 1, 0); | 361 i = OWFirst(ROM, 1, 0); |
369 do { | 362 do { |
370 switch (i) { | 363 switch (i) { |
371 case OW_NOMODULES: | 364 case OW_NOMODULES: |
365 return; | |
366 | |
372 case OW_FOUND: | 367 case OW_FOUND: |
373 break; | 368 for (i = 0; i < 8; i++) |
374 | 369 printf_P(PSTR("%02x%S"), ROM[i], i == 7 ? PSTR("\r\n") : PSTR(":")); |
370 break; | |
371 | |
375 case OW_BADWIRE: | 372 case OW_BADWIRE: |
376 case OW_NOPRESENCE: | 373 case OW_NOPRESENCE: |
377 case OW_BADCRC: | 374 case OW_BADCRC: |
378 default: | 375 default: |
379 printf_P(PSTR("Err %d\r\n"), i); | 376 printf_P(PSTR("Err %d\r\n"), i); |
380 break; | 377 return; |
381 } | 378 } |
382 | |
383 if (i != OW_FOUND) | |
384 break; | |
385 | |
386 for (i = 0; i < 8; i++) | |
387 printf_P(PSTR("%02x%S"), ROM[i], i == 7 ? PSTR("\r\n") : PSTR(":")); | |
388 | |
389 i = OWNext(ROM, 1, 0); | 379 i = OWNext(ROM, 1, 0); |
390 } while (1); | 380 } while (1); |
391 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("te"), 2)) { | 381 } else if (!strcasecmp_P(argv[0], PSTR("te"))) { |
392 uint8_t ROM[8]; | 382 uint8_t ROM[8]; |
393 int16_t t; | 383 int16_t t; |
394 | 384 |
395 if (sscanf_P((char *)cmd.buf, PSTR("te %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), | 385 if (sscanf_P(argv[1], PSTR("%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), |
396 &ROM[0], &ROM[1], &ROM[2], &ROM[3], | 386 &ROM[0], &ROM[1], &ROM[2], &ROM[3], |
397 &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) { | 387 &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) { |
398 printf_P(PSTR("Unable to parse ROM ID\r\n")); | 388 printf_P(PSTR("Unable to parse ROM ID\r\n")); |
399 return; | 389 return; |
400 } | 390 } |
415 | 405 |
416 default: | 406 default: |
417 printf_P(PSTR("%d.%02d\r\n"), GETWHOLE(t), GETFRAC(t)); | 407 printf_P(PSTR("%d.%02d\r\n"), GETWHOLE(t), GETFRAC(t)); |
418 break; | 408 break; |
419 } | 409 } |
420 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("re"), 2)) { | 410 } else if (!strcasecmp_P(argv[0], PSTR("re"))) { |
421 printf_P(PSTR("Reset = %d\r\n"), OWTouchReset()); | 411 printf_P(PSTR("Reset = %d\r\n"), OWTouchReset()); |
422 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rb"), 2)) { | 412 } else if (!strcasecmp_P(argv[0], PSTR("rb"))) { |
423 printf_P(PSTR("Read %d\r\n"), OWReadBit()); | 413 printf_P(PSTR("Read %d\r\n"), OWReadBit()); |
424 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rc"), 2)) { | 414 } else if (!strcasecmp_P(argv[0], PSTR("rc"))) { |
425 printf_P(PSTR("Read 0x%02x\r\n"), OWReadByte()); | 415 printf_P(PSTR("Read 0x%02x\r\n"), OWReadByte()); |
426 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wb"), 2)) { | 416 } else if (!strcasecmp_P(argv[0], PSTR("wb"))) { |
427 uint8_t d; | 417 uint8_t d; |
428 | 418 |
429 if (sscanf_P((char *)cmd.buf, PSTR("wb %hhu"), &d) != 1) { | 419 if (sscanf_P((char *)cmd.buf, PSTR("wb %hhu"), &d) != 1) { |
430 printf_P(PSTR("Can't parse bit\r\n")); | 420 printf_P(PSTR("Can't parse bit\r\n")); |
431 return; | 421 return; |
432 } | 422 } |
433 OWWriteBit(d); | 423 OWWriteBit(d); |
434 printf_P(PSTR("Wrote %d\r\n"), d); | 424 printf_P(PSTR("Wrote %d\r\n"), d); |
435 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wc"), 2)) { | 425 } else if (!strcasecmp_P(argv[0], PSTR("wc"))) { |
436 uint8_t d; | 426 uint8_t d; |
437 | 427 char *eptr; |
438 if (sscanf_P((char *)cmd.buf, PSTR("wc %hhx"), &d) != 1) { | 428 |
439 printf_P(PSTR("Can't parse byte\r\n")); | 429 d = strtol(argv[1], &eptr, 16); |
430 if (eptr == argv[1]) { | |
431 printf_P(PSTR("Unable to parse byte\r\n")); | |
440 return; | 432 return; |
441 } | 433 } |
442 | 434 |
443 OWWriteByte(d); | 435 OWWriteByte(d); |
444 printf_P(PSTR("Wrote 0x%02x\r\n"), d); | 436 printf_P(PSTR("Wrote 0x%02x\r\n"), d); |
445 } else { | 437 } else { |
446 printf_P(PSTR("Unknown command, help for a list\r\n")); | 438 printf_P(PSTR("Unknown command, help for a list\r\n")); |
447 } | 439 } |
448 } | 440 } |
449 |