root / quad2 / arduino / src / ros_lib / examples / BlinkM / BlinkM_funcs.h @ c1426757
History | View | Annotate | Download (11.4 KB)
1 |
/*
|
---|---|
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 |
} |