Statistics
| Revision:

root / Ports / Ports.h

History | View | Annotate | Download (13.2 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.h 7763 2011-12-11 01:28:16Z jcw $
6
7
#ifndef Ports_h
8
#define Ports_h
9
10
#include <WProgram.h>
11
#include <stdint.h>
12
#include <avr/pgmspace.h>
13
14
class Port {
15
protected:
16
    uint8_t portNum;
17
18
    inline uint8_t digiPin() const
19
        { return portNum ? portNum + 3 : 18; }
20
    inline uint8_t digiPin2() const
21
        { return portNum ? portNum + 13 : 19; }
22
    inline uint8_t anaPin() const
23
        { return portNum - 1; }
24
public:
25
    inline Port (uint8_t num) : portNum (num) {}
26
27
    // DIO pin
28
    inline void mode(uint8_t value) const
29
        { pinMode(digiPin(), value); }
30
    inline uint8_t digiRead() const
31
        { return digitalRead(digiPin()); }
32
    inline void digiWrite(uint8_t value) const
33
        { return digitalWrite(digiPin(), value); }
34
    inline void anaWrite(uint8_t val) const
35
        { analogWrite(digiPin(), val); }
36
    inline uint32_t pulse(uint8_t state, uint32_t timeout =1000000L) const
37
        { return pulseIn(digiPin(), state, timeout); }
38
    
39
    // AIO pin
40
    inline void mode2(uint8_t value) const
41
        { pinMode(digiPin2(), value); }
42
    inline uint16_t anaRead() const
43
        { return analogRead(anaPin()); }        
44
    inline uint8_t digiRead2() const
45
        { return digitalRead(digiPin2()); }
46
    inline void digiWrite2(uint8_t value) const
47
        { return digitalWrite(digiPin2(), value); }
48
    inline uint32_t pulse2(uint8_t state, uint32_t timeout =1000000L) const
49
        { return pulseIn(digiPin2(), state, timeout); }
50
        
51
    // IRQ pin (INT1, shared across all ports)
52
    static void mode3(uint8_t value)
53
        { pinMode(3, value); }
54
    static uint8_t digiRead3()
55
        { return digitalRead(3); }
56
    static void digiWrite3(uint8_t value)
57
        { return digitalWrite(3, value); }
58
    static void anaWrite3(uint8_t val)
59
        { analogWrite(3, val); }
60
        
61
    // both pins: data on DIO, clock on AIO
62
    inline void shift(uint8_t bitOrder, uint8_t value) const
63
        { shiftOut(digiPin(), digiPin2(), bitOrder, value); }
64
    uint16_t shiftRead(uint8_t bitOrder, uint8_t count =8) const;
65
    void shiftWrite(uint8_t bitOrder, uint16_t value, uint8_t count =8) const;
66
};
67
68
class RemoteNode {
69
public: 
70
    typedef struct {
71
        uint8_t flags, modes, digiIO, anaOut[2];
72
        uint16_t anaIn[4]; // only bits 0..11 used
73
    } Data;
74
75
    RemoteNode (char id, uint8_t band, uint8_t group =0);
76
    
77
    void poll(uint16_t msecs);
78
79
    friend class RemoteHandler;
80
    friend class RemotePort;
81
private:
82
    uint8_t nid;
83
    uint32_t lastPoll;
84
    Data data;
85
};
86
87
class RemoteHandler {
88
public:
89
    static void setup(uint8_t id, uint8_t band, uint8_t group =0);
90
    static uint8_t poll(RemoteNode& node, uint8_t send);
91
};
92
93
class RemotePort : protected Port {
94
    RemoteNode& node;
95
96
    inline uint8_t pinBit() const
97
        { return portNum - 1; }
98
    inline uint8_t pinBit2() const
99
        { return portNum + 3; }
100
public:
101
    RemotePort (RemoteNode& remote, uint8_t num) : Port (num), node (remote) {}
102
103
    void mode(uint8_t value) const;
104
    uint8_t digiRead() const;
105
    void digiWrite(uint8_t value) const;
106
    void anaWrite(uint8_t val) const;
107
    
108
    void mode2(uint8_t value) const;    
109
    uint16_t anaRead() const;
110
    uint8_t digiRead2() const;
111
    void digiWrite2(uint8_t value) const;    
112
};
113
114
class PortI2C : public Port {
115
    uint8_t uswait;
116
    
117
    inline void hold() const
118
        { delayMicroseconds(uswait); }
119
    inline void sdaOut(uint8_t value) const
120
        { mode(!value); digiWrite(value); }
121
    inline uint8_t sdaIn() const
122
        { return digiRead(); }
123
    inline void sclHi() const
124
        { hold(); digiWrite2(1); }
125
    inline void sclLo() const
126
        { hold(); digiWrite2(0); }
127
public:
128
    enum { KHZMAX = 1, KHZ400 = 2, KHZ100 = 9 };
129
    
130
    PortI2C (uint8_t num, uint8_t rate =KHZMAX);
131
    
132
    uint8_t start(uint8_t addr) const;
133
    void stop() const;
134
    uint8_t write(uint8_t data) const;
135
    uint8_t read(uint8_t last) const;
136
};
137
138
class DeviceI2C {
139
    const PortI2C& port;
140
    uint8_t addr;
141
    
142
public:
143
    DeviceI2C(const PortI2C& p, uint8_t me) : port (p), addr (me << 1) {}
144
    
145
    bool isPresent() const;
146
    
147
    uint8_t send() const
148
        { return port.start(addr); }
149
    uint8_t receive() const
150
        { return port.start(addr | 1); }
151
    void stop() const
152
        { port.stop(); }
153
    uint8_t write(uint8_t data) const
154
        { return port.write(data); }
155
    uint8_t read(uint8_t last) const
156
        { return port.read(last); }
157
        
158
    uint8_t setAddress(uint8_t me)
159
        { addr = me << 1; }
160
};
161
162
// The millisecond timer can be used for timeouts up to 60000 milliseconds.
163
// Setting the timeout to zero disables the timer.
164
//
165
// for periodic timeouts, poll the timer object with "if (timer.poll(123)) ..."
166
// for one-shot timeouts, call "timer.set(123)" and poll as "if (timer.poll())"
167
168
class MilliTimer {
169
    word next;
170
    byte armed;
171
public:
172
    MilliTimer () : armed (0) {}
173
    
174
    byte poll(word ms =0);
175
    word remaining() const;
176
    byte idle() const { return !armed; }
177
    void set(word ms);
178
};
179
180
// Low-power utility code.
181
class Sleepy {
182
public:
183
    // start the watchdog timer (or disable it if mode < 0)
184
    static void watchdogInterrupts (char mode);
185
    
186
    // enter low-power mode, wake up with watchdog, INT0/1, or pin-change
187
    static void powerDown (byte prrOff =0xFF);
188
    
189
    // spend some time in low-power mode, the timing is only approximate
190
    // returns 1 if all went normally, or 0 if some other interrupt occurred
191
    static byte loseSomeTime (word msecs);
192
193
    // this must be called from your watchdog interrupt code
194
    static void watchdogEvent();
195
};
196
197
// simple task scheduler for times up to 6000 seconds
198
class Scheduler {
199
    word* tasks, remaining;
200
    byte maxTasks;
201
    MilliTimer ms100;
202
public:
203
    // initialize for a specified maximum number of tasks
204
    Scheduler (byte max);
205
    Scheduler (word* buf, byte max);
206
207
    // return next task to run, or -1 if there is none
208
    char poll();
209
    // same as poll, but wait for event in power-down mode
210
    char pollWaiting();
211
    
212
    // set a task timer, in tenths of seconds
213
    void timer(byte task, word tenths);
214
    // cancel a task timer
215
    void cancel(byte task);
216
    
217
    // return true if a task timer is not running
218
    byte idle(byte task) { return tasks[task] == ~0; }
219
};
220
221
// interface for the Blink Plug - see http://jeelabs.org/bp1
222
class BlinkPlug : public Port {
223
    MilliTimer debounce;
224
    byte leds, lastState, checkFlags;
225
public:
226
    enum { ALL_OFF, ON1, OFF1, ON2, OFF2, SOME_ON, ALL_ON }; // for buttonCheck
227
    
228
    BlinkPlug (byte port)
229
        : Port (port), leds (0), lastState (0), checkFlags (0) {}
230
    
231
    void ledOn(byte mask);
232
    void ledOff(byte mask);
233
    byte state();
234
    byte pushed(); // deprecated, don't use in combination with buttonCheck
235
    byte buttonCheck();
236
};
237
238
// interface for the Memory Plug - see http://jeelabs.org/mp1
239
class MemoryPlug : public DeviceI2C {
240
    uint32_t nextSave;
241
public:
242
    MemoryPlug (PortI2C& port)
243
        : DeviceI2C (port, 0x50), nextSave (0) {}
244
245
    void load(word page, void* buf, byte offset =0, int count =256);
246
    void save(word page, const void* buf, byte offset =0, int count =256);
247
};
248
249
class MemoryStream {
250
    MemoryPlug& dev;
251
    word start, curr;
252
    char step;
253
    byte buffer[256], pos;
254
public:
255
    MemoryStream (MemoryPlug& plug, word page =0, char dir =1)
256
            : dev (plug), start (page), curr (page), step (dir), pos (0) {}
257
    
258
    long position(byte writing) const;
259
    byte get();
260
    void put(byte data);
261
    word flush();
262
    void reset();
263
};
264
265
// interface for the UART Plug - see http://jeelabs.org/up1
266
class UartPlug : public Print {
267
    DeviceI2C dev;
268
    // avoid per-byte access, fill entire buffer instead to reduce I2C overhead
269
    byte rxbuf[20], in, out;
270
271
    void regSet (byte reg, byte value);
272
    void regRead (byte reg);
273
    
274
public:
275
    UartPlug (PortI2C& port, byte addr)
276
        : dev (port, addr), in (0), out (0) {}
277
        
278
    void begin(long);
279
    byte available();
280
    int read();
281
    void flush();
282
    virtual void write(byte);
283
};
284
285
// interface for the Dimmer Plug - see http://jeelabs.org/dp1
286
class DimmerPlug : public DeviceI2C {
287
public:
288
    enum {
289
        MODE1, MODE2,
290
        PWM0, PWM1, PWM2, PWM3, PWM4, PWM5, PWM6, PWM7,
291
        PWM8, PWM9, PWM10, PWM11, PWM12, PWM13, PWM14, PWM15,
292
        GRPPWM, GRPFREQ,
293
        LEDOUT0, LEDOUT1, LEDOUT2, LEDOUT3,
294
        SUBADR1, SUBADR2, SUBADR3, ALLCALLADR,
295
    };
296
297
    DimmerPlug (PortI2C& port, byte addr)
298
        : DeviceI2C (port, addr) {}
299
    
300
    void begin ();
301
    byte getReg(byte reg) const;
302
    void setReg(byte reg, byte value) const;
303
    void setMulti(byte reg, ...) const;
304
};
305
306
// interface for the Lux Plug - see http://jeelabs.org/xp1
307
class LuxPlug : public DeviceI2C {
308
    union { byte b[4]; word w[2]; } data;
309
public:
310
    enum {
311
        CONTROL, TIMING,
312
        THRESHLOWLOW, THRESHLOWHIGH, THRESHHIGHLOW, THRESHHIGHHIGH, INTERRUPT,
313
        LUXID = 0xA,
314
        DATA0LOW = 0xC, DATA0HIGH, DATA1LOW, DATA1HIGH,
315
    };
316
317
    LuxPlug (PortI2C& port, byte addr) : DeviceI2C (port, addr) {}
318
    
319
    void begin() {
320
        send();
321
        write(0xC0 | CONTROL);
322
        write(3); // power up
323
        stop();
324
    }
325
    
326
    void setGain(byte high);
327
    
328
    const word* getData();
329
330
    word calcLux(byte iGain =0, byte tInt =2) const;
331
};
332
333
// interface for the Gravity Plug - see http://jeelabs.org/gp1
334
class GravityPlug : public DeviceI2C {
335
    union { byte b[6]; int w[3]; } data;
336
public:
337
    GravityPlug (PortI2C& port) : DeviceI2C (port, 0x38) {}
338
    
339
    void begin() {}
340
    
341
    const int* getAxes();
342
};
343
344
// interface for the Input Plug - see http://jeelabs.org/ip1
345
class InputPlug : public Port {
346
    uint8_t slow;
347
public:
348
    InputPlug (uint8_t num, uint8_t fix =0) : Port (num), slow (fix) {}
349
    
350
    void select(uint8_t channel);
351
};
352
353
// interface for the Infrared Plug - see http://jeelabs.org/ir1
354
class InfraredPlug : public Port {
355
    uint8_t slot, gap, buf [40];
356
    char fill;
357
    uint32_t prev;
358
public:
359
    // initialize with default values for NEC protocol
360
    InfraredPlug (uint8_t num);
361
    
362
    // set slot size (us*4) and end-of-data gap (us*256)
363
    void configure(uint8_t slot4, uint8_t gap256 =80);
364
    
365
    // call this continuously or at least right after a pin change
366
    void poll();
367
    
368
    // returns number of nibbles read, or 0 if not yet ready
369
    uint8_t done();
370
    
371
    // try to decode a received packet, return type of packet
372
    // if recognized, the receive buffer will be overwritten with the results
373
    enum { UNKNOWN, NEC, NEC_REP };
374
    uint8_t decoder(uint8_t nibbles);
375
    
376
    // access to the receive buffer
377
    const uint8_t* buffer() { return buf; }
378
    
379
    // send out a bit pattern, cycle time is the "slot4" config value
380
    void send(const uint8_t* data, uint16_t bits);
381
};
382
383
// interface for the Heading Board - see http://jeelabs.org/hb1
384
class HeadingBoard : public PortI2C {
385
    DeviceI2C eeprom, adc, compass;
386
    Port aux;
387
    // keep following fields in order:
388
    word C1, C2, C3, C4, C5, C6, C7;
389
    byte A, B, C, D, setReset;
390
391
    byte eepromByte(byte reg) const;
392
    void getConstants();
393
    word adcValue(byte press) const;
394
395
public:
396
    HeadingBoard (int num)
397
        : PortI2C (num), eeprom (*this, 0x50), adc (*this, 0x77),
398
          compass (*this, 0x30), aux (5-num), setReset (0x02) {}
399
    
400
    void begin();
401
    void pressure(int& temp, int& pres) const;
402
    void heading(int& xaxis, int& yaxis);
403
};
404
405
// interface for the Proximity Plug - see http://jeelabs.org/yp1
406
class ProximityPlug : public DeviceI2C {
407
public:
408
    enum {
409
        FIFO, FAULT, TPSTATUS, TPCONFIG,
410
        STR1, STR2, STR3, STR4, STR5, STR6, STR7, STR8, 
411
        ECEMR, MNTPR, MTPR, TASPR, SCR, LPCR, SKTR,
412
        CONFIG, SINFO,
413
    };
414
415
    ProximityPlug (PortI2C& port, byte num =0)
416
        : DeviceI2C (port, 0x5C + num) {}
417
    
418
    void begin();
419
    
420
    void setReg(byte reg, byte value) const;
421
    byte getReg(byte reg) const;
422
};
423
424
#ifdef Stream_h // only available in recent Arduino IDE versions
425
426
// simple parser for input data and one-letter commands
427
class InputParser {
428
public:
429
    typedef struct {
430
        char code;      // one-letter command code
431
        byte bytes;     // number of bytes required as input
432
        void (*fun)();  // code to call for this command
433
    } Commands;
434
    
435
    // set up with a buffer of specified size
436
    InputParser (byte size, Commands PROGMEM*, Stream& =Serial);
437
    InputParser (byte* buf, byte size, Commands PROGMEM*, Stream& =Serial);
438
    
439
    // number of data bytes
440
    byte count() { return fill; }
441
    
442
    // call this frequently to check for incoming data
443
    void poll();
444
    
445
    InputParser& operator >> (char& v)      { return get(&v, 1); }
446
    InputParser& operator >> (byte& v)      { return get(&v, 1); }
447
    InputParser& operator >> (int& v)       { return get(&v, 2); }
448
    InputParser& operator >> (word& v)      { return get(&v, 2); }
449
    InputParser& operator >> (long& v)      { return get(&v, 4); }
450
    InputParser& operator >> (uint32_t& v)  { return get(&v, 4); }
451
    InputParser& operator >> (const char*& v);
452
453
private:
454
    InputParser& get(void*, byte);
455
    void reset();
456
    
457
    byte *buffer, limit, fill, top, next;
458
    byte instring, hexmode, hasvalue;
459
    uint32_t value;
460
    Commands* cmds;
461
    Stream& io;
462
};
463
464
#endif // Stream_h
465
466
#endif