manueller import aus nem CVS checkout (ist eh nur zum testen)
[ds1820tousb.git] / main.c
CommitLineData
93ac315e
MPM
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
17uint8_t doprobescan = 1;
18uint8_t curprobe;
19uint8_t usbreadpos;
20uint32_t readpendingts;
21uint8_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 */
26void get_mcusr(void) __attribute__((naked)) __attribute__((section(".init3")));
27void 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. */
41usbMsgLen_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. */
98uchar 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
128int 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.063888 seconds and 4 git commands to generate.