new displayclient for arduino with ethernet shield and neopixels

format for central config file describing dynamically the setup
moved some files around and adapted runitall / readme for the new layout
master
Gunstick 2015-02-13 22:53:04 +01:00
parent 4d02195fd6
commit f4c71012be
72 changed files with 353 additions and 6 deletions

View File

@ -12,12 +12,12 @@ The system is set up of various parts. See frameserver.png
Latest setup is:
* displayclienthtml/ws_udp.js
* displayclient/html/ws_udp.js
-----------------------------
A nodjs server => $ node displayclienthtml/ws_udp.js
A nodjs server => $ node displayclient/html/ws_udp.js
This listens for UDP packets to show on a virtual building
This server creates a webserver where a browser can connect to see a simulation
of the building. => $ firefox/chromium displayclienthtml/visionneuse.html
of the building. => $ firefox/chromium displayclient/html/visionneuse.html
* frameserver
-------------

View File

@ -0,0 +1,15 @@
This recieves a syn2lighs packet via UDP and displays it on an neopixel array
The arduino does the conversion from normal x/y coordinates to physical pixels.
This means thet the physical layout should not be of concern for the
sender of the UDP packet. Top left is always 0,0
The neopixel array can be set up several ways:
Feed in is in one of the 4 corners
From there it goes vertically in zigzag to the opposing side.
e.g. feed in is top left corner
Left down, then 1 right, up gain, 1 right etc...
Alternatively it can also go horizontally in zigzag to the opposite side
Enhancement: have dip switches to configure max X/Y and layout

View File

@ -0,0 +1,109 @@
/* syndilights display with arduino and neopixel */
/* !!!!! this does NOT YET use the syndilights format !!!! */
/* Based on http://arduino.cc/en/pmwiki.php?n=Reference/EthernetUDPRead */
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <EEPROM.h>
#include <Adafruit_NeoPixel.h> // https://learn.adafruit.com/adafruit-neopixel-uberguide/arduino-library
// Which pin on the Arduino is connected to the NeoPixels?
#define PIN 6
// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS 25
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
uint16_t brightness = 10;
// the mac will be filled out by serial number, stored as ascii hex in the eeprom 6 first bytes
byte mac[] = { '2', 'S', 'L', 0, 0, 0 }; // 2(to) S-yn2-L-ights (2 because unicast + locally administered)
// IPAddress ip(10, 2, 113, 51); // not using ip, will use DHCP
unsigned int localPort = 8888; // local port to listen on
// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,
byte tomac[4];
void setup() {
Serial.begin(9600);
// you need to store into the EEPROM in the first 6 bytes an ascii version of the serial number.
// read that in and use it for the mac
int j=0;
for(int i=0;i<7;i+=2) {
int v;
v=(int)(EEPROM.read(i)-'0');
if (v>9) {v-=7;} // adjust for A-F are 7 chars later in ascii table
tomac[j]=v<<4;
v=(int)(EEPROM.read(i+1)-'0');
if (v>9) {v-=7;} // adjust for A-F are 7 chars later in ascii table
tomac[j++]+=v;
}
mac[3]=tomac[0];
mac[4]=tomac[1];
mac[5]=tomac[2];
// start the Ethernet and UDP:
// Ethernet.begin(mac,ip);
Ethernet.begin(mac); // use DHCP. This eats 2732 of sketch size
Udp.begin(localPort);
Serial.println("---");
for (byte thisByte = 0; thisByte < 4; thisByte++) {
// print the value of each byte of the IP address:
Serial.print(Ethernet.localIP()[thisByte], DEC);
Serial.print(".");
}
Serial.println();
pixels.begin();
}
void loop() {
int packetSize = Udp.parsePacket();
if(packetSize)
{
drawCommand();
}
}
uint16_t readSubPixelValue(byte in){
char s[2];
pinMode(13, OUTPUT);
s[0] = (char)in;
//if (s[0] == -1) s[0]='0';
s[1] = 0;
uint16_t r = (uint16_t)strtoul(s,NULL,16);
return r;
}
void drawCommand() {
Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);
for(uint16_t i = 0; i<NUMPIXELS; i++){
byte r=(byte)packetBuffer[i*3];
byte g=(byte)packetBuffer[i*3+1];
byte b=(byte)packetBuffer[i*3+2];
pixels.setPixelColor(indirect(i), pixels.Color(readSubPixelValue(r), readSubPixelValue(g), readSubPixelValue(b)));
}
pixels.show();
}
#define ROWS 5
uint16_t indirect(uint16_t in) {
if((in/ROWS)%2) {
uint16_t t;
t=in/ROWS;
t*=ROWS;
t+=ROWS-(in%ROWS)-1;
return t;
} else {
return in;
}
}

View File

@ -0,0 +1,183 @@
// WRITES TO SERIAL EEPROM Arduino
//
// Do this only once on an Arduino,
// Write the Serial of the Arduino in the
// First 6 bytes of the EEPROM
// you find the serial by connecting to usb in /dev/serial/by-id
// usb-Arduino__www.arduino.cc__0042_7533030393435171B1A0-if00
// take the last 6 positions 71B1A0
#include <EEPROM.h>
char sID[7]="71B1A0"; // change this to the serial number on the board
#define EEPROM_MIN_ADDR 0
#define EEPROM_MAX_ADDR 511
//
// Returns true if the address is between the
// minimum and maximum allowed values,
// false otherwise.
//
// This function is used by the other, higher-level functions
// to prevent bugs and runtime errors due to invalid addresses.
//
boolean eeprom_is_addr_ok(int addr) {
return ((addr >= EEPROM_MIN_ADDR) && (addr <= EEPROM_MAX_ADDR));
}
boolean eeprom_write_bytes(int startAddr, const byte* array, int numBytes) {
// counter
int i;
// both first byte and last byte addresses must fall within
// the allowed range
if (!eeprom_is_addr_ok(startAddr) || !eeprom_is_addr_ok(startAddr + numBytes)) {
return false;
}
for (i = 0; i < numBytes; i++) {
EEPROM.write(startAddr + i, array[i]);
}
return true;
}
//
// Writes a string starting at the specified address.
// Returns true if the whole string is successfully written.
// Returns false if the address of one or more bytes
// fall outside the allowed range.
// If false is returned, nothing gets written to the eeprom.
//
boolean eeprom_write_string(int addr, const char* string) {
// actual number of bytes to be written
int numBytes;
// we'll need to write the string contents
// plus the string terminator byte (0x00)
numBytes = strlen(string) + 1;
return eeprom_write_bytes(addr, (const byte*)string, numBytes);
}
//
// Reads the specified number of bytes from the specified address into the provided buffer.
// Returns true if all the bytes are successfully read.
// Returns false if the star or end addresses aren't between
// the minimum and maximum allowed values.
// When returning false, the provided array is untouched.
//
// Note: the caller must ensure that array[] has enough space
// to store at most numBytes bytes.
//
boolean eeprom_read_bytes(int startAddr, byte array[], int numBytes) {
int i;
// both first byte and last byte addresses must fall within
// the allowed range
if (!eeprom_is_addr_ok(startAddr) || !eeprom_is_addr_ok(startAddr + numBytes)) {
return false;
}
for (i = 0; i < numBytes; i++) {
array[i] = EEPROM.read(startAddr + i);
}
return true;
}
//
// Reads a string starting from the specified address.
// Returns true if at least one byte (even only the
// string terminator one) is read.
// Returns false if the start address falls outside
// or declare buffer size os zero.
// the allowed range.
// The reading might stop for several reasons:
// - no more space in the provided buffer
// - last eeprom address reached
// - string terminator byte (0x00) encountered.
// The last condition is what should normally occur.
//
boolean eeprom_read_string(int addr, char* buffer, int bufSize) {
// byte read from eeprom
byte ch;
// number of bytes read so far
int bytesRead;
// check start address
if (!eeprom_is_addr_ok(addr)) {
return false;
}
// how can we store bytes in an empty buffer ?
if (bufSize == 0) {
return false;
}
// is there is room for the string terminator only,
// no reason to go further
if (bufSize == 1) {
buffer[0] = 0;
return true;
}
// initialize byte counter
bytesRead = 0;
// read next byte from eeprom
ch = EEPROM.read(addr + bytesRead);
// store it into the user buffer
buffer[bytesRead] = ch;
// increment byte counter
bytesRead++;
// stop conditions:
// - the character just read is the string terminator one (0x00)
// - we have filled the user buffer
// - we have reached the last eeprom address
while ( (ch != 0x00) && (bytesRead < bufSize) && ((addr + bytesRead) <= EEPROM_MAX_ADDR) ) {
// if no stop condition is met, read the next byte from eeprom
ch = EEPROM.read(addr + bytesRead);
// store it into the user buffer
buffer[bytesRead] = ch;
// increment byte counter
bytesRead++;
}
// make sure the user buffer has a string terminator
// (0x00) as its last byte
if ((ch != 0x00) && (bytesRead >= 1)) {
buffer[bytesRead - 1] = 0;
}
return true;
}
char buf[7];
void setup()
{
Serial.begin(9600);
eeprom_read_string(0,buf, 7); // read from addr 0 into buf 7 chars
if(strncmp(buf,sID,6) != 0) { // only write if not yet written
eeprom_write_string(0, sID); // write to adress 0 the ID
}
}
void loop () {
Serial.println("---");
Serial.print("old value: ");
Serial.println(buf);
Serial.print("new value: ");
Serial.println(sID);
if(strncmp(buf,sID,6) != 0) {
Serial.println("different");
} else {
Serial.println("same");
}
}

View File

Before

Width:  |  Height:  |  Size: 267 KiB

After

Width:  |  Height:  |  Size: 267 KiB

View File

Before

Width:  |  Height:  |  Size: 181 KiB

After

Width:  |  Height:  |  Size: 181 KiB

View File

Before

Width:  |  Height:  |  Size: 1012 B

After

Width:  |  Height:  |  Size: 1012 B

18
frameserver/mkbinconv.sh Executable file
View File

@ -0,0 +1,18 @@
#!/bin/sh
awk -F '=' '
BEGIN{rows=columns=displays=disprows=dispsegments=0}
/^COLUMNS=/{columns=$2}
/^ROWS=/{rows=$2}
/^DISPLAYS=/{displays=$2}
/^DISPROWS=/{disprows=$2}
/^DISPSEGMENTS=/{dispsegments=$2}
END {
print "s2l"
printf "%c",columns+48
printf "%c",rows+48
printf "%c",displays+48
printf "%c",disprows+48
printf "%c",dispsegments+48
print " "
}
'

2
frameserver/s2l.binconf Normal file
View File

@ -0,0 +1,2 @@
s2l
<8<18

20
frameserver/s2l.conf Normal file
View File

@ -0,0 +1,20 @@
# this file defines the frame format
# it has to be converted to binconf format with mkbinconv.sh
# byte "s2l\n"
# byte windows per row (i.e. max X) in ASCII. in our case 12 => '<'
COLUMNS=12
# byte rows (i.e. max Y) in ASCII. in our case 8 => '8'
ROWS=8
# this part is only for having 7 segment displays instead of single pixels
# if you don't need this, set DISPLAYS to 0
# byte displays per row (usually same as windows per row) '<'
DISPLAYS=12
# byte disprows (how many rows of 7 segment displays). In our case always '1'
DISPROWS=1
# byte segments per display (can be 7,8,14 ... depending on the hardware)
DISPSEGMENTS=8
# byte reserved (future use) currently always set to 0x20 ' '
# byte z (indicates z level. 1=the most backwards) this is in binary...
# byte '\n'
# byte windows (channels*width+1)*height (so this starts 12 bytes from beginning)
# byte segments displays*(channels*segments+1)*disprows

View File

@ -12,10 +12,10 @@ then
exit 1
fi
$xt -t "central frameserver" -e frameserver/frameserver &
$xt -t "webserver" -e "$(which node) displayclienthtml/ws_udp.js" &
$xt -t "webserver" -e "$(which node) displayclient/html/ws_udp.js" &
sleep 5
chromium-browser displayclienthtml/visionneuse.html ||
x-www-browser displayclienthtml/visionneuse.html &
chromium-browser displayclient/html/visionneuse.html ||
x-www-browser displayclient/html/visionneuse.html &
$xt -t "client: plasma" -e "python clients/plasma.py" &
sleep 20
$xt -t "client: cellular" -e "python clients/cellular.py"