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
8 #include <avr/interrupt.h>
10 #include <avr/power.h>
11 #include <avr/sleep.h>
12 #include <util/delay.h>
13 #include "usbdrv/usbdrv.h"
17 uint8_t doprobescan = 1;
20 uint32_t readpendingts;
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) {
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])
43 usbRequest_t *rq = (void *)data;
44 static uchar replyBuf[8];
46 if (rq->bRequest == 0){ /* ECHO */
48 replyBuf[0] = rq->wValue.bytes[0];
49 replyBuf[1] = rq->wValue.bytes[1];
52 if (rq->bRequest == 1) { /* GET_STATUS_SHORT */
53 uint32_t curtime = gettime();
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 */
65 if (rq->bRequest == 2) { /* RESCAN_BUS */
68 replyBuf[0] = 42; /* Scan already scheduled / in progress */
70 replyBuf[0] = 23; /* OK, scan scheduled */
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 */
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. */
85 wdt_reset(); /* Make sure we get the full 2 seconds */
88 /* Unknown request. Ignore. */
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) {
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 */
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];
121 data[i] = 0; /* Unused */
130 /* Some powersaving: Disable unused stuff */
133 power_timer1_disable();
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();
144 /* This function must be called before interrupts are enabled and the main
145 * loop is entered. */
148 /* Reset if we don't return to the main loop within 2 seconds */
151 /* Init the ds1820 code and bus */
157 /* Prepare sleep mode */
158 set_sleep_mode(SLEEP_MODE_IDLE);
161 /* All set up, enable interrupts and go. */
164 while (1) { /* We should never exit, or should we? */
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
174 if ((readpending == 0) && (doprobescan)) {
179 if (readpending == 0) {
180 /* Select next probe to query */
181 if ((ds1820probes[curprobe].flags & DS1820FLAG_SLOTINUSE) == DS1820FLAG_SLOTINUSE) {
182 ds1820queryprobe(curprobe);
185 readpendingts = gettime();
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];
193 for (i = 0; i < 6; i++) {
194 whattosend[i] = ds1820probes[curprobe].serial[i];
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);
209 if (curprobe >= DS1820_MAXPROBES) { curprobe = 0; }
215 /* Go to sleep now */