root / quad2 / arduino / src / ros_lib / examples / BlinkM / BlinkM_funcs.h @ c1426757
History | View | Annotate | Download (11.4 KB)
1 | c1426757 | Tom Mullins | /*
|
---|---|---|---|
2 | * BlinkM_funcs.h -- Arduino 'library' to control BlinkM
|
||
3 | * --------------
|
||
4 | *
|
||
5 | *
|
||
6 | * Note: original version of this file lives with the BlinkMTester sketch
|
||
7 | *
|
||
8 | * Note: all the functions are declared 'static' because
|
||
9 | * it saves about 1.5 kbyte in code space in final compiled sketch.
|
||
10 | * A C++ library of this costs a 1kB more.
|
||
11 | *
|
||
12 | * 2007-8, Tod E. Kurt, ThingM, http://thingm.com/
|
||
13 | *
|
||
14 | * version: 20081101
|
||
15 | *
|
||
16 | * history:
|
||
17 | * 20080101 - initial release
|
||
18 | * 20080203 - added setStartupParam(), bugfix receiveBytes() from Dan Julio
|
||
19 | * 20081101 - fixed to work with Arduino-0012, added MaxM commands,
|
||
20 | * added test script read/write functions, cleaned up some functions
|
||
21 | * 20090121 - added I2C bus scan functions, has dependencies on private
|
||
22 | * functions inside Wire library, so might break in the future
|
||
23 | * 20100420 - added BlinkM_startPower and _stopPower
|
||
24 | *
|
||
25 | */
|
||
26 | |||
27 | #include "WProgram.h" |
||
28 | #include "wiring.h" |
||
29 | #include <Wire.h> |
||
30 | |||
31 | extern "C" { |
||
32 | #include "utility/twi.h" // from Wire library, so we can do bus scanning |
||
33 | } |
||
34 | |||
35 | |||
36 | // format of light script lines: duration, command, arg1,arg2,arg3
|
||
37 | typedef struct _blinkm_script_line { |
||
38 | uint8_t dur; |
||
39 | uint8_t cmd[4]; // cmd,arg1,arg2,arg3 |
||
40 | } blinkm_script_line; |
||
41 | |||
42 | |||
43 | // Call this first (when powering BlinkM from a power supply)
|
||
44 | static void BlinkM_begin() |
||
45 | { |
||
46 | Wire.begin(); // join i2c bus (address optional for master)
|
||
47 | } |
||
48 | |||
49 | /*
|
||
50 | * actually can't do this either, because twi_init() has THREE callocs in it too
|
||
51 | *
|
||
52 | static void BlinkM_reset()
|
||
53 | {
|
||
54 | twi_init(); // can't just call Wire.begin() again because of calloc()s there
|
||
55 | }
|
||
56 | */
|
||
57 | |||
58 | //
|
||
59 | // each call to twi_writeTo() should return 0 if device is there
|
||
60 | // or other value (usually 2) if nothing is at that address
|
||
61 | //
|
||
62 | static void BlinkM_scanI2CBus(byte from, byte to, |
||
63 | void(*callback)(byte add, byte result) )
|
||
64 | { |
||
65 | byte rc; |
||
66 | byte data = 0; // not used, just an address to feed to twi_writeTo() |
||
67 | for( byte addr = from; addr <= to; addr++ ) {
|
||
68 | rc = twi_writeTo(addr, &data, 0, 1); |
||
69 | callback( addr, rc ); |
||
70 | } |
||
71 | } |
||
72 | |||
73 | //
|
||
74 | //
|
||
75 | static int8_t BlinkM_findFirstI2CDevice()
|
||
76 | { |
||
77 | byte rc; |
||
78 | byte data = 0; // not used, just an address to feed to twi_writeTo() |
||
79 | for( byte addr=1; addr < 120; addr++ ) { // only scan addrs 1-120 |
||
80 | rc = twi_writeTo(addr, &data, 0, 1); |
||
81 | if( rc == 0 ) return addr; // found an address |
||
82 | } |
||
83 | return -1; // no device found in range given |
||
84 | } |
||
85 | |||
86 | // FIXME: make this more Arduino-like
|
||
87 | static void BlinkM_startPowerWithPins(byte pwrpin, byte gndpin) |
||
88 | { |
||
89 | DDRC |= _BV(pwrpin) | _BV(gndpin); // make outputs
|
||
90 | PORTC &=~ _BV(gndpin); |
||
91 | PORTC |= _BV(pwrpin); |
||
92 | } |
||
93 | |||
94 | // FIXME: make this more Arduino-like
|
||
95 | static void BlinkM_stopPowerWithPins(byte pwrpin, byte gndpin) |
||
96 | { |
||
97 | DDRC &=~ (_BV(pwrpin) | _BV(gndpin)); |
||
98 | } |
||
99 | |||
100 | //
|
||
101 | static void BlinkM_startPower() |
||
102 | { |
||
103 | BlinkM_startPowerWithPins( PORTC3, PORTC2 ); |
||
104 | } |
||
105 | |||
106 | //
|
||
107 | static void BlinkM_stopPower() |
||
108 | { |
||
109 | BlinkM_stopPowerWithPins( PORTC3, PORTC2 ); |
||
110 | } |
||
111 | |||
112 | // General version of BlinkM_beginWithPower().
|
||
113 | // Call this first when BlinkM is plugged directly into Arduino
|
||
114 | static void BlinkM_beginWithPowerPins(byte pwrpin, byte gndpin) |
||
115 | { |
||
116 | BlinkM_startPowerWithPins(pwrpin,gndpin); |
||
117 | delay(100); // wait for things to stabilize |
||
118 | Wire.begin(); |
||
119 | } |
||
120 | |||
121 | // Call this first when BlinkM is plugged directly into Arduino
|
||
122 | // FIXME: make this more Arduino-like
|
||
123 | static void BlinkM_beginWithPower() |
||
124 | { |
||
125 | BlinkM_beginWithPowerPins( PORTC3, PORTC2 ); |
||
126 | } |
||
127 | |||
128 | // sends a generic command
|
||
129 | static void BlinkM_sendCmd(byte addr, byte* cmd, int cmdlen) |
||
130 | { |
||
131 | Wire.beginTransmission(addr); |
||
132 | for( byte i=0; i<cmdlen; i++) |
||
133 | Wire.send(cmd[i]); |
||
134 | Wire.endTransmission(); |
||
135 | } |
||
136 | |||
137 | // receives generic data
|
||
138 | // returns 0 on success, and -1 if no data available
|
||
139 | // note: responsiblity of caller to know how many bytes to expect
|
||
140 | static int BlinkM_receiveBytes(byte addr, byte* resp, byte len) |
||
141 | { |
||
142 | Wire.requestFrom(addr, len); |
||
143 | if( Wire.available() ) {
|
||
144 | for( int i=0; i<len; i++) |
||
145 | resp[i] = Wire.receive(); |
||
146 | return 0; |
||
147 | } |
||
148 | return -1; |
||
149 | } |
||
150 | |||
151 | // Sets the I2C address of the BlinkM.
|
||
152 | // Uses "general call" broadcast address
|
||
153 | static void BlinkM_setAddress(byte newaddress) |
||
154 | { |
||
155 | Wire.beginTransmission(0x00); // general call (broadcast address) |
||
156 | Wire.send('A');
|
||
157 | Wire.send(newaddress); |
||
158 | Wire.send(0xD0);
|
||
159 | Wire.send(0x0D); // dood! |
||
160 | Wire.send(newaddress); |
||
161 | Wire.endTransmission(); |
||
162 | delay(50); // just in case |
||
163 | } |
||
164 | |||
165 | |||
166 | // Gets the I2C address of the BlinKM
|
||
167 | // Kind of redundant when sent to a specific address
|
||
168 | // but uses to verify BlinkM communication
|
||
169 | static int BlinkM_getAddress(byte addr) |
||
170 | { |
||
171 | Wire.beginTransmission(addr); |
||
172 | Wire.send('a');
|
||
173 | Wire.endTransmission(); |
||
174 | Wire.requestFrom(addr, (byte)1); // general call |
||
175 | if( Wire.available() ) {
|
||
176 | byte b = Wire.receive(); |
||
177 | return b;
|
||
178 | } |
||
179 | return -1; |
||
180 | } |
||
181 | |||
182 | // Gets the BlinkM firmware version
|
||
183 | static int BlinkM_getVersion(byte addr) |
||
184 | { |
||
185 | Wire.beginTransmission(addr); |
||
186 | Wire.send('Z');
|
||
187 | Wire.endTransmission(); |
||
188 | Wire.requestFrom(addr, (byte)2);
|
||
189 | if( Wire.available() ) {
|
||
190 | byte major_ver = Wire.receive(); |
||
191 | byte minor_ver = Wire.receive(); |
||
192 | return (major_ver<<8) + minor_ver; |
||
193 | } |
||
194 | return -1; |
||
195 | } |
||
196 | |||
197 | // Demonstrates how to verify you're talking to a BlinkM
|
||
198 | // and that you know its address
|
||
199 | static int BlinkM_checkAddress(byte addr) |
||
200 | { |
||
201 | //Serial.print("Checking BlinkM address...");
|
||
202 | int b = BlinkM_getAddress(addr);
|
||
203 | if( b==-1 ) { |
||
204 | //Serial.println("No response, that's not good");
|
||
205 | return -1; // no response |
||
206 | } |
||
207 | //Serial.print("received addr: 0x");
|
||
208 | //Serial.print(b,HEX);
|
||
209 | if( b != addr )
|
||
210 | return 1; // error, addr mismatch |
||
211 | else
|
||
212 | return 0; // match, everything okay |
||
213 | } |
||
214 | |||
215 | // Sets the speed of fading between colors.
|
||
216 | // Higher numbers means faster fading, 255 == instantaneous fading
|
||
217 | static void BlinkM_setFadeSpeed(byte addr, byte fadespeed) |
||
218 | { |
||
219 | Wire.beginTransmission(addr); |
||
220 | Wire.send('f');
|
||
221 | Wire.send(fadespeed); |
||
222 | Wire.endTransmission(); |
||
223 | } |
||
224 | |||
225 | // Sets the light script playback time adjust
|
||
226 | // The timeadj argument is signed, and is an additive value to all
|
||
227 | // durations in a light script. Set to zero to turn off time adjust.
|
||
228 | static void BlinkM_setTimeAdj(byte addr, byte timeadj) |
||
229 | { |
||
230 | Wire.beginTransmission(addr); |
||
231 | Wire.send('t');
|
||
232 | Wire.send(timeadj); |
||
233 | Wire.endTransmission(); |
||
234 | } |
||
235 | |||
236 | // Fades to an RGB color
|
||
237 | static void BlinkM_fadeToRGB(byte addr, byte red, byte grn, byte blu) |
||
238 | { |
||
239 | Wire.beginTransmission(addr); |
||
240 | Wire.send('c');
|
||
241 | Wire.send(red); |
||
242 | Wire.send(grn); |
||
243 | Wire.send(blu); |
||
244 | Wire.endTransmission(); |
||
245 | } |
||
246 | |||
247 | // Fades to an HSB color
|
||
248 | static void BlinkM_fadeToHSB(byte addr, byte hue, byte saturation, byte brightness) |
||
249 | { |
||
250 | Wire.beginTransmission(addr); |
||
251 | Wire.send('h');
|
||
252 | Wire.send(hue); |
||
253 | Wire.send(saturation); |
||
254 | Wire.send(brightness); |
||
255 | Wire.endTransmission(); |
||
256 | } |
||
257 | |||
258 | // Sets an RGB color immediately
|
||
259 | static void BlinkM_setRGB(byte addr, byte red, byte grn, byte blu) |
||
260 | { |
||
261 | Wire.beginTransmission(addr); |
||
262 | Wire.send('n');
|
||
263 | Wire.send(red); |
||
264 | Wire.send(grn); |
||
265 | Wire.send(blu); |
||
266 | Wire.endTransmission(); |
||
267 | } |
||
268 | |||
269 | // Fades to a random RGB color
|
||
270 | static void BlinkM_fadeToRandomRGB(byte addr, byte rrnd, byte grnd, byte brnd) |
||
271 | { |
||
272 | Wire.beginTransmission(addr); |
||
273 | Wire.send('C');
|
||
274 | Wire.send(rrnd); |
||
275 | Wire.send(grnd); |
||
276 | Wire.send(brnd); |
||
277 | Wire.endTransmission(); |
||
278 | } |
||
279 | // Fades to a random HSB color
|
||
280 | static void BlinkM_fadeToRandomHSB(byte addr, byte hrnd, byte srnd, byte brnd) |
||
281 | { |
||
282 | Wire.beginTransmission(addr); |
||
283 | Wire.send('H');
|
||
284 | Wire.send(hrnd); |
||
285 | Wire.send(srnd); |
||
286 | Wire.send(brnd); |
||
287 | Wire.endTransmission(); |
||
288 | } |
||
289 | |||
290 | //
|
||
291 | static void BlinkM_getRGBColor(byte addr, byte* r, byte* g, byte* b) |
||
292 | { |
||
293 | Wire.beginTransmission(addr); |
||
294 | Wire.send('g');
|
||
295 | Wire.endTransmission(); |
||
296 | Wire.requestFrom(addr, (byte)3);
|
||
297 | if( Wire.available() ) {
|
||
298 | *r = Wire.receive(); |
||
299 | *g = Wire.receive(); |
||
300 | *b = Wire.receive(); |
||
301 | } |
||
302 | } |
||
303 | |||
304 | //
|
||
305 | static void BlinkM_playScript(byte addr, byte script_id, byte reps, byte pos) |
||
306 | { |
||
307 | Wire.beginTransmission(addr); |
||
308 | Wire.send('p');
|
||
309 | Wire.send(script_id); |
||
310 | Wire.send(reps); |
||
311 | Wire.send(pos); |
||
312 | Wire.endTransmission(); |
||
313 | } |
||
314 | |||
315 | //
|
||
316 | static void BlinkM_stopScript(byte addr) |
||
317 | { |
||
318 | Wire.beginTransmission(addr); |
||
319 | Wire.send('o');
|
||
320 | Wire.endTransmission(); |
||
321 | } |
||
322 | |||
323 | //
|
||
324 | static void BlinkM_setScriptLengthReps(byte addr, byte script_id, |
||
325 | byte len, byte reps) |
||
326 | { |
||
327 | Wire.beginTransmission(addr); |
||
328 | Wire.send('L');
|
||
329 | Wire.send(script_id); |
||
330 | Wire.send(len); |
||
331 | Wire.send(reps); |
||
332 | Wire.endTransmission(); |
||
333 | } |
||
334 | |||
335 | // Fill up script_line with data from a script line
|
||
336 | // currently only script_id = 0 works (eeprom script)
|
||
337 | static void BlinkM_readScriptLine(byte addr, byte script_id, |
||
338 | byte pos, blinkm_script_line* script_line) |
||
339 | { |
||
340 | Wire.beginTransmission(addr); |
||
341 | Wire.send('R');
|
||
342 | Wire.send(script_id); |
||
343 | Wire.send(pos); |
||
344 | Wire.endTransmission(); |
||
345 | Wire.requestFrom(addr, (byte)5);
|
||
346 | while( Wire.available() < 5 ) ; // FIXME: wait until we get 7 bytes |
||
347 | script_line->dur = Wire.receive(); |
||
348 | script_line->cmd[0] = Wire.receive();
|
||
349 | script_line->cmd[1] = Wire.receive();
|
||
350 | script_line->cmd[2] = Wire.receive();
|
||
351 | script_line->cmd[3] = Wire.receive();
|
||
352 | } |
||
353 | |||
354 | //
|
||
355 | static void BlinkM_writeScriptLine(byte addr, byte script_id, |
||
356 | byte pos, byte dur, |
||
357 | byte cmd, byte arg1, byte arg2, byte arg3) |
||
358 | { |
||
359 | #ifdef BLINKM_FUNCS_DEBUG
|
||
360 | Serial.print("writing line:"); Serial.print(pos,DEC);
|
||
361 | Serial.print(" with cmd:"); Serial.print(cmd);
|
||
362 | Serial.print(" arg1:"); Serial.println(arg1,HEX);
|
||
363 | #endif
|
||
364 | Wire.beginTransmission(addr); |
||
365 | Wire.send('W');
|
||
366 | Wire.send(script_id); |
||
367 | Wire.send(pos); |
||
368 | Wire.send(dur); |
||
369 | Wire.send(cmd); |
||
370 | Wire.send(arg1); |
||
371 | Wire.send(arg2); |
||
372 | Wire.send(arg3); |
||
373 | Wire.endTransmission(); |
||
374 | |||
375 | } |
||
376 | |||
377 | //
|
||
378 | static void BlinkM_writeScript(byte addr, byte script_id, |
||
379 | byte len, byte reps, |
||
380 | blinkm_script_line* lines) |
||
381 | { |
||
382 | #ifdef BLINKM_FUNCS_DEBUG
|
||
383 | Serial.print("writing script to addr:"); Serial.print(addr,DEC);
|
||
384 | Serial.print(", script_id:"); Serial.println(script_id,DEC);
|
||
385 | #endif
|
||
386 | for(byte i=0; i < len; i++) { |
||
387 | blinkm_script_line l = lines[i]; |
||
388 | BlinkM_writeScriptLine( addr, script_id, i, l.dur, |
||
389 | l.cmd[0], l.cmd[1], l.cmd[2], l.cmd[3]); |
||
390 | delay(20); // must wait for EEPROM to be programmed |
||
391 | } |
||
392 | BlinkM_setScriptLengthReps(addr, script_id, len, reps); |
||
393 | } |
||
394 | |||
395 | //
|
||
396 | static void BlinkM_setStartupParams(byte addr, byte mode, byte script_id, |
||
397 | byte reps, byte fadespeed, byte timeadj) |
||
398 | { |
||
399 | Wire.beginTransmission(addr); |
||
400 | Wire.send('B');
|
||
401 | Wire.send(mode); // default 0x01 == Play script
|
||
402 | Wire.send(script_id); // default 0x00 == script #0
|
||
403 | Wire.send(reps); // default 0x00 == repeat infinitely
|
||
404 | Wire.send(fadespeed); // default 0x08 == usually overridden by sketch
|
||
405 | Wire.send(timeadj); // default 0x00 == sometimes overridden by sketch
|
||
406 | Wire.endTransmission(); |
||
407 | } |
||
408 | |||
409 | |||
410 | // Gets digital inputs of the BlinkM
|
||
411 | // returns -1 on failure
|
||
412 | static int BlinkM_getInputsO(byte addr) |
||
413 | { |
||
414 | Wire.beginTransmission(addr); |
||
415 | Wire.send('i');
|
||
416 | Wire.endTransmission(); |
||
417 | Wire.requestFrom(addr, (byte)1);
|
||
418 | if( Wire.available() ) {
|
||
419 | byte b = Wire.receive(); |
||
420 | return b;
|
||
421 | } |
||
422 | return -1; |
||
423 | } |
||
424 | |||
425 | // Gets digital inputs of the BlinkM
|
||
426 | // stores them in passed in array
|
||
427 | // returns -1 on failure
|
||
428 | static int BlinkM_getInputs(byte addr, byte inputs[]) |
||
429 | { |
||
430 | Wire.beginTransmission(addr); |
||
431 | Wire.send('i');
|
||
432 | Wire.endTransmission(); |
||
433 | Wire.requestFrom(addr, (byte)4);
|
||
434 | while( Wire.available() < 4 ) ; // FIXME: wait until we get 4 bytes |
||
435 | |||
436 | inputs[0] = Wire.receive();
|
||
437 | inputs[1] = Wire.receive();
|
||
438 | inputs[2] = Wire.receive();
|
||
439 | inputs[3] = Wire.receive();
|
||
440 | |||
441 | return 0; |
||
442 | } |