|
| 1 | +""" |
| 2 | +Drivers for electricdollarstore I2C parts |
| 3 | +""" |
| 4 | +import struct |
| 5 | +import time |
| 6 | +import datetime |
| 7 | + |
| 8 | +class Dig2: |
| 9 | + """ DIG2 is a 2-digit 7-segment LED display """ |
| 10 | + |
| 11 | + def __init__(self, i2, a = 0x14): |
| 12 | + self.i2 = i2 |
| 13 | + self.a = a |
| 14 | + |
| 15 | + def raw(self, b0, b1): |
| 16 | + """ Set all 8 segments from the bytes b0 and b1 """ |
| 17 | + self.i2.regwr(self.a, 0, struct.pack("BB", b0, b1)) |
| 18 | + |
| 19 | + def hex(self, b): |
| 20 | + """ Display a hex number 0-0xff """ |
| 21 | + self.i2.regwr(self.a, 1, b) |
| 22 | + |
| 23 | + def dec(self, b): |
| 24 | + """ Display a decimal number 00-99 """ |
| 25 | + self.i2.regwr(self.a, 2, b) |
| 26 | + |
| 27 | + def dp(self, p0, p1): |
| 28 | + """ Set the state the decimal point indicators """ |
| 29 | + self.i2.regwr(self.a, 3, (p1 << 1) | p0) |
| 30 | + |
| 31 | + def brightness(self, b): |
| 32 | + """ Set the brightness from 0 (off) to 255 (maximum) """ |
| 33 | + self.i2.regwr(self.a, 4, b) |
| 34 | + |
| 35 | +class LED: |
| 36 | + """ LED is an RGB LED """ |
| 37 | + def __init__(self, i2, a = 0x08): |
| 38 | + self.i2 = i2 |
| 39 | + self.a = a |
| 40 | + |
| 41 | + def rgb(self, r, g, b, t = 0): |
| 42 | + """ |
| 43 | + Set the color to (r,g,b). Each is a byte 0-255. |
| 44 | + If t is nonzero, the change happens over t/30 seconds. |
| 45 | + For example if t is 15 the color fades over a half-second. |
| 46 | + """ |
| 47 | + if t == 0: |
| 48 | + self.i2.start(self.a, 0) |
| 49 | + self.i2.regwr(self.a, 0, r, g, b) |
| 50 | + else: |
| 51 | + self.i2.start(self.a, 0) |
| 52 | + self.i2.regwr(self.a, 1, r, g, b, t) |
| 53 | + |
| 54 | + def hex(self, hhh, t = 0): |
| 55 | + """ |
| 56 | + Set the color to hhh, a 24-bit RGB color. |
| 57 | + If t is nonzero, the change happens over t/30 seconds. |
| 58 | + For example if t is 15 the color fades over a half-second. |
| 59 | + """ |
| 60 | + r = (hhh >> 16) & 0xff |
| 61 | + g = (hhh >> 8) & 0xff |
| 62 | + b = hhh & 0xff |
| 63 | + self.rgb(r, g, b, t) |
| 64 | + |
| 65 | +class Pot: |
| 66 | + """ POT is an analog knob potentiometer """ |
| 67 | + def __init__(self, i2, a = 0x28): |
| 68 | + self.i2 = i2 |
| 69 | + self.a = a |
| 70 | + |
| 71 | + def raw(self): |
| 72 | + """ |
| 73 | + Return the current knob rotation as a 16-bit integer. |
| 74 | + """ |
| 75 | + return self.i2.regrd(self.a, 0, "H") |
| 76 | + |
| 77 | + def rd(self, r): |
| 78 | + """ |
| 79 | + Return the current knob rotation, scaled to the range 0 .. r |
| 80 | + inclusive. For example rd(100) returns a value in the range 0 to 100. |
| 81 | + """ |
| 82 | + return self.i2.regrd(self.a, r) |
| 83 | + |
| 84 | +class Beep: |
| 85 | + """ BEEP is a beeper """ |
| 86 | + def __init__(self, i2, a = 0x30): |
| 87 | + self.i2 = i2 |
| 88 | + self.a = a |
| 89 | + |
| 90 | + def beep(self, dur, note): |
| 91 | + """ |
| 92 | + Play a note. |
| 93 | + dur is the duration in milliseconds, 0-255. |
| 94 | + note is a MIDI note in the range 21-127 inclusive. |
| 95 | + """ |
| 96 | + self.i2.regwr(self.a, dur, note) |
| 97 | + |
| 98 | +class Remote: |
| 99 | + """ REMOTE is a NEC IR code receiver / decoder """ |
| 100 | + def __init__(self, i2, a = 0x60): |
| 101 | + self.i2 = i2 |
| 102 | + self.a = a |
| 103 | + |
| 104 | + def key(self): |
| 105 | + """ |
| 106 | + For the electricdollarstore IR transmitter. |
| 107 | + If there is a code in the queue, return its character code. |
| 108 | + The layout of the remote is |
| 109 | + |
| 110 | + p c n |
| 111 | + < > ' ' |
| 112 | + - + = |
| 113 | + 0 % & |
| 114 | + 1 2 3 |
| 115 | + 4 5 6 |
| 116 | + 7 8 9 |
| 117 | +
|
| 118 | + If there is no IR code in the queue, return None. |
| 119 | + """ |
| 120 | + r = self.i2.regrd(self.a, 0) |
| 121 | + if r != 0: |
| 122 | + return chr(r) |
| 123 | + |
| 124 | + def raw(self): |
| 125 | + """ |
| 126 | + If there is a code in the queue, return a tuple containing the four-byte code, |
| 127 | + and a timestamp. |
| 128 | + If there is no IR code in the queue, return None. |
| 129 | + """ |
| 130 | + |
| 131 | + r = self.i2.regrd(self.a, 1, "4BH") |
| 132 | + if r[:4] != (0xff, 0xff, 0xff, 0xff): |
| 133 | + age_in_ms = r[4] |
| 134 | + return (r[:4], time.time() - age_in_ms * .001) |
| 135 | + else: |
| 136 | + return None |
| 137 | + |
| 138 | +class Temp: |
| 139 | + """ TEMP is a LM75B temperature sesnor """ |
| 140 | + def __init__(self, i2, a = 0x48): |
| 141 | + self.i2 = i2 |
| 142 | + self.a = a |
| 143 | + |
| 144 | + def reg(self, r): |
| 145 | + return self.i2.regrd(self.a, r, ">h") |
| 146 | + |
| 147 | + def read(self): |
| 148 | + """ Return the current temperature in Celsius """ |
| 149 | + return (self.reg(0) >> 5) * 0.125 |
| 150 | + |
| 151 | +class EPROM: |
| 152 | + """ EPROM is a CAT24C512 512 Kbit (64 Kbyte) flash memory """ |
| 153 | + def __init__(self, i2, a = 0x50): |
| 154 | + self.i2 = i2 |
| 155 | + self.a = a |
| 156 | + |
| 157 | + def write(self, addr, data): |
| 158 | + """ Write data to EPROM, starting at address addr """ |
| 159 | + for i in range(0, len(data), 128): |
| 160 | + self.i2.start(self.a, 0) |
| 161 | + self.i2.write(struct.pack(">H", addr + i)) |
| 162 | + self.i2.write(data[i:i + 128]) |
| 163 | + self.i2.stop() |
| 164 | + while self.i2.start(self.a, 0) == False: |
| 165 | + pass |
| 166 | + |
| 167 | + def read(self, addr, n): |
| 168 | + """ Read n bytes from the EPROM, starting at address addr """ |
| 169 | + self.i2.start(self.a, 0) |
| 170 | + self.i2.write(struct.pack(">H", addr)) |
| 171 | + self.i2.start(self.a, 1) |
| 172 | + r = self.i2.read(n) |
| 173 | + self.i2.stop() |
| 174 | + return r |
| 175 | + self.i2.stop() |
| 176 | + |
| 177 | +class Clock: |
| 178 | + """ CLOCK is a HT1382 I2C/3-Wire Real Time Clock with a 32 kHz crystal """ |
| 179 | + def __init__(self, i2, a = 0x68): |
| 180 | + self.i2 = i2 |
| 181 | + self.a = a |
| 182 | + |
| 183 | + def set(self, t = None): |
| 184 | + if t is None: |
| 185 | + t = datetime.datetime.now() |
| 186 | + def bcd(x): |
| 187 | + return (x % 10) + 16 * (x // 10) |
| 188 | + self.i2.regwr(self.a, 7, 0) |
| 189 | + self.i2.regwr(self.a, 6, bcd(t.year % 100)) |
| 190 | + self.i2.regwr(self.a, 5, 1 + t.weekday()) |
| 191 | + self.i2.regwr(self.a, 4, bcd(t.month)) |
| 192 | + self.i2.regwr(self.a, 3, bcd(t.day)) |
| 193 | + self.i2.regwr(self.a, 2, 0x80 | bcd(t.hour)) # use 24-hour mode |
| 194 | + self.i2.regwr(self.a, 1, bcd(t.minute)) |
| 195 | + self.i2.regwr(self.a, 0, bcd(t.second)) |
| 196 | + |
| 197 | + def read(self): |
| 198 | + self.i2.start(self.a, 0) |
| 199 | + self.i2.write([0]) |
| 200 | + self.i2.stop() |
| 201 | + self.i2.start(self.a, 1) |
| 202 | + (ss,mm,hh,dd,MM,ww,yy) = (struct.unpack("7B", self.i2.read(7))) |
| 203 | + self.i2.stop() |
| 204 | + def dec(x): |
| 205 | + return (x % 16) + 10 * (x // 16) |
| 206 | + return datetime.datetime( |
| 207 | + 2000 + dec(yy), |
| 208 | + dec(MM), |
| 209 | + dec(dd), |
| 210 | + dec(hh & 0x7f), |
| 211 | + dec(mm), |
| 212 | + dec(ss)) |
| 213 | + |
| 214 | + def dump(self): |
| 215 | + self.i2.start(self.a, 0) |
| 216 | + self.i2.write([0]) |
| 217 | + self.i2.stop() |
| 218 | + self.i2.start(self.a, 1) |
| 219 | + print(list(self.i2.read(16))) |
| 220 | + self.i2.stop() |
| 221 | + |
| 222 | +class Magnet: |
| 223 | + """ MAGNET is an ST LIS3MDL 3-axis magnetometer """ |
| 224 | + def __init__(self, i2, a = 0x1c): |
| 225 | + self.i2 = i2 |
| 226 | + self.a = a |
| 227 | + self.i2.regwr(self.a, 0x22, 0) # CTRL_REG3 operating mode 0: continuous conversion |
| 228 | + |
| 229 | + def rd(self): |
| 230 | + """ Read the measurement STATUS_REG and OUT_X,Y,Z """ |
| 231 | + return self.i2.regrd(self.a, 0x27, "<B3h") |
| 232 | + |
| 233 | + def measurement(self): |
| 234 | + """ Wait for a new field reading, return the (x,y,z) """ |
| 235 | + while True: |
| 236 | + (status, x, y, z) = self.rd() |
| 237 | + if status & 8: |
| 238 | + return (x, y, z) |
| 239 | + |
| 240 | +class Accel: |
| 241 | + """ ACCEL is a Richtek RT3000C 3-Axis Digital Accelerometer """ |
| 242 | + |
| 243 | + def __init__(self, i2, a = 0x19): |
| 244 | + self.i2 = i2 |
| 245 | + self.a = a |
| 246 | + |
| 247 | + print(bin(i2.regrd(self.a, 0xf))) |
| 248 | + i2.regwr(self.a, 0x20, 0b01000111) # CTRL_REG1: 50 Hz, enable X,Y,Z |
| 249 | + i2.regwr(self.a, 0x23, 0b00000000) # CTRL_REG4: High resolution mode |
| 250 | + |
| 251 | + def measurement(self): |
| 252 | + """ Wait for a new reading, return the (x,y,z) acceleration in g """ |
| 253 | + |
| 254 | + # Note that the RT3000A does not support multibyte |
| 255 | + # reads. So must read the data one byte at a time. |
| 256 | + |
| 257 | + while True: |
| 258 | + STS_REG = self.i2.regrd(self.a, 0x27) |
| 259 | + if STS_REG & 8: |
| 260 | + regs = [self.i2.regrd(self.a, i) for i in range(0x28, 0x2e)] |
| 261 | + xyz = struct.unpack("<3h", struct.pack("6B", *regs)) |
| 262 | + return tuple([c / 16384. for c in xyz]) |
0 commit comments