Statistics
| Branch: | Revision:

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
}