manueller import aus nem CVS checkout (ist eh nur zum testen)
[ds1820tousb.git] / main.c
1 /* $Id: main.c,v 1.5 2010/06/09 23:13:28 simimeie Exp $
2  * USB interface for ds1820
3  * This is the main file that glues it all together.
4  * (C) Michael "Fox" Meier 2009
5  */
6
7 #include <avr/io.h>
8 #include <avr/interrupt.h>
9 #include <avr/wdt.h>
10 #include <avr/power.h>
11 #include <avr/sleep.h>
12 #include <util/delay.h>
13 #include "usbdrv/usbdrv.h"
14 #include "ds1820.h"
15 #include "time.h"
16
17 uint8_t doprobescan = 1;
18 uint8_t curprobe;
19 uint8_t usbreadpos;
20 uint32_t readpendingts;
21 uint8_t readpending;
22
23 /* This is needed to recover from a watchdog reset, as the watchdog
24  * stays active after the reset. Without this we'll just do an
25  * endless reset loop */
26 void get_mcusr(void) __attribute__((naked)) __attribute__((section(".init3")));
27 void get_mcusr(void) {
28   MCUSR = 0;
29   wdt_disable();
30 }
31
32 /* This function is called when the driver receives a SETUP transaction from
33  * the host which is not answered by the driver itself (in practice: class and
34  * vendor requests). All control transfers start with a SETUP transaction where
35  * the host communicates the parameters of the following (optional) data
36  * transfer. The SETUP data is available in the 'data' parameter which can
37  * (and should) be casted to 'usbRequest_t *' for a more user-friendly access
38  * to parameters. [...]
39  * in short: Set usbMsgPtr to your answer, and return number of bytes.
40  * return USB_NO_MSG to supply the long answer packets with the usbFunctionRead. */
41 usbMsgLen_t usbFunctionSetup(uchar data[8])
42 {
43   usbRequest_t    *rq = (void *)data;
44   static uchar    replyBuf[8];
45
46   if (rq->bRequest == 0){  /* ECHO */
47     usbMsgPtr = replyBuf;
48     replyBuf[0] = rq->wValue.bytes[0];
49     replyBuf[1] = rq->wValue.bytes[1];
50     return 2;
51   }
52   if (rq->bRequest == 1) { /* GET_STATUS_SHORT */
53     uint32_t curtime = gettime();
54     usbMsgPtr = replyBuf;
55     replyBuf[0] = 0; /* Version high */
56     replyBuf[1] = 1; /* Version low */
57     replyBuf[2] = ((uint8_t *)&curtime)[0];  /* Time */
58     replyBuf[3] = ((uint8_t *)&curtime)[1];
59     replyBuf[4] = ((uint8_t *)&curtime)[2];
60     replyBuf[5] = ((uint8_t *)&curtime)[3];
61     replyBuf[6] = DS1820_MAXPROBES;  /* max. number of probes */
62     replyBuf[7] = 0; /* UNUSED */
63     return 8;
64   }
65   if (rq->bRequest == 2) { /* RESCAN_BUS */
66     usbMsgPtr = replyBuf;
67     if (doprobescan) {
68       replyBuf[0] = 42; /* Scan already scheduled / in progress */
69     } else {
70       replyBuf[0] = 23; /* OK, scan scheduled */
71       doprobescan = 1;
72     }
73     return 1;
74   }
75   if (rq->bRequest == 3) { /* GET_STATUS_LONG */
76     /* the answer to this query will list all probes on the bus
77      * and thus can be very lengthy. We will handle that with usbFunctionRead */
78     usbreadpos = 0;
79     return USB_NO_MSG;
80   }
81   if (rq->bRequest == 4) { /* RESET_HARD */
82     /* Reset, both the probe bus and ourselves. We reset ourselves through
83      * the watchdog timer and just pull the 1wire bus low. */
84     ds1820killbus();
85     wdt_reset(); /* Make sure we get the full 2 seconds */
86     for (;;) { }
87   }
88   /* Unknown request. Ignore. */
89   return 0;
90 }
91
92 /* This function is called by the driver to ask the application for a control
93  * transfer's payload data (control-in). It is called in chunks of up to 8
94  * bytes each. You should copy the data to the location given by 'data' and
95  * return the actual number of bytes copied. If you return less than requested,
96  * the control-in transfer is terminated. If you return 0xff, the driver aborts
97  * the transfer with a STALL token. */
98 uchar usbFunctionRead(uchar *data, uchar len) {
99   uint8_t i;
100   for (i = 0; i < len; i++) {
101     uint8_t j = usbreadpos + i;
102     uint8_t probenum = j / 16;
103     uint8_t probeoff = j % 16;
104     if (probenum >= DS1820_MAXPROBES) {
105       return (i - usbreadpos); /* the end - no more data */
106     }
107     if        (probeoff < 6) {
108       data[i] = ds1820probes[probenum].serial[probeoff];
109     } else if (probeoff == 6) {
110       data[i] = ds1820probes[probenum].family;
111     } else if (probeoff == 7) {
112       data[i] = ds1820probes[probenum].flags;
113     } else if (probeoff == 8) {
114       data[i] = ds1820probes[probenum].lasttemp[0];
115     } else if (probeoff == 9) {
116       data[i] = ds1820probes[probenum].lasttemp[1];
117     } else if (probeoff < 14) {
118       uint8_t * tp = (uint8_t *)&ds1820probes[probenum].lastts;
119       data[i] = tp[probeoff - 10];
120     } else {
121       data[i] = 0; /* Unused */
122     }
123   }
124   usbreadpos += len;
125   return len;
126 }
127
128 int main(void)
129 {
130   /* Some powersaving: Disable unused stuff */
131   power_adc_disable();
132   power_usi_disable();
133   power_timer1_disable();
134   
135   /* From the avr usb doku wiki: Call usbDeviceDisconnect(), wait several
136    * 100 milliseconds and then call usbDeviceConnect(). This enforces
137    * (re-)enumeration of the device. In theory, you don't need this, but
138    * it prevents inconsistencies between host and device after hardware
139    * or watchdog resets. */
140   usbDeviceDisconnect();
141   _delay_ms(500.0);
142   usbDeviceConnect();
143   
144   /* This function must be called before interrupts are enabled and the main
145    * loop is entered. */
146   usbInit();
147   
148   /* Reset if we don't return to the main loop within 2 seconds */
149   wdt_enable(WDTO_2S);
150   
151   /* Init the ds1820 code and bus */
152   ds1820init();
153   
154   /* Init timer */
155   time_init();
156   
157   /* Prepare sleep mode */
158   set_sleep_mode(SLEEP_MODE_IDLE);
159   sleep_enable();
160   
161   /* All set up, enable interrupts and go. */
162   sei();
163   
164   while (1) { /* We should never exit, or should we? */
165     wdt_reset();
166     
167     /* This function must be called at regular intervals from the main loop.
168      * Maximum delay between calls is somewhat less than 50ms (USB timeout for
169      * accepting a Setup message). Otherwise the device will not be recognized.
170      * If other functions are called from the USB code, they will be called from
171      * usbPoll(). */
172     usbPoll();
173     
174     if ((readpending == 0) && (doprobescan)) {
175       ds1820scan();
176       doprobescan = 0;
177       curprobe = 0;
178     } else {
179       if (readpending == 0) {
180         /* Select next probe to query */
181         if ((ds1820probes[curprobe].flags & DS1820FLAG_SLOTINUSE) == DS1820FLAG_SLOTINUSE) {
182           ds1820queryprobe(curprobe);
183         }
184         readpending = 1;
185         readpendingts = gettime();
186       } else {
187         if ((gettime() - readpendingts) > 60) { /* >1 second passed, data should be ready */
188           if ((ds1820probes[curprobe].flags & DS1820FLAG_SLOTINUSE) == DS1820FLAG_SLOTINUSE) { /* Is that probe even there? */
189             if (ds1820updateprobe(curprobe)) { /* Successful, send updated data */
190               if (usbInterruptIsReady()) { /* Last message has been sent, so send new data */
191                 uint8_t whattosend[8];
192                 uint8_t i;
193                 for (i = 0; i < 6; i++) {
194                   whattosend[i] = ds1820probes[curprobe].serial[i];
195                 }
196                 whattosend[6] = ds1820probes[curprobe].lasttemp[0];
197                 whattosend[7] = ds1820probes[curprobe].lasttemp[1];
198                 /* This function sets the message which will be sent during the next interrupt
199                  * IN transfer. The message is copied to an internal buffer and must not exceed
200                  * a length of 8 bytes. The message may be 0 bytes long just to indicate the
201                  * interrupt status to the host.
202                  * If you need to transfer more bytes, use a control read after the interrupt.  */
203                 /* void usbSetInterrupt(uchar *data, uchar len);*/
204                 usbSetInterrupt(whattosend, 8);
205               }
206             }
207           }
208           curprobe++;
209           if (curprobe >= DS1820_MAXPROBES) { curprobe = 0; }
210           readpending = 0;
211         }
212       }
213     }
214     
215     /* Go to sleep now */
216     sleep_cpu();
217   }
218   
219   /* Never reached */
220   return 0;
221 }
This page took 0.094319 seconds and 3 git commands to generate.