My favorites | Sign in
Project Home Downloads Wiki Issues Source
Checkout   Browse   Changes    
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
/*
* arduino serial-i2c-gateway, Copyright (C) 2010-2011 michael vogt <michu@neophob.com>
*
* based on
* -blinkm firmware by thingM
* -"daft punk" firmware by Scott C / ThreeFN
*
* libraries to patch:
* Wire:
* utility/twi.h: #define TWI_FREQ 400000L (was 100000L)
* #define TWI_BUFFER_LENGTH 98 (was 32)
* wire.h: #define BUFFER_LENGTH 98 (was 32)
*
* This file is part of neorainbowduino.
*
* neorainbowduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* neorainbowduino is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/

#include <Wire.h>
#include "WProgram.h"

extern "C" {
#include "utility/twi.h" // from Wire library, so we can do bus scanning
}


//to draw a frame we need arround 20ms to send an image. the serial baudrate is
//NOT the bottleneck.
#define BAUD_RATE 115200

#define CLEARCOL 51 //00110011

//some magic numberes
#define CMD_START_BYTE 0x01
#define CMD_SENDFRAME 0x03
#define CMD_PING 0x04
#define CMD_INIT_RAINBOWDUINO 0x05
#define CMD_SCAN_I2C_BUS 0x06

//8ms is the minimum!
#define SERIAL_WAIT_TIME_IN_MS 8

//I2C definitions
#define START_OF_DATA 0x10
#define END_OF_DATA 0x20

//Static start+end address for i2x scan
#define START_I2C_SCAN 1
#define END_I2C_SCAN 101

//frame size for specific color resolution
#define COLOR_4BIT_FRAME_SIZE 96
#define COLOR_5BIT_FRAME_SIZE 128

#define SERIAL_HEADER_SIZE 5

//this should match RX_BUFFER_SIZE from HardwareSerial.cpp
#define SERIAL_RX_BUFFER_SIZE 128
byte serInStr[SERIAL_RX_BUFFER_SIZE]; // array that will hold the serial input string

//counter for 2000 frames
//http://www.ftdichip.com/Support/Documents/AppNotes/AN232B-04_DataLatencyFlow.pdf
//there is a 16ms delay until the buffer is full, here are some measurements
//time is round trip time from/to java
//size errorrate frames>35ms time for 2000frames time/frame time/frame worstcase
//5 -> rate: 0.0, long: 156, totalTime: 44250 22.13ms
//8 -> rate: 5.894106, long: 38, totalTime: 41184 20.59ms 21.83ms
//16 -> rate: 7.092907, long: 4, totalTime: 40155 20.07ms 21.48ms
//32 -> rate: 6.943056, long: 5, totalTime: 39939 19.97ms 21.36ms
//62 -> rate: 22.97702, long: 7, totalTime: 33739 16.89ms 20.58ms
//64 -> rate: 24.22577, long: 3, totalTime: 33685 16.84ms 20.89ms
//-> I use 16b - not the fastest variant but more accurate

#define SERIALBUFFERSIZE 16
byte serialResonse[SERIALBUFFERSIZE];

byte g_errorCounter;

//send status back to library
static void sendAck() {
serialResonse[0] = 'A';
serialResonse[1] = 'K';
serialResonse[2] = Serial.available();
serialResonse[3] = g_errorCounter;
Serial.write(serialResonse, 4);

//Clear bufer
// Serial.flush();
}


//send an white image to the target rainbowduino
//contains red led's which describe its i2c addr
byte send_initial_image(byte i2caddr) {
//clear whole buffer
memset(serInStr, CLEARCOL, COLOR_4BIT_FRAME_SIZE);

//draw i2c addr as led pixels
float tail = i2caddr/2.0f;
byte tail2 = (byte)(tail);
boolean useTail = (tail-(byte)(tail))!=0;

//buffer layout: 32b RED, 32b GREEN, 32b BLUE
byte ofs=0;
for (byte i=0; i<tail2; i++) {
serInStr[ofs++]=255;
}
if (useTail) {
serInStr[ofs++]=243;
}

return BlinkM_sendBuffer(i2caddr, serInStr, COLOR_4BIT_FRAME_SIZE);
}

// ripped from http://todbot.com/arduino/sketches/I2CScanner/I2CScanner.pde
// Scan the I2C bus between addresses from_addr and to_addr.
// On each address, call the callback function with the address and result.
// If result==0, address was found, otherwise, address wasn't found
// (can use result to potentially get other status on the I2C bus, see twi.c)
// Assumes Wire.begin() has already been called
// HINT: maximal 14 devices can be scanned!
void scanI2CBus() {
memset(serialResonse, 255, SERIALBUFFERSIZE);
serialResonse[0] = CMD_START_BYTE;
serialResonse[1] = CMD_SCAN_I2C_BUS;

byte rc,i=2;
byte data = 0; // not used, just an address to feed to twi_writeTo()
for (byte addr = START_I2C_SCAN; addr <= END_I2C_SCAN; addr++) {
//rc 0 = success
digitalWrite(13, HIGH);
rc = twi_writeTo(addr, &data, 0, 1);
digitalWrite(13, LOW);
if (rc==0) {
serialResonse[i]=addr;
if (i<SERIALBUFFERSIZE) i++;
}
delayMicroseconds(64);
}
Serial.write(serialResonse, SERIALBUFFERSIZE);
memset(serialResonse, 0, SERIALBUFFERSIZE);
}


void setup() {
Wire.begin(1); // join i2c bus (address optional for master)

pinMode(13, OUTPUT);
memset(serialResonse, 0, SERIALBUFFERSIZE);

//im your slave and wait for your commands, master!
Serial.begin(BAUD_RATE); //Setup high speed Serial
Serial.flush();
}


void loop() {
//read the serial port and create a string out of what you read
g_errorCounter=0;

digitalWrite(13, LOW);
// see if we got a proper command string yet
if (readCommand(serInStr) == 0) {
//no valid data found
//sleep for 250us
delayMicroseconds(500);
return;
}

digitalWrite(13, HIGH);

//i2c addres of device
byte addr = serInStr[1];
//how many bytes we're sending
byte sendlen = serInStr[2];
//what kind of command we send
byte type = serInStr[3];
//parameter
byte* cmd = serInStr+5;

switch (type) {
case CMD_SENDFRAME:
//the size of an image must be exactly 96 bytes (12bit) or 128 bytes (15bit)
if (sendlen==COLOR_4BIT_FRAME_SIZE || sendlen == COLOR_5BIT_FRAME_SIZE) {
g_errorCounter = BlinkM_sendBuffer(addr, cmd, sendlen);
} else {
g_errorCounter=100;
}
break;

case CMD_PING:
//just send the ack!
break;
case CMD_INIT_RAINBOWDUINO:
//send initial image to rainbowduino
g_errorCounter = send_initial_image(addr);
break;
case CMD_SCAN_I2C_BUS:
scanI2CBus();
break;
default:
//invalid command
g_errorCounter=130;
break;
}

//send ack to library - command processed
sendAck();

}



//send data via I2C to a client
static byte BlinkM_sendBuffer(byte addr, byte* cmd, byte sendlen) {
Wire.beginTransmission(addr);
Wire.send(START_OF_DATA);
Wire.send(cmd, sendlen);
Wire.send(END_OF_DATA);
return Wire.endTransmission();
}


//read a string from the serial and store it in an array
//you must supply the str array variable
//returns number of bytes read, or zero if fail
/* example ping command:
cmdfull[0] = START_OF_CMD (marker);
cmdfull[1] = addr;
cmdfull[2] = 0x01;
cmdfull[3] = CMD_PING;
cmdfull[4] = START_OF_DATA (marker);
cmdfull[5] = 0x02;
cmdfull[6] = END_OF_DATA (marker);
*/

byte readCommand(byte *str) {
byte b,i,sendlen;

//wait until we get a CMD_START_BYTE or queue is empty
i=0;
while (Serial.available()>0 && i==0) {
b = Serial.read();
if (b == CMD_START_BYTE) {
i=1;
}
}

if (i==0) {
//failed to get data
g_errorCounter=101;
return 0;
}

//read header
i = SERIAL_WAIT_TIME_IN_MS;
while (Serial.available() < SERIAL_HEADER_SIZE-1) { // wait for the rest
delay(1);
if (i-- == 0) {
g_errorCounter=102;
return 0; // get out if takes too long
}
}
for (i=1; i<SERIAL_HEADER_SIZE; i++) {
str[i] = Serial.read(); // fill it up
}

// --- START HEADER CHECK
//check if data is correct, 0x10 = START_OF_DATA
if (str[4] != START_OF_DATA) {
g_errorCounter=104;
return 0;
}

//check sendlen, its possible that sendlen is 0!
sendlen = str[2];
// --- END HEADER CHECK


//read data
i = SERIAL_WAIT_TIME_IN_MS;
// wait for the final part, +1 for END_OF_DATA
while (Serial.available() < sendlen+1) {
delay(1);
if( i-- == 0 ) {
g_errorCounter=105;
return 0;
}
}

for (i=SERIAL_HEADER_SIZE; i<SERIAL_HEADER_SIZE+sendlen+1; i++) {
str[i] = Serial.read(); // fill it up
}

//check if data is correct, 0x20 = END_OF_DATA
if (str[SERIAL_HEADER_SIZE+sendlen] != END_OF_DATA) {
g_errorCounter=106;
return 0;
}

//return data size (without meta data)
return sendlen;
}


Change log

r216 by mi...@neophob.com on Jan 17, 2011   Diff
some 15bit adjustments
Go to: 
Project members, sign in to write a code review

Older revisions

r179 by michudroid on Jan 7, 2011   Diff
replace funny ints with nicre byte's
r153 by mi...@neophob.com on Nov 25, 2010   Diff
minor improvments
r145 by mi...@neophob.com on Nov 22, 2010   Diff
update scanner, add i2c adr1 to i2c
master
All revisions of this file

File info

Size: 8712 bytes, 318 lines
Powered by Google Project Hosting