Statistics
| Revision:

root / Ports / Ports.cpp

History | View | Annotate | Download (26.1 KB)

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