Mercurial > ~darius > hgwebdir.cgi > tempctrl
comparison main.c @ 72:13f8e6eb5c01
Create a new repo for temperature control to make hacking on other things easier.
Rename main file, remove USB stuff & fix makefiles, etc..
author | darius@Inchoate |
---|---|
date | Wed, 21 Jan 2009 16:37:32 +1030 |
parents | testavr.c@1ef17cd8af7a |
children | 56165caf744b |
comparison
equal
deleted
inserted
replaced
71:553c061fda7c | 72:13f8e6eb5c01 |
---|---|
1 /* | |
2 * Test various AVR bits and pieces | |
3 * | |
4 * Copyright (c) 2008 | |
5 * Daniel O'Connor <darius@dons.net.au>. All rights reserved. | |
6 * | |
7 * Redistribution and use in source and binary forms, with or without | |
8 * modification, are permitted provided that the following conditions | |
9 * are met: | |
10 * 1. Redistributions of source code must retain the above copyright | |
11 * notice, this list of conditions and the following disclaimer. | |
12 * 2. Redistributions in binary form must reproduce the above copyright | |
13 * notice, this list of conditions and the following disclaimer in the | |
14 * documentation and/or other materials provided with the distribution. | |
15 * | |
16 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
19 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE | |
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 * SUCH DAMAGE. | |
27 */ | |
28 | |
29 #include <avr/io.h> | |
30 #include <avr/interrupt.h> | |
31 #include <avr/pgmspace.h> | |
32 #include <stdio.h> | |
33 #include <string.h> | |
34 #include <ctype.h> | |
35 #include <stdlib.h> | |
36 #include <util/delay.h> | |
37 #include <avr/wdt.h> | |
38 | |
39 #include "cons.h" | |
40 #include "1wire.h" | |
41 #ifdef WITHUSB | |
42 #include "usb.h" | |
43 #endif | |
44 #include "tempctrl.h" | |
45 #include "ds1307.h" | |
46 | |
47 /* | |
48 * Mirror of the MCUCSR register, taken early during startup. | |
49 */ | |
50 uint8_t mcucsr __attribute__((section(".noinit"))); | |
51 | |
52 void process_cmd(void); | |
53 | |
54 /* | |
55 * Read out and reset MCUCSR early during startup. | |
56 */ | |
57 void handle_mcucsr(void) | |
58 __attribute__((section(".init3"))) | |
59 __attribute__((naked)); | |
60 void handle_mcucsr(void) { | |
61 wdt_disable(); | |
62 mcucsr = MCUCSR; | |
63 MCUCSR = 0; | |
64 } | |
65 | |
66 int | |
67 main(void) { | |
68 /* Disable interrupts while we frob stuff */ | |
69 cli(); | |
70 | |
71 #if 0 | |
72 /* Disable JTAG (yes twice) */ | |
73 MCUCSR |= _BV(JTD); | |
74 MCUCSR |= _BV(JTD); | |
75 #endif | |
76 | |
77 #ifdef WITHUSB | |
78 /* USB data bus (7:0) */ | |
79 DDRA = 0x00; | |
80 PORTA = 0x00; | |
81 | |
82 /* USB control (4:0) */ | |
83 DDRB = 0x0d; | |
84 PORTB = 0x00; | |
85 #else | |
86 DDRA = 0xff; | |
87 PORTA = 0x00; | |
88 | |
89 DDRB = 0x00; | |
90 PORTB = 0x00; | |
91 | |
92 #endif | |
93 /* GPIO (0:7) */ | |
94 DDRC = 0xff; | |
95 PORTC = 0x00; | |
96 | |
97 /* USART (0:1), IDBus (2:5), 485 (6:6), GPIO (7:7) */ | |
98 DDRD = 0xf7; | |
99 PORTD = 0xf7; | |
100 | |
101 #ifndef WITHUSB | |
102 /* Beep | |
103 * | |
104 * Fpwm = Fclk / (N * 510) | |
105 * = 16e6 / (8 * 510) | |
106 * = 3921Hz | |
107 * | |
108 * Behind ifndef because PB3 is A0 on PDI chip | |
109 * | |
110 * Phase correct PWM, non-inverted output, divide by 8 */ | |
111 TCCR0 = _BV(WGM00) | _BV(WGM11) | _BV(COM00) | _BV(COM01) | _BV(CS01); | |
112 OCR0 = 128; | |
113 #endif | |
114 | |
115 /* Set up the one wire stuff */ | |
116 OWInit(); | |
117 | |
118 /* Setup IIC */ | |
119 ds1307_init(); | |
120 | |
121 /* Init UART */ | |
122 cons_init(); | |
123 | |
124 /* Init temperature control stuff */ | |
125 tempctrl_init(); | |
126 | |
127 printf_P(PSTR("\r\n\r\n===============\r\n" | |
128 "Inited!\r\n\r\n")); | |
129 | |
130 if ((mcucsr & _BV(PORF)) == _BV(PORF)) | |
131 printf_P(PSTR("Power on reset\r\n")); | |
132 | |
133 if ((mcucsr & _BV(EXTRF)) == _BV(EXTRF)) | |
134 printf_P(PSTR("External reset\r\n")); | |
135 | |
136 if ((mcucsr & _BV(BORF)) == _BV(BORF)) | |
137 printf_P(PSTR("Brown-out reset\r\n")); | |
138 | |
139 if ((mcucsr & _BV(WDRF)) == _BV(WDRF)) | |
140 printf_P(PSTR("Watchdog reset\r\n")); | |
141 | |
142 if ((mcucsr & _BV(JTRF)) == _BV(JTRF)) | |
143 printf_P(PSTR("JTAG reset\r\n")); | |
144 | |
145 /* Ready to go! */ | |
146 sei(); | |
147 | |
148 /* | |
149 * Enable the watchdog with the largest prescaler. Will cause a | |
150 * watchdog reset after approximately 2 s @ Vcc = 5 V | |
151 * | |
152 * Gets reset in the loop below and in the tempctrl.c timer IRQ | |
153 */ | |
154 wdt_enable(WDTO_2S); | |
155 | |
156 #ifdef WITHUSB | |
157 printf_P(PSTR("Calling usb_init\r\n")); | |
158 usb_init(); | |
159 printf_P(PSTR("done\r\n")); | |
160 _delay_us(1000); | |
161 #endif | |
162 printf_P(PSTR("> ")); | |
163 cmd.state = 0; | |
164 | |
165 /* Wait for user input or an "interrupt" */ | |
166 while (1) { | |
167 wdt_reset(); | |
168 | |
169 tempctrl_update(); | |
170 | |
171 if (cmd.state == 255) { | |
172 process_cmd(); | |
173 printf_P(PSTR("> ")); | |
174 /* Allow new characters to be processed */ | |
175 cmd.state = 0; | |
176 } | |
177 | |
178 #ifdef WITHUSB | |
179 if (!(PDICTL & _BV(PDIINT))) | |
180 usb_intr(); | |
181 #endif | |
182 } | |
183 } | |
184 | |
185 void | |
186 process_cmd(void) { | |
187 uint8_t ROM[8], crc, buf[9], temp; | |
188 int8_t i, arg; | |
189 int16_t t; | |
190 | |
191 /* User just pressed enter */ | |
192 if (cmd.len == 0) | |
193 return; | |
194 | |
195 if (!strcasecmp_P((char *)cmd.buf, PSTR("?")) || | |
196 !strcasecmp_P((char *)cmd.buf, PSTR("help"))) { | |
197 printf_P(PSTR("rs Reset and check for presence\r\n" | |
198 "sr Search the bus for ROMs\r\n" | |
199 "re Read a bit\r\n" | |
200 "rb Read a byte\r\n" | |
201 "wr bit Write a bit\r\n" | |
202 "wb byte Write a byte (hex)\r\n" | |
203 "wc cmd [ROMID] Write command\r\n" | |
204 "te ROMID Read the temperature from a DS1820\r\n" | |
205 "in port Read from a port\r\n" | |
206 "ou port val Write to a port (val in hex)\r\n" | |
207 "dd port [val] Read/write DDR for a port (val in hex)\r\n" | |
208 "rt ROMID Read DS2502 status page\r\n" | |
209 "we ROMID adr val Write data into a DS2502 PROM (adr & val in hex)\r\n" | |
210 "rr ROMID Read DS2502 PROM\r\n" | |
211 "zz Reset MCU\r\n" | |
212 "gc Get time of day\r\n" | |
213 "sc time Set time of day (time is YYYY/MM/DD HH:MM:SS)\r\n" | |
214 #ifdef WITHUSB | |
215 "us Generate USB data\r\n" | |
216 #endif | |
217 "tc ... Temperature control related (tc help for more)\r\n")); | |
218 | |
219 return; | |
220 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("zz"), 2)) { | |
221 cli(); | |
222 wdt_enable(WDTO_15MS); | |
223 for (;;) | |
224 ; | |
225 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rs"), 2)) { | |
226 printf_P(PSTR("Resetting... ")); | |
227 | |
228 if (OWTouchReset() == 1) | |
229 printf_P(PSTR("No presence pulse found\r\n")); | |
230 else | |
231 printf_P(PSTR("Presence pulse found\r\n")); | |
232 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("re"), 2)) { | |
233 if (OWReadBit()) | |
234 printf_P(PSTR("Read a 1\r\n")); | |
235 else | |
236 printf_P(PSTR("Read a 0\r\n")); | |
237 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rb"), 2)) { | |
238 printf_P(PSTR("Read a 0x%02x\r\n"), OWReadByte()); | |
239 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wr"), 2)) { | |
240 arg = strtol((char *)cmd.buf + 3, (char **)NULL, 10); | |
241 OWWriteBit(arg); | |
242 printf_P(PSTR("Wrote a %c\r\n"), arg ? '1' : '0'); | |
243 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wb"), 2)) { | |
244 arg = (int)strtol((char *)cmd.buf + 3, (char **)NULL, 16); | |
245 OWWriteByte(arg); | |
246 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rt"), 2)) { | |
247 if (sscanf_P((char *)cmd.buf, PSTR("rt %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), | |
248 &ROM[0], &ROM[1], &ROM[2], &ROM[3], | |
249 &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) { | |
250 printf_P(PSTR("Unable to parse ROM ID\r\n")); | |
251 return; | |
252 } | |
253 | |
254 if (ROM[0] != OW_FAMILY_ROM) { | |
255 printf_P(PSTR("ROM specified isn't a DS2502\r\n")); | |
256 return; | |
257 } | |
258 | |
259 if (OWTouchReset() != 0) { | |
260 printf_P(PSTR("No presence\r\n")); | |
261 return; | |
262 } | |
263 | |
264 crc = 0; | |
265 | |
266 OWCRC(OW_READ_STATUS, &crc); | |
267 OWSendCmd(ROM, OW_READ_STATUS); | |
268 | |
269 OWWriteByte(0x00); | |
270 OWCRC(0x00, &crc); | |
271 | |
272 OWWriteByte(0x00); | |
273 OWCRC(0x00, &crc); | |
274 | |
275 if (crc != OWReadByte()) { | |
276 printf_P(PSTR("CRC mismatch on command & address\r\n")); | |
277 return; | |
278 } | |
279 | |
280 crc = 0; | |
281 for (i = 0; i < 8; i++) { | |
282 temp = OWReadByte(); | |
283 printf_P(PSTR("%02x "), temp); | |
284 OWCRC(temp, &crc); | |
285 } | |
286 printf_P(PSTR("\r\n")); | |
287 if (crc != OWReadByte()) { | |
288 printf_P(PSTR("CRC mismatch on data\r\n")); | |
289 return; | |
290 } | |
291 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("we"), 2)) { | |
292 uint8_t adr, data; | |
293 | |
294 if (sscanf_P((char *)cmd.buf, PSTR("we %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhx %hhx"), | |
295 &ROM[0], &ROM[1], &ROM[2], &ROM[3], | |
296 &ROM[4], &ROM[5], &ROM[6], &ROM[7], | |
297 &adr, &data) != 10) { | |
298 printf_P(PSTR("Unable to parse ROM ID\r\n")); | |
299 return; | |
300 } | |
301 | |
302 if (ROM[0] != OW_FAMILY_ROM) { | |
303 printf_P(PSTR("ID specified isn't a ROM\r\n")); | |
304 return; | |
305 } | |
306 | |
307 if (OWTouchReset() != 0) { | |
308 printf_P(PSTR("No presence\r\n")); | |
309 return; | |
310 } | |
311 | |
312 printf_P(PSTR("OWProgROM returned %S\r\n"), OWProgROM_Status[OWProgROM(ROM, buf[0], 2, &buf[1], 0, 0)]); | |
313 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rr"), 2)) { | |
314 if (sscanf_P((char *)cmd.buf, PSTR("rr %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), | |
315 &ROM[0], &ROM[1], &ROM[2], &ROM[3], | |
316 &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) { | |
317 printf_P(PSTR("Unable to parse ROM ID\r\n")); | |
318 return; | |
319 } | |
320 | |
321 if (ROM[0] != OW_FAMILY_ROM) { | |
322 printf_P(PSTR("ROM specified isn't a ROM\r\n")); | |
323 return; | |
324 } | |
325 | |
326 crc = 0; | |
327 OWSendCmd(ROM, OW_READ_MEMORY); | |
328 OWCRC(OW_READ_MEMORY, &crc); | |
329 | |
330 OWWriteByte(0x00); | |
331 OWCRC(0x00, &crc); | |
332 | |
333 OWWriteByte(0x00); | |
334 OWCRC(0x00, &crc); | |
335 | |
336 if (crc != OWReadByte()) { | |
337 printf_P(PSTR("CRC mismatch on command & address\r\n")); | |
338 return; | |
339 } | |
340 | |
341 crc = 0; | |
342 for (buf[0] = 0; buf[0] < 128; buf[0]++) { | |
343 buf[1] = OWReadByte(); | |
344 if (buf[0] > 0) { | |
345 if (buf[0] % 16 != 0) | |
346 printf_P(PSTR(" ")); | |
347 else | |
348 printf_P(PSTR("\r\n")); | |
349 } | |
350 | |
351 printf_P(PSTR("%02x"), buf[1]); | |
352 OWCRC(buf[1], &crc); | |
353 } | |
354 printf_P(PSTR("\r\n")); | |
355 if (crc != OWReadByte()) { | |
356 printf_P(PSTR("CRC mismatch on data\r\n")); | |
357 return; | |
358 } | |
359 | |
360 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wc"), 2)) { | |
361 uint8_t c; | |
362 | |
363 i = sscanf_P((char *)cmd.buf, PSTR("wc %hhx %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), | |
364 &ROM[0], &ROM[1], &ROM[2], &ROM[3], | |
365 &ROM[4], &ROM[5], &ROM[6], &ROM[7], | |
366 &c); | |
367 | |
368 if (i != 1 && i != 9) { | |
369 printf_P(PSTR("Incorrect usage\r\n")); | |
370 return; | |
371 } | |
372 | |
373 if (i == 1) { | |
374 OWSendCmd(i == 1 ? NULL : ROM, c); | |
375 return; | |
376 } | |
377 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("te"), 2)) { | |
378 if (sscanf_P((char *)cmd.buf, PSTR("te %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), | |
379 &ROM[0], &ROM[1], &ROM[2], &ROM[3], | |
380 &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) { | |
381 printf_P(PSTR("Unable to parse ROM ID\r\n")); | |
382 return; | |
383 } | |
384 | |
385 t = OWGetTemp(ROM); | |
386 switch (t) { | |
387 case OW_TEMP_WRONG_FAM: | |
388 printf_P(PSTR("ROM specified isn't a temperature sensor\r\n")); | |
389 break; | |
390 | |
391 case OW_TEMP_CRC_ERR: | |
392 printf_P(PSTR("CRC mismatch\r\n")); | |
393 break; | |
394 | |
395 case OW_TEMP_NO_ROM: | |
396 printf_P(PSTR("No ROM found\r\n")); | |
397 break; | |
398 | |
399 default: | |
400 printf_P(PSTR("%d.%02d\r\n"), GETWHOLE(t), GETFRAC(t)); | |
401 break; | |
402 } | |
403 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("sr"), 2)) { | |
404 memset(ROM, 0, 8); | |
405 | |
406 i = OWFirst(ROM, 1, 0); | |
407 do { | |
408 switch (i) { | |
409 case OW_BADWIRE: | |
410 printf_P(PSTR("Presence pulse, but no module found, bad module/cabling?\r\n")); | |
411 break; | |
412 | |
413 case OW_NOPRESENCE: | |
414 printf_P(PSTR("No presence pulse found\r\n")); | |
415 break; | |
416 | |
417 case OW_BADCRC: | |
418 printf_P(PSTR("Bad CRC\r\n")); | |
419 break; | |
420 | |
421 case OW_NOMODULES: | |
422 case OW_FOUND: | |
423 break; | |
424 | |
425 default: | |
426 printf_P(PSTR("Unknown error from 1 wire library\r\n")); | |
427 break; | |
428 } | |
429 | |
430 if (i != OW_FOUND) | |
431 break; | |
432 | |
433 for (i = 0; i < 8; i++) | |
434 printf_P(PSTR("%02x%S"), ROM[i], i == 7 ? PSTR("\r\n") : PSTR(":")); | |
435 | |
436 i = OWNext(ROM, 1, 0); | |
437 } while (1); | |
438 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("in"), 2)) { | |
439 uint8_t inp; | |
440 | |
441 switch (tolower(cmd.buf[3])) { | |
442 case 'a': | |
443 inp = PINA; | |
444 break; | |
445 | |
446 case 'b': | |
447 inp = PINB; | |
448 break; | |
449 | |
450 case 'c': | |
451 inp = PINC; | |
452 break; | |
453 | |
454 case 'd': | |
455 inp = PIND; | |
456 break; | |
457 | |
458 default: | |
459 printf_P(PSTR("Unknown port\r\n")); | |
460 return; | |
461 } | |
462 printf_P(PSTR("0x%02x\r\n"), inp); | |
463 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("ou"), 2)) { | |
464 char port; | |
465 int val; | |
466 | |
467 if (sscanf_P((char *)cmd.buf, PSTR("ou %c %x"), &port, &val) != 2) { | |
468 printf_P(PSTR("Unable to parse ou arguments\r\n")); | |
469 return; | |
470 } | |
471 | |
472 switch (port) { | |
473 case 'a': | |
474 PORTA = val & 0xff; | |
475 break; | |
476 | |
477 case 'b': | |
478 PORTB = val & 0xff; | |
479 break; | |
480 | |
481 case 'c': | |
482 PORTC = val & 0xff; | |
483 break; | |
484 | |
485 case 'd': | |
486 PORTD = val & 0xff; | |
487 break; | |
488 | |
489 default: | |
490 printf_P(PSTR("Unknown port\r\n")); | |
491 return; | |
492 } | |
493 printf_P(PSTR("PORT%c <= 0x%02x\r\n"), toupper(port), val); | |
494 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("dd"), 2)) { | |
495 char port; | |
496 uint8_t val; | |
497 int num; | |
498 | |
499 num = sscanf_P((char *)cmd.buf, PSTR("dd %c %x"), &port, &val); | |
500 | |
501 if (num != 2 && num != 3) { | |
502 printf_P(PSTR("Unable to parse dd arguments\r\n")); | |
503 return; | |
504 } | |
505 | |
506 if (num == 2) { | |
507 switch (port) { | |
508 case 'a': | |
509 val = DDRA; | |
510 break; | |
511 | |
512 case 'b': | |
513 val = DDRB; | |
514 break; | |
515 | |
516 case 'c': | |
517 val = DDRC; | |
518 break; | |
519 | |
520 case 'd': | |
521 val = DDRD; | |
522 break; | |
523 | |
524 default: | |
525 printf_P(PSTR("Unknown port\r\n")); | |
526 return; | |
527 } | |
528 printf_P(PSTR("DDR%c => 0x%02x\r\n"), toupper(port), val); | |
529 } else { | |
530 switch (port) { | |
531 case 'a': | |
532 DDRA = val & 0xff; | |
533 break; | |
534 | |
535 case 'b': | |
536 DDRB = val & 0xff; | |
537 break; | |
538 | |
539 case 'c': | |
540 DDRC = val & 0xff; | |
541 break; | |
542 | |
543 case 'd': | |
544 DDRD = val & 0xff; | |
545 break; | |
546 | |
547 default: | |
548 printf_P(PSTR("Unknown port\r\n")); | |
549 return; | |
550 } | |
551 printf_P(PSTR("DDR%c <= 0x%02x\r\n"), toupper(port), val); | |
552 } | |
553 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("tc"), 2)) { | |
554 tempctrl_cmd((char *)cmd.buf); | |
555 #ifdef WITHUSB | |
556 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("us"), 2)) { | |
557 usb_gendata(); | |
558 #endif | |
559 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("gc"), 2)) { | |
560 ds1307_printtime(PSTR(""), PSTR("\r\n")); | |
561 } else if (!strncasecmp_P((char *)cmd.buf, PSTR("sc"), 2)) { | |
562 if (cmd.len < 17) { | |
563 printf_P(PSTR("Command not long enough\r\n")); | |
564 } else { | |
565 if (ds1307_settod((char *)cmd.buf + 3) != 1) | |
566 printf_P(PSTR("Unable to set time of day\r\n")); | |
567 } | |
568 } else { | |
569 printf_P(PSTR("Unknown command, help for a list\r\n")); | |
570 } | |
571 } | |
572 |