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