BlinkM_funcs.h
Go to the documentation of this file.
00001 /*
00002  * BlinkM_funcs.h -- Arduino 'library' to control BlinkM
00003  * --------------
00004  *
00005  *
00006  * Note: original version of this file lives with the BlinkMTester sketch
00007  *
00008  * Note: all the functions are declared 'static' because 
00009  *       it saves about 1.5 kbyte in code space in final compiled sketch.  
00010  *       A C++ library of this costs a 1kB more.
00011  *
00012  * 2007-8, Tod E. Kurt, ThingM, http://thingm.com/
00013  *
00014  * version: 20081101
00015  *
00016  * history:
00017  *  20080101 - initial release
00018  *  20080203 - added setStartupParam(), bugfix receiveBytes() from Dan Julio
00019  *  20081101 - fixed to work with Arduino-0012, added MaxM commands,
00020  *             added test script read/write functions, cleaned up some functions
00021  *  20090121 - added I2C bus scan functions, has dependencies on private 
00022  *             functions inside Wire library, so might break in the future
00023  *  20100420 - added BlinkM_startPower and _stopPower
00024  *
00025  */
00026 
00027 #include "WProgram.h"
00028 #include "wiring.h"
00029 #include <Wire.h>
00030 
00031 extern "C" { 
00032 #include "utility/twi.h"  // from Wire library, so we can do bus scanning
00033 }
00034 
00035 
00036 // format of light script lines: duration, command, arg1,arg2,arg3
00037 typedef struct _blinkm_script_line {
00038   uint8_t dur;
00039   uint8_t cmd[4];    // cmd,arg1,arg2,arg3
00040 } blinkm_script_line;
00041 
00042 
00043 // Call this first (when powering BlinkM from a power supply)
00044 static void BlinkM_begin()
00045 {
00046   Wire.begin();                // join i2c bus (address optional for master)
00047 }
00048 
00049 /*
00050  * actually can't do this either, because twi_init() has THREE callocs in it too
00051  *
00052 static void BlinkM_reset()
00053 {
00054   twi_init();  // can't just call Wire.begin() again because of calloc()s there
00055 }
00056 */
00057 
00058 //
00059 // each call to twi_writeTo() should return 0 if device is there
00060 // or other value (usually 2) if nothing is at that address
00061 // 
00062 static void BlinkM_scanI2CBus(byte from, byte to, 
00063                               void(*callback)(byte add, byte result) ) 
00064 {
00065   byte rc;
00066   byte data = 0; // not used, just an address to feed to twi_writeTo()
00067   for( byte addr = from; addr <= to; addr++ ) {
00068     rc = twi_writeTo(addr, &data, 0, 1);
00069     callback( addr, rc );
00070   }
00071 }
00072 
00073 //
00074 //
00075 static int8_t BlinkM_findFirstI2CDevice() 
00076 {
00077   byte rc;
00078   byte data = 0; // not used, just an address to feed to twi_writeTo()
00079   for( byte addr=1; addr < 120; addr++ ) {  // only scan addrs 1-120
00080     rc = twi_writeTo(addr, &data, 0, 1);
00081     if( rc == 0 ) return addr; // found an address
00082   }
00083   return -1; // no device found in range given
00084 }
00085 
00086 // FIXME: make this more Arduino-like
00087 static void BlinkM_startPowerWithPins(byte pwrpin, byte gndpin)
00088 {
00089   DDRC |= _BV(pwrpin) | _BV(gndpin);  // make outputs
00090   PORTC &=~ _BV(gndpin);
00091   PORTC |=  _BV(pwrpin);
00092 }
00093 
00094 // FIXME: make this more Arduino-like
00095 static void BlinkM_stopPowerWithPins(byte pwrpin, byte gndpin)
00096 {
00097   DDRC &=~ (_BV(pwrpin) | _BV(gndpin));
00098 }
00099 
00100 //
00101 static void BlinkM_startPower()
00102 {
00103   BlinkM_startPowerWithPins( PORTC3, PORTC2 );
00104 }
00105 
00106 //
00107 static void BlinkM_stopPower()
00108 {
00109   BlinkM_stopPowerWithPins( PORTC3, PORTC2 );
00110 }
00111 
00112 // General version of BlinkM_beginWithPower().
00113 // Call this first when BlinkM is plugged directly into Arduino
00114 static void BlinkM_beginWithPowerPins(byte pwrpin, byte gndpin)
00115 {
00116   BlinkM_startPowerWithPins(pwrpin,gndpin);
00117   delay(100);  // wait for things to stabilize
00118   Wire.begin();
00119 }
00120 
00121 // Call this first when BlinkM is plugged directly into Arduino
00122 // FIXME: make this more Arduino-like
00123 static void BlinkM_beginWithPower()
00124 {
00125   BlinkM_beginWithPowerPins( PORTC3, PORTC2 );
00126 }
00127 
00128 // sends a generic command
00129 static void BlinkM_sendCmd(byte addr, byte* cmd, int cmdlen)
00130 {
00131   Wire.beginTransmission(addr);
00132   for( byte i=0; i<cmdlen; i++) 
00133     Wire.send(cmd[i]);
00134   Wire.endTransmission();
00135 }
00136 
00137 // receives generic data
00138 // returns 0 on success, and -1 if no data available
00139 // note: responsiblity of caller to know how many bytes to expect
00140 static int BlinkM_receiveBytes(byte addr, byte* resp, byte len)
00141 {
00142   Wire.requestFrom(addr, len);
00143   if( Wire.available() ) {
00144     for( int i=0; i<len; i++) 
00145       resp[i] = Wire.receive();
00146     return 0;
00147   }
00148   return -1;
00149 }
00150 
00151 // Sets the I2C address of the BlinkM.  
00152 // Uses "general call" broadcast address
00153 static void BlinkM_setAddress(byte newaddress)
00154 {
00155   Wire.beginTransmission(0x00);  // general call (broadcast address)
00156   Wire.send('A');
00157   Wire.send(newaddress);
00158   Wire.send(0xD0);
00159   Wire.send(0x0D);  // dood!
00160   Wire.send(newaddress);
00161   Wire.endTransmission();
00162   delay(50); // just in case
00163 }
00164 
00165 
00166 // Gets the I2C address of the BlinKM
00167 // Kind of redundant when sent to a specific address
00168 // but uses to verify BlinkM communication
00169 static int BlinkM_getAddress(byte addr)
00170 {
00171   Wire.beginTransmission(addr);
00172   Wire.send('a');
00173   Wire.endTransmission();
00174   Wire.requestFrom(addr, (byte)1);  // general call
00175   if( Wire.available() ) {
00176     byte b = Wire.receive();
00177     return b;
00178   }
00179   return -1;
00180 }
00181 
00182 // Gets the BlinkM firmware version
00183 static int BlinkM_getVersion(byte addr)
00184 {
00185   Wire.beginTransmission(addr);
00186   Wire.send('Z');
00187   Wire.endTransmission();
00188   Wire.requestFrom(addr, (byte)2);
00189   if( Wire.available() ) {
00190     byte major_ver = Wire.receive();
00191     byte minor_ver = Wire.receive();
00192     return (major_ver<<8) + minor_ver;
00193   }
00194   return -1;
00195 }
00196 
00197 // Demonstrates how to verify you're talking to a BlinkM 
00198 // and that you know its address
00199 static int BlinkM_checkAddress(byte addr)
00200 {
00201   //Serial.print("Checking BlinkM address...");
00202   int b = BlinkM_getAddress(addr);
00203   if( b==-1 ) {
00204     //Serial.println("No response, that's not good");
00205     return -1;  // no response
00206   } 
00207   //Serial.print("received addr: 0x");
00208   //Serial.print(b,HEX);
00209   if( b != addr )
00210     return 1; // error, addr mismatch 
00211   else 
00212     return 0; // match, everything okay
00213 }
00214 
00215 // Sets the speed of fading between colors.  
00216 // Higher numbers means faster fading, 255 == instantaneous fading
00217 static void BlinkM_setFadeSpeed(byte addr, byte fadespeed)
00218 {
00219   Wire.beginTransmission(addr);
00220   Wire.send('f');
00221   Wire.send(fadespeed);
00222   Wire.endTransmission();  
00223 }
00224 
00225 // Sets the light script playback time adjust
00226 // The timeadj argument is signed, and is an additive value to all
00227 // durations in a light script. Set to zero to turn off time adjust.
00228 static void BlinkM_setTimeAdj(byte addr, byte timeadj)
00229 {
00230   Wire.beginTransmission(addr);
00231   Wire.send('t');
00232   Wire.send(timeadj);
00233   Wire.endTransmission();  
00234 }
00235 
00236 // Fades to an RGB color
00237 static void BlinkM_fadeToRGB(byte addr, byte red, byte grn, byte blu)
00238 {
00239   Wire.beginTransmission(addr);
00240   Wire.send('c');
00241   Wire.send(red);
00242   Wire.send(grn);
00243   Wire.send(blu);
00244   Wire.endTransmission();
00245 }
00246 
00247 // Fades to an HSB color
00248 static void BlinkM_fadeToHSB(byte addr, byte hue, byte saturation, byte brightness)
00249 {
00250   Wire.beginTransmission(addr);
00251   Wire.send('h');
00252   Wire.send(hue);
00253   Wire.send(saturation);
00254   Wire.send(brightness);
00255   Wire.endTransmission();
00256 }
00257 
00258 // Sets an RGB color immediately
00259 static void BlinkM_setRGB(byte addr, byte red, byte grn, byte blu)
00260 {
00261   Wire.beginTransmission(addr);
00262   Wire.send('n');
00263   Wire.send(red);
00264   Wire.send(grn);
00265   Wire.send(blu);
00266   Wire.endTransmission();
00267 }
00268 
00269 // Fades to a random RGB color
00270 static void BlinkM_fadeToRandomRGB(byte addr, byte rrnd, byte grnd, byte brnd)
00271 {
00272   Wire.beginTransmission(addr);
00273   Wire.send('C');
00274   Wire.send(rrnd);
00275   Wire.send(grnd);
00276   Wire.send(brnd);
00277   Wire.endTransmission();
00278 }
00279 // Fades to a random HSB color
00280 static void BlinkM_fadeToRandomHSB(byte addr, byte hrnd, byte srnd, byte brnd)
00281 {
00282   Wire.beginTransmission(addr);
00283   Wire.send('H');
00284   Wire.send(hrnd);
00285   Wire.send(srnd);
00286   Wire.send(brnd);
00287   Wire.endTransmission();
00288 }
00289 
00290 //
00291 static void BlinkM_getRGBColor(byte addr, byte* r, byte* g, byte* b)
00292 {
00293   Wire.beginTransmission(addr);
00294   Wire.send('g');
00295   Wire.endTransmission();
00296   Wire.requestFrom(addr, (byte)3);
00297   if( Wire.available() ) {
00298     *r = Wire.receive();
00299     *g = Wire.receive();
00300     *b = Wire.receive();
00301   }
00302 }
00303 
00304 //
00305 static void BlinkM_playScript(byte addr, byte script_id, byte reps, byte pos)
00306 {
00307   Wire.beginTransmission(addr);
00308   Wire.send('p');
00309   Wire.send(script_id);
00310   Wire.send(reps);
00311   Wire.send(pos);
00312   Wire.endTransmission();
00313 }
00314 
00315 //
00316 static void BlinkM_stopScript(byte addr)
00317 {
00318   Wire.beginTransmission(addr);
00319   Wire.send('o');
00320   Wire.endTransmission();
00321 }
00322 
00323 //
00324 static void BlinkM_setScriptLengthReps(byte addr, byte script_id, 
00325                                        byte len, byte reps)
00326 {
00327   Wire.beginTransmission(addr);
00328   Wire.send('L');
00329   Wire.send(script_id);
00330   Wire.send(len);
00331   Wire.send(reps);
00332   Wire.endTransmission();
00333 }
00334 
00335 // Fill up script_line with data from a script line
00336 // currently only script_id = 0 works (eeprom script)
00337 static void BlinkM_readScriptLine(byte addr, byte script_id, 
00338                                   byte pos, blinkm_script_line* script_line)
00339 {
00340   Wire.beginTransmission(addr);
00341   Wire.send('R');
00342   Wire.send(script_id);
00343   Wire.send(pos);
00344   Wire.endTransmission();
00345   Wire.requestFrom(addr, (byte)5);
00346   while( Wire.available() < 5 ) ; // FIXME: wait until we get 7 bytes
00347   script_line->dur    = Wire.receive();
00348   script_line->cmd[0] = Wire.receive();
00349   script_line->cmd[1] = Wire.receive();
00350   script_line->cmd[2] = Wire.receive();
00351   script_line->cmd[3] = Wire.receive();
00352 }
00353 
00354 //
00355 static void BlinkM_writeScriptLine(byte addr, byte script_id, 
00356                                    byte pos, byte dur,
00357                                    byte cmd, byte arg1, byte arg2, byte arg3)
00358 {
00359 #ifdef BLINKM_FUNCS_DEBUG
00360   Serial.print("writing line:");  Serial.print(pos,DEC);
00361   Serial.print(" with cmd:"); Serial.print(cmd); 
00362   Serial.print(" arg1:"); Serial.println(arg1,HEX);
00363 #endif
00364   Wire.beginTransmission(addr);
00365   Wire.send('W');
00366   Wire.send(script_id);
00367   Wire.send(pos);
00368   Wire.send(dur);
00369   Wire.send(cmd);
00370   Wire.send(arg1);
00371   Wire.send(arg2);
00372   Wire.send(arg3);
00373   Wire.endTransmission();
00374 
00375 }
00376 
00377 //
00378 static void BlinkM_writeScript(byte addr, byte script_id, 
00379                                byte len, byte reps,
00380                                blinkm_script_line* lines)
00381 {
00382 #ifdef BLINKM_FUNCS_DEBUG
00383   Serial.print("writing script to addr:"); Serial.print(addr,DEC);
00384   Serial.print(", script_id:"); Serial.println(script_id,DEC);
00385 #endif
00386   for(byte i=0; i < len; i++) {
00387     blinkm_script_line l = lines[i];
00388     BlinkM_writeScriptLine( addr, script_id, i, l.dur,
00389                             l.cmd[0], l.cmd[1], l.cmd[2], l.cmd[3]);
00390     delay(20); // must wait for EEPROM to be programmed
00391   }
00392   BlinkM_setScriptLengthReps(addr, script_id, len, reps);
00393 }
00394 
00395 //
00396 static void BlinkM_setStartupParams(byte addr, byte mode, byte script_id,
00397                                     byte reps, byte fadespeed, byte timeadj)
00398 {
00399   Wire.beginTransmission(addr);
00400   Wire.send('B');
00401   Wire.send(mode);             // default 0x01 == Play script
00402   Wire.send(script_id);        // default 0x00 == script #0
00403   Wire.send(reps);             // default 0x00 == repeat infinitely
00404   Wire.send(fadespeed);        // default 0x08 == usually overridden by sketch 
00405   Wire.send(timeadj);          // default 0x00 == sometimes overridden by sketch
00406   Wire.endTransmission();
00407 } 
00408 
00409 
00410 // Gets digital inputs of the BlinkM
00411 // returns -1 on failure
00412 static int BlinkM_getInputsO(byte addr)
00413 {
00414   Wire.beginTransmission(addr);
00415   Wire.send('i');
00416   Wire.endTransmission();
00417   Wire.requestFrom(addr, (byte)1);
00418   if( Wire.available() ) {
00419     byte b = Wire.receive();
00420     return b; 
00421   }
00422   return -1;
00423 }
00424 
00425 // Gets digital inputs of the BlinkM
00426 // stores them in passed in array
00427 // returns -1 on failure
00428 static int BlinkM_getInputs(byte addr, byte inputs[])
00429 {
00430   Wire.beginTransmission(addr);
00431   Wire.send('i');
00432   Wire.endTransmission();
00433   Wire.requestFrom(addr, (byte)4);
00434   while( Wire.available() < 4 ) ; // FIXME: wait until we get 4 bytes
00435     
00436   inputs[0] = Wire.receive();
00437   inputs[1] = Wire.receive();
00438   inputs[2] = Wire.receive();
00439   inputs[3] = Wire.receive();
00440 
00441   return 0;
00442 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines


traxbot_robot
Author(s): André Gonçalves Araújo
autogenerated on Fri Feb 1 2013 13:21:12