Statistics
| Revision:

root / Ports / Ports.h

History | View | Annotate | Download (13.2 KB)

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