Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 1011 lines (910 sloc) 26.673 kb
fa906da @jcw files imported
authored
1 // Ports library definitions
9c0edcc @jcw get rid of svn $Id keyword & update email address
authored
2 // 2009-02-13 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
fa906da @jcw files imported
authored
3
4 #include "Ports.h"
5 #include <avr/sleep.h>
6 #include <util/atomic.h>
7
8 // flag bits sent to the receiver
9 #define MODE_CHANGE 0x80 // a pin mode was changed
10 #define DIG_CHANGE 0x40 // a digital output was changed
11 #define PWM_CHANGE 0x30 // an analog (pwm) value was changed on port 2..3
12 #define ANA_MASK 0x0F // an analog read was requested on port 1..4
13
14 uint16_t Port::shiftRead(uint8_t bitOrder, uint8_t count) const {
15 uint16_t value = 0, mask = bit(LSBFIRST ? 0 : count - 1);
16 for (uint8_t i = 0; i < count; ++i) {
17 digiWrite2(1);
18 delayMicroseconds(5);
19 if (digiRead())
20 value |= mask;
21 if (bitOrder == LSBFIRST)
22 mask <<= 1;
23 else
24 mask >>= 1;
25 digiWrite2(0);
26 delayMicroseconds(5);
27 }
28 return value;
29 }
30
31 void Port::shiftWrite(uint8_t bitOrder, uint16_t value, uint8_t count) const {
32 uint16_t mask = bit(LSBFIRST ? 0 : count - 1);
33 for (uint8_t i = 0; i < count; ++i) {
34 digiWrite((value & mask) != 0);
35 if (bitOrder == LSBFIRST)
36 mask <<= 1;
37 else
38 mask >>= 1;
39 digiWrite2(1);
40 digiWrite2(0);
41 }
42 }
43
44 RemoteNode::RemoteNode (char id, uint8_t band, uint8_t group)
45 : nid (id & 0x1F)
46 {
47 memset(&data, 0, sizeof data);
48 RemoteHandler::setup(nid, band, group);
49 }
50
51 void RemoteNode::poll(uint16_t msecs) {
52 uint8_t pending = millis() >= lastPoll + msecs;
53 if (RemoteHandler::poll(*this, pending))
54 lastPoll = millis();
55 }
56
57 void RemotePort::mode(uint8_t value) const {
58 node.data.flags |= MODE_CHANGE;
59 bitWrite(node.data.modes, pinBit(), value);
60 }
61
62 uint8_t RemotePort::digiRead() const {
63 return bitRead(node.data.digiIO, pinBit());
64 }
65
66 void RemotePort::digiWrite(uint8_t value) const {
67 node.data.flags |= DIG_CHANGE;
68 bitWrite(node.data.digiIO, pinBit(), value);
69 }
70
71 void RemotePort::anaWrite(uint8_t val) const {
72 if (portNum == 2 || portNum == 3) {
73 bitSet(node.data.flags, portNum + 2);
74 node.data.anaOut[portNum - 2] = val;
75 } else
76 digiWrite2(val >= 128);
77 }
78
79 void RemotePort::mode2(uint8_t value) const {
80 node.data.flags |= MODE_CHANGE;
81 bitWrite(node.data.modes, pinBit2(), value);
82 }
83
84 uint16_t RemotePort::anaRead() const {
85 bitSet(node.data.flags, pinBit());
86 return node.data.anaIn[pinBit()];
87 }
88
89 uint8_t RemotePort::digiRead2() const {
90 return bitRead(node.data.digiIO, pinBit2());
91 }
92
93 void RemotePort::digiWrite2(uint8_t value) const {
94 node.data.flags |= DIG_CHANGE;
95 bitWrite(node.data.digiIO, pinBit2(), value);
96 }
97
98 PortI2C::PortI2C (uint8_t num, uint8_t rate)
99 : Port (num), uswait (rate)
100 {
101 sdaOut(1);
102 mode2(OUTPUT);
103 sclHi();
104 }
105
106 uint8_t PortI2C::start(uint8_t addr) const {
107 sclLo();
108 sclHi();
109 sdaOut(0);
110 return write(addr);
111 }
112
113 void PortI2C::stop() const {
114 sdaOut(0);
115 sclHi();
116 sdaOut(1);
117 }
118
119 uint8_t PortI2C::write(uint8_t data) const {
120 sclLo();
121 for (uint8_t mask = 0x80; mask != 0; mask >>= 1) {
122 sdaOut(data & mask);
123 sclHi();
124 sclLo();
125 }
126 sdaOut(1);
127 sclHi();
128 uint8_t ack = ! sdaIn();
129 sclLo();
130 return ack;
131 }
132
133 uint8_t PortI2C::read(uint8_t last) const {
134 uint8_t data = 0;
135 for (uint8_t mask = 0x80; mask != 0; mask >>= 1) {
136 sclHi();
137 if (sdaIn())
138 data |= mask;
139 sclLo();
140 }
141 sdaOut(last);
142 sclHi();
143 sclLo();
144 if (last)
145 stop();
146 sdaOut(1);
147 return data;
148 }
149
150 bool DeviceI2C::isPresent () const {
151 byte ok = send();
152 stop();
153 return ok;
154 }
155
156 byte MilliTimer::poll(word ms) {
157 byte ready = 0;
158 if (armed) {
159 word remain = next - millis();
160 // since remain is unsigned, it will overflow to large values when
161 // the timeout is reached, so this test works as long as poll() is
162 // called no later than 5535 millisecs after the timer has expired
163 if (remain <= 60000)
164 return 0;
165 // return a value between 1 and 255, being msecs+1 past expiration
166 // note: the actual return value is only reliable if poll() is
167 // called no later than 255 millisecs after the timer has expired
168 ready = -remain;
169 }
170 set(ms);
171 return ready;
172 }
173
174 word MilliTimer::remaining() const {
175 word remain = armed ? next - millis() : 0;
176 return remain <= 60000 ? remain : 0;
177 }
178
179 void MilliTimer::set(word ms) {
180 armed = ms != 0;
181 if (armed)
182 next = millis() + ms - 1;
183 }
184
185 void BlinkPlug::ledOn (byte mask) {
186 if (mask & 1) {
187 digiWrite(0);
188 mode(OUTPUT);
189 }
190 if (mask & 2) {
191 digiWrite2(0);
192 mode2(OUTPUT);
193 }
194 leds |= mask; //TODO could be read back from pins, i.s.o. saving here
195 }
196
197 void BlinkPlug::ledOff (byte mask) {
198 if (mask & 1) {
199 mode(INPUT);
200 digiWrite(1);
201 }
202 if (mask & 2) {
203 mode2(INPUT);
204 digiWrite2(1);
205 }
206 leds &= ~ mask; //TODO could be read back from pins, i.s.o. saving here
207 }
208
209 byte BlinkPlug::state () {
210 byte saved = leds;
211 ledOff(1+2);
212 byte result = !digiRead() | (!digiRead2() << 1);
213 ledOn(saved);
214 return result;
215 }
216
217 //TODO deprecated, use buttonCheck() !
218 byte BlinkPlug::pushed () {
219 if (debounce.idle() || debounce.poll()) {
220 byte newState = state();
221 if (newState != lastState) {
222 debounce.set(100); // don't check again for at least 100 ms
223 byte nowOn = (lastState ^ newState) & newState;
224 lastState = newState;
225 return nowOn;
226 }
227 }
228 return 0;
229 }
230
231 byte BlinkPlug::buttonCheck () {
232 // collect button changes in the checkFlags bits, with proper debouncing
233 if (debounce.idle() || debounce.poll()) {
234 byte newState = state();
235 if (newState != lastState) {
236 debounce.set(100); // don't check again for at least 100 ms
237 if ((lastState ^ newState) & 1)
238 bitSet(checkFlags, newState & 1 ? ON1 : OFF1);
239 if ((lastState ^ newState) & 2)
240 bitSet(checkFlags, newState & 2 ? ON2 : OFF2);
241 lastState = newState;
242 }
243 }
244 // note that simultaneous button events will be returned in successive calls
245 if (checkFlags)
246 for (byte i = ON1; i <= OFF2; ++i) {
247 if (bitRead(checkFlags, i)) {
248 bitClear(checkFlags, i);
249 return i;
250 }
251 }
252 // if there are no button events, return the overall current button state
253 return lastState == 3 ? ALL_ON : lastState ? SOME_ON : ALL_OFF;
254 }
255
256 void MemoryPlug::load (word page, void* buf, byte offset, int count) {
257 setAddress(0x50 + (page >> 8));
258 send();
259 write((byte) page);
260 write(offset);
261 receive();
262 byte* p = (byte*) buf;
263 while (--count >= 0)
264 *p++ = read(count == 0);
265 stop();
266 }
267
268 void MemoryPlug::save (word page, const void* buf, byte offset, int count) {
269 // don't do back-to-back saves, last one must have had time to finish!
270 while (millis() < nextSave)
271 ;
272
273 setAddress(0x50 + (page >> 8));
274 send();
275 write((byte) page);
276 write(offset);
277 const byte* p = (const byte*) buf;
278 while (--count >= 0)
279 write(*p++);
280 stop();
281
282 nextSave = millis() + 6;
283 // delay(5);
284 }
285
286 long MemoryStream::position (byte writing) const {
287 long v = (curr - start) * step;
288 if (pos > 0 && !writing)
289 --v; // get() advances differently than put()
290 return (v << 8) | pos;
291 }
292
293 byte MemoryStream::get () {
294 if (pos == 0) {
295 dev.load(curr, buffer);
296 curr += step;
297 }
298 return buffer[pos++];
299 }
300
301 void MemoryStream::put (byte data) {
302 buffer[pos++] = data;
303 if (pos == 0) {
304 dev.save(curr, buffer);
305 curr += step;
306 }
307 }
308
309 word MemoryStream::flush () {
310 if (pos != 0) {
311 memset(buffer + pos, 0xFF, 256 - pos);
312 dev.save(curr, buffer);
313 }
314 return curr;
315 }
316
317 void MemoryStream::reset () {
318 curr = start;
319 pos = 0;
320 }
321
322 // uart register definitions
323 #define RHR (0 << 3)
324 #define THR (0 << 3)
325 #define DLL (0 << 3)
326 #define DLH (1 << 3)
327 #define FCR (2 << 3)
328 #define LCR (3 << 3)
329 #define RXLVL (9 << 3)
330
331 void UartPlug::regSet (byte reg, byte value) {
332 dev.send();
333 dev.write(reg);
334 dev.write(value);
335 }
336
337 void UartPlug::regRead (byte reg) {
338 dev.send();
339 dev.write(reg);
340 dev.receive();
341 }
342
343 void UartPlug::begin (long baud) {
344 word divisor = 230400 / baud;
345 regSet(LCR, 0x80); // divisor latch enable
346 regSet(DLL, divisor); // low byte
347 regSet(DLH, divisor >> 8); // high byte
348 regSet(LCR, 0x03); // 8 bits, no parity
349 regSet(FCR, 0x07); // fifo enable (and flush)
350 dev.stop();
351 }
352
353 byte UartPlug::available () {
354 if (in != out)
355 return 1;
356 out = 0;
357 regRead(RXLVL);
358 in = dev.read(1);
359 if (in == 0)
360 return 0;
361 if (in > sizeof rxbuf)
362 in = sizeof rxbuf;
363 regRead(RHR);
364 for (byte i = 0; i < in; ++i)
365 rxbuf[i] = dev.read(i == in - 1);
366 return 1;
367 }
368
369 int UartPlug::read () {
370 return available() ? rxbuf[out++] : -1;
371 }
372
373 void UartPlug::flush () {
374 regSet(FCR, 0x07); // flush both RX and TX queues
375 dev.stop();
376 in = out;
377 }
378
379 void UartPlug::write (byte data) {
380 regSet(THR, data);
381 dev.stop();
382 }
383
384 void DimmerPlug::begin () {
385 setReg(MODE1, 0x00); // normal
386 setReg(MODE2, 0x14); // inverted, totem-pole
387 setReg(GRPPWM, 0xFF); // set group dim to max brightness
388 setMulti(LEDOUT0, 0xFF, 0xFF, 0xFF, 0xFF, -1); // all LEDs group-dimmable
389 }
390
391 byte DimmerPlug::getReg(byte reg) const {
392 send();
393 write(reg);
394 receive();
395 byte result = read(1);
396 stop();
397 return result;
398 }
399
400 void DimmerPlug::setReg(byte reg, byte value) const {
401 send();
402 write(reg);
403 write(value);
404 stop();
405 }
406
407 void DimmerPlug::setMulti(byte reg, ...) const {
408 va_list ap;
409 va_start(ap, reg);
410 send();
411 write(0xE0 | reg); // auto-increment
412 for (;;) {
413 int v = va_arg(ap, int);
414 if (v < 0) break;
415 write(v);
416 }
417 stop();
418 }
419
420 void LuxPlug::setGain(byte high) {
421 send();
422 write(0x81); // write to Timing regiser
423 write(high ? 0x12 : 0x02);
424 stop();
425 }
426
427 const word* LuxPlug::getData() {
428 send();
429 write(0xA0 | DATA0LOW);
430 receive();
431 data.b[0] = read(0);
432 data.b[1] = read(0);
433 data.b[2] = read(0);
434 data.b[3] = read(1);
435 stop();
436 return data.w;
437 }
438
439 #define LUX_SCALE 14 // scale by 2^14
440 #define RATIO_SCALE 9 // scale ratio by 2^9
441 #define CH_SCALE 10 // scale channel values by 2^10
442
443 word LuxPlug::calcLux(byte iGain, byte tInt) const
444 {
445 unsigned long chScale;
446 switch (tInt) {
447 case 0: chScale = 0x7517; break;
448 case 1: chScale = 0x0fe7; break;
449 default: chScale = (1 << CH_SCALE); break;
450 }
451 if (!iGain)
452 chScale <<= 4;
453 unsigned long channel0 = (data.w[0] * chScale) >> CH_SCALE;
454 unsigned long channel1 = (data.w[1] * chScale) >> CH_SCALE;
455
456 unsigned long ratio1 = 0;
457 if (channel0 != 0)
458 ratio1 = (channel1 << (RATIO_SCALE+1)) / channel0;
459 unsigned long ratio = (ratio1 + 1) >> 1;
460
461 word b, m;
462 if (ratio <= 0x0040) { b = 0x01F2; m = 0x01BE; }
463 else if (ratio <= 0x0080) { b = 0x0214; m = 0x02D1; }
464 else if (ratio <= 0x00C0) { b = 0x023F; m = 0x037B; }
465 else if (ratio <= 0x0100) { b = 0x0270; m = 0x03FE; }
466 else if (ratio <= 0x0138) { b = 0x016F; m = 0x01FC; }
467 else if (ratio <= 0x019A) { b = 0x00D2; m = 0x00FB; }
468 else if (ratio <= 0x029A) { b = 0x0018; m = 0x0012; }
469 else { b = 0x0000; m = 0x0000; }
470
471 unsigned long temp = channel0 * b - channel1 * m;
472 temp += 1 << (LUX_SCALE-1);
473 return temp >> LUX_SCALE;
474 }
475
476 const int* GravityPlug::getAxes() {
477 send();
478 write(0x02);
479 receive();
480 for (byte i = 0; i < 5; ++i)
481 data.b[i] = read(0);
482 data.b[5] = read(1);
483 stop();
484 data.w[0] = (data.b[0] >> 6) | (data.b[1] << 2);
485 data.w[1] = (data.b[2] >> 6) | (data.b[3] << 2);
486 data.w[2] = (data.b[4] >> 6) | (data.b[5] << 2);
487 for (byte i = 0; i < 3; ++i)
488 data.w[i] = (data.w[i] ^ 0x200) - 0x200; // sign extends bit 9
489 return data.w;
490 }
491
492 void InputPlug::select(uint8_t channel) {
493 digiWrite(0);
494 mode(OUTPUT);
495
496 delayMicroseconds(slow ? 400 : 50);
497 byte data = 0x10 | (channel & 0x0F);
498 byte mask = 1 << (portNum + 3); // digitalWrite is too slow
499
500 ATOMIC_BLOCK(ATOMIC_FORCEON) {
501 for (byte i = 0; i < 5; ++i) {
502 byte us = bitRead(data, 4 - i) ? 9 : 3;
503 if (slow)
504 us <<= 3;
505 #ifdef PORTD
506 PORTD |= mask;
507 delayMicroseconds(us);
508 PORTD &= ~ mask;
509 #else
510 //XXX TINY!
511 #endif
512 delayMicroseconds(slow ? 32 : 4);
513 }
514 }
515 }
516
517 byte HeadingBoard::eepromByte(byte reg) const {
518 eeprom.send();
519 eeprom.write(reg);
520 eeprom.receive();
521 byte result = eeprom.read(1);
522 eeprom.stop();
523 return result;
524 }
525
526 void HeadingBoard::getConstants() {
527 for (byte i = 0; i < 18; ++i)
528 ((byte*) &C1)[i < 14 ? i^1 : i] = eepromByte(16 + i);
529 // Serial.println(C1);
530 // Serial.println(C2);
531 // Serial.println(C3);
532 // Serial.println(C4);
533 // Serial.println(C5);
534 // Serial.println(C6);
535 // Serial.println(C7);
536 // Serial.println(A, DEC);
537 // Serial.println(B, DEC);
538 // Serial.println(C, DEC);
539 // Serial.println(D, DEC);
540 }
541
542 word HeadingBoard::adcValue(byte press) const {
543 aux.digiWrite(1);
544 adc.send();
545 adc.write(0xFF);
546 adc.write(0xE0 | (press << 4));
547 adc.stop();
548 delay(40);
549 adc.send();
550 adc.write(0xFD);
551 adc.receive();
552 byte msb = adc.read(0);
553 int result = (msb << 8) | adc.read(1);
554 adc.stop();
555 aux.digiWrite(0);
556 return result;
557 }
558
559 void HeadingBoard::begin() {
560 // prepare ADC
561 aux.mode(OUTPUT);
562 aux.digiWrite(0);
563
564 // generate 32768 Hz on IRQ pin (OC2B)
565 #ifdef TCCR2A
566 TCCR2A = bit(COM2B0) | bit(WGM21);
567 TCCR2B = bit(CS20);
568 OCR2A = 243;
569 #else
570 //XXX TINY!
571 #endif
572 aux.mode3(OUTPUT);
573
574 getConstants();
575 }
576
577 void HeadingBoard::pressure(int& temp, int& pres) const {
578 word D2 = adcValue(0);
579 // Serial.print("D2 = ");
580 // Serial.println(D2);
581 int corr = (D2 - C5) >> 7;
582 // Serial.print("corr = ");
583 // Serial.println(corr);
584 int dUT = (D2 - C5) - (corr * (long) corr * (D2 >= C5 ? A : B) >> C);
585 // Serial.print("dUT = ");
586 // Serial.println(dUT);
587 temp = 250 + (dUT * C6 >> 16) - (dUT >> D);
588
589 word D1 = adcValue(1);
590 // Serial.print("D1 = ");
591 // Serial.println(D1);
592 word OFF = (C2 + ((C4 - 1024) * dUT >> 14)) << 2;
593 // Serial.print("OFF = ");
594 // Serial.println(OFF);
595 word SENS = C1 + (C3 * dUT >> 10);
596 // Serial.print("SENS = ");
597 // Serial.println(SENS);
598 word X = (SENS * (D1 - 7168L) >> 14) - OFF;
599 // Serial.print("X = ");
600 // Serial.println(X);
601 pres = (X * 10L >> 5) + C7;
602 }
603
604 void HeadingBoard::heading(int& xaxis, int& yaxis) {
605 // set or reset the magnetometer coil
606 compass.send();
607 compass.write(0x00);
608 compass.write(setReset);
609 compass.stop();
610 delayMicroseconds(50);
611 setReset = 6 - setReset;
612 // perform measurement
613 compass.send();
614 compass.write(0x00);
615 compass.write(0x01);
616 compass.stop();
617 delay(5);
618 compass.send();
619 compass.write(0x00);
620 compass.receive();
621 byte tmp, reg = compass.read(0);
622 tmp = compass.read(0);
623 xaxis = ((tmp << 8) | compass.read(0)) - 2048;
624 tmp = compass.read(0);
625 yaxis = ((tmp << 8) | compass.read(1)) - 2048;
626 compass.stop();
627 }
628
629 InfraredPlug::InfraredPlug (uint8_t num)
630 : Port (num), slot (140), gap (80), fill (-1), prev (0) {
631 digiWrite(0);
632 mode(OUTPUT);
633 mode2(INPUT);
634 digiWrite2(1); // pull-up
635 }
636
637 void InfraredPlug::configure(uint8_t slot4, uint8_t gap256) {
638 slot = slot4;
639 gap = gap256;
640 fill = -1;
641 }
642
643 void InfraredPlug::poll() {
644 byte bit = digiRead2(); // 0 is interpreted as pulse ON
645 if (fill < 0) {
646 if (fill < -1 || bit == 1)
647 return;
648 fill = 0;
649 prev = micros();
650 memset(buf, 0, sizeof buf);
651 }
652 // act only if the bit changed, using the low bit of the nibble fill count
653 if (bit != (fill & 1) && fill < 2 * sizeof buf) {
654 uint32_t curr = micros(), diff = (curr - prev + 2) >> 2;
655 if (diff > 65000)
656 diff = 65000; // * 4 us, i.e. 260 ms
657 // convert to a slot number, with rounding halfway between each slot
658 word ticks = ((word) diff + slot / 2) / slot;
659 if (ticks > 20)
660 ticks = 20;
661 // condense upper values to fit in the range 0..15
662 byte nibble = ticks;
663 if (nibble > 10)
664 nibble -= (nibble - 10) / 2;
665 buf[fill>>1] |= nibble << ((fill & 1) << 2);
666 ++fill;
667 prev = curr;
668 }
669 }
670
671 uint8_t InfraredPlug::done() {
672 byte result = 0;
673 if (fill > 0)
674 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
675 if (((micros() - prev) >> 8) >= gap) {
676 result = fill;
677 fill = -2; // prevent new pulses from clobbering buf
678 }
679 }
680 else if (fill < -1)
681 fill = -1; // second call to done() release buffer again for capture
682 return result;
683 }
684
685 uint8_t InfraredPlug::decoder(uint8_t nibbles) {
686 switch (nibbles) {
687 case 67: // 2 + 64 + 1 nibbles could be a NEC packet
688 if (buf[0] == 0x8D && buf[33] == 0x01) {
689 // check that all nibbles are either 1 or 3
690 for (byte i = 1; i < 33; ++i)
691 if ((buf[i] & ~0x20) != 0x11)
692 return UNKNOWN;
693 // valid packet, convert in-place
694 for (byte i = 0; i < 4; ++i) {
695 byte v;
696 for (byte j = 0; j < 8; ++j)
697 v = (v << 1) | (buf[1+j+8*i] >> 5);
698 buf[i] = v;
699 }
700 return NEC;
701 }
702 break;
703 case 3: // 2 + 1 nibbles could be a NEC repeat packet
704 if (buf[0] == 0x4D && buf[1] == 0x01)
705 return NEC_REP;
706 break;
707 }
708 return UNKNOWN;
709 }
710
711 void InfraredPlug::send(const uint8_t* data, uint16_t bits) {
712 // TODO: switch to an interrupt-driven design
713 for (byte i = 0; i < bits; ++i) {
714 digiWrite(bitRead(data[i/8], i%8));
715 delayMicroseconds(4 * slot);
716 }
717 digiWrite(0);
718 }
719
720 void ProximityPlug::begin() {
721 delay(100);
722 setReg(CONFIG, 0x04); // reset, STOP1
723 delay(100);
724 // setReg(TPCONFIG, 0xB5); // TPSE, BKA, ACE, TPTBE, TPE
725 setReg(TPCONFIG, 0xB1); // TPSE, BKA, ACE, TPE
726 setReg(CONFIG, 0x15); // RUN1
727 delay(100);
728 }
729
730 void ProximityPlug::setReg(byte reg, byte value) const {
731 send();
732 write(reg);
733 write(value);
734 stop();
735 }
736
737 byte ProximityPlug::getReg(byte reg) const {
738 send();
739 write(reg);
740 receive();
741 byte result = read(1);
742 stop();
743 return result;
744 }
745
746 // ISR(WDT_vect) { Sleepy::watchdogEvent(); }
747
748 static volatile byte watchdogCounter;
749
750 void Sleepy::watchdogInterrupts (char mode) {
751 // correct for the fact that WDP3 is *not* in bit position 3!
752 if (mode & bit(3))
753 mode ^= bit(3) | bit(WDP3);
754 // pre-calculate the WDTCSR value, can't do it inside the timed sequence
755 // we only generate interrupts, no reset
756 byte wdtcsr = mode >= 0 ? bit(WDIE) | mode : 0;
757 MCUSR &= ~(1<<WDRF);
758 ATOMIC_BLOCK(ATOMIC_FORCEON) {
759 WDTCSR |= (1<<WDCE) | (1<<WDE); // timed sequence
760 WDTCSR = wdtcsr;
761 }
762 }
763
764 void Sleepy::powerDown (byte prrOff) {
765 byte adcsraSave = ADCSRA;
766 ADCSRA &= ~ bit(ADEN); // disable the ADC
767 #ifdef PRR
768 byte prrSave = PRR;
769 PRR = prrOff;
770 #endif
771 // see http://www.nongnu.org/avr-libc/user-manual/group__avr__sleep.html
772 set_sleep_mode(SLEEP_MODE_PWR_DOWN);
773 ATOMIC_BLOCK(ATOMIC_FORCEON) {
774 sleep_enable();
775 // sleep_bod_disable(); // can't use this - not in my avr-libc version!
776 #ifdef BODSE
777 MCUCR = MCUCR | bit(BODSE) | bit(BODS); // timed sequence
778 MCUCR = MCUCR & ~ bit(BODSE) | bit(BODS);
779 #endif
780 }
781 sleep_cpu();
782 sleep_disable();
783 // re-enable what we disabled
784 #ifdef PRR
785 PRR = prrSave;
786 #endif
787 ADCSRA = adcsraSave;
788 }
789
790 byte Sleepy::loseSomeTime (word msecs) {
791 // only slow down for periods longer than the watchdog granularity
792 while (msecs >= 16) {
793 char wdp = 0; // wdp 0..9 corresponds to roughly 16..8192 ms
794 while (msecs >= (32 << wdp) && wdp < 9)
795 ++wdp;
796 watchdogCounter = 0;
797 watchdogInterrupts(wdp);
798 powerDown();
799 watchdogInterrupts(-1); // off
800 if (watchdogCounter == 0)
801 return 0; // lost some time, but got interrupted
802 // adjust the milli ticks, since we will have missed several
803 extern volatile unsigned long timer0_millis;
804 timer0_millis += 16 << wdp;
805 msecs -= 16 << wdp;
806 }
807 return 1; // lost some time as planned
808 }
809
810 void Sleepy::watchdogEvent() {
811 ++watchdogCounter;
812 }
813
814 Scheduler::Scheduler (byte size) : maxTasks (size) {
815 byte bytes = size * sizeof *tasks;
816 tasks = (word*) malloc(bytes);
817 memset(tasks, 0xFF, bytes);
818 }
819
820 Scheduler::Scheduler (word* buf, byte size) : tasks (buf), maxTasks (size) {
821 byte bytes = size * sizeof *tasks;
822 memset(tasks, 0xFF, bytes);
823 }
824
825 char Scheduler::poll() {
826 // all times in the tasks array are relative to the "remaining" value
827 // i.e. only remaining counts down while waiting for the next timeout
828 if (remaining == 0) {
829 word lowest = ~0;
830 for (byte i = 0; i < maxTasks; ++i) {
831 if (tasks[i] == 0) {
832 tasks[i] = ~0;
833 return i;
834 }
835 if (tasks[i] < lowest)
836 lowest = tasks[i];
837 }
838 if (lowest != ~0)
839 for (byte i = 0; i < maxTasks; ++i)
840 tasks[i] -= lowest;
841 remaining = lowest;
842 } else if (ms100.poll(100))
843 --remaining;
844 return -1;
845 }
846
847 char Scheduler::pollWaiting() {
848 // first wait until the remaining time we need to wait is less than 0.1s
849 while (remaining > 0) {
850 if (!Sleepy::loseSomeTime(100)) // approximate, actually waits 96 ms
851 return -1;
852 --remaining;
853 }
854 // now lose some more time until that 0.1s mark
855 if (!Sleepy::loseSomeTime(ms100.remaining()))
856 return -1;
857 // lastly, just ignore the 0..15 ms still left to go until the 0.1s mark
858 return poll();
859 }
860
861 void Scheduler::timer(byte task, word tenths) {
862 // if new timer will go off sooner than the rest, then adjust all entries
863 if (tenths < remaining) {
864 word diff = remaining - tenths;
865 for (byte i = 0; i < maxTasks; ++i)
866 if (tasks[i] != ~0)
867 tasks[i] += diff;
868 remaining = tenths;
869 }
870 tasks[task] = tenths - remaining;
871 }
872
873 void Scheduler::cancel(byte task) {
874 tasks[task] = ~0;
875 }
876
877 #ifdef Stream_h // only available in recent Arduino IDE versions
878
879 InputParser::InputParser (byte* buf, byte size, Commands* ctab, Stream& stream)
880 : buffer (buf), limit (size), cmds (ctab), io (stream) {
881 reset();
882 }
883
884 InputParser::InputParser (byte size, Commands* ctab, Stream& stream)
885 : limit (size), cmds (ctab), io (stream) {
886 buffer = (byte*) malloc(size);
887 reset();
888 }
889
890 void InputParser::reset() {
891 fill = next = 0;
892 instring = hexmode = hasvalue = 0;
893 top = limit;
894 }
895
896 void InputParser::poll() {
897 if (!io.available())
898 return;
899 char ch = io.read();
900 if (ch < ' ' || fill >= top) {
901 reset();
902 return;
903 }
904 if (instring) {
905 if (ch == '"') {
906 buffer[fill++] = 0;
907 do
908 buffer[--top] = buffer[--fill];
909 while (fill > value);
910 ch = top;
911 instring = 0;
912 }
913 buffer[fill++] = ch;
914 return;
915 }
916 if (hexmode && ('0' <= ch && ch <= '9' ||
917 'A' <= ch && ch <= 'F' ||
918 'a' <= ch && ch <= 'f')) {
919 if (!hasvalue)
920 value = 0;
921 if (ch > '9')
922 ch += 9;
923 value <<= 4;
924 value |= (byte) (ch & 0x0F);
925 hasvalue = 1;
926 return;
927 }
928 if ('0' <= ch && ch <= '9') {
929 if (!hasvalue)
930 value = 0;
931 value = 10 * value + (ch - '0');
932 hasvalue = 1;
933 return;
934 }
935 hexmode = 0;
936 switch (ch) {
937 case '$': hexmode = 1;
938 return;
939 case '"': instring = 1;
940 value = fill;
941 return;
942 case ':': (word&) buffer[fill] = value;
943 fill += 2;
944 value >>= 16;
945 // fall through
946 case '.': (word&) buffer[fill] = value;
947 fill += 2;
948 hasvalue = 0;
949 return;
950 case '-': value = - value;
951 hasvalue = 0;
952 return;
953 case ' ': if (!hasvalue)
954 return;
955 // fall through
956 case ',': buffer[fill++] = value;
957 hasvalue = 0;
958 return;
959 }
960 if (hasvalue) {
961 io.print("Unrecognized character: ");
962 io.print(ch);
963 io.println();
964 reset();
965 return;
966 }
967
968 for (Commands* p = cmds; ; ++p) {
969 char code = pgm_read_byte(&p->code);
970 if (code == 0)
971 break;
972 if (ch == code) {
973 byte bytes = pgm_read_byte(&p->bytes);
974 if (fill < bytes) {
975 io.print("Not enough data, need ");
976 io.print((int) bytes);
977 io.println(" bytes");
978 } else {
979 memset(buffer + fill, 0, top - fill);
980 ((void (*)()) pgm_read_word(&p->fun))();
981 }
982 reset();
983 return;
984 }
985 }
986
987 io.print("Known commands:");
988 for (Commands* p = cmds; ; ++p) {
989 char code = pgm_read_byte(&p->code);
990 if (code == 0)
991 break;
992 io.print(' ');
993 io.print(code);
994 }
995 io.println();
996 }
997
998 InputParser& InputParser::get(void* ptr, byte len) {
999 memcpy(ptr, buffer + next, len);
1000 next += len;
1001 return *this;
1002 }
1003
1004 InputParser& InputParser::operator >> (const char*& v) {
1005 byte offset = buffer[next++];
1006 v = top <= offset && offset < limit ? (char*) buffer + offset : "";
1007 return *this;
1008 }
1009
1010 #endif // Stream_h
Something went wrong with that request. Please try again.