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 layoutmaster
parent
4d02195fd6
commit
f4c71012be
|
@ -12,12 +12,12 @@ The system is set up of various parts. See frameserver.png
|
||||||
|
|
||||||
Latest setup is:
|
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 listens for UDP packets to show on a virtual building
|
||||||
This server creates a webserver where a browser can connect to see a simulation
|
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
|
* frameserver
|
||||||
-------------
|
-------------
|
||||||
|
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Before Width: | Height: | Size: 267 KiB After Width: | Height: | Size: 267 KiB |
Before Width: | Height: | Size: 181 KiB After Width: | Height: | Size: 181 KiB |
Before Width: | Height: | Size: 1012 B After Width: | Height: | Size: 1012 B |
|
@ -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 " "
|
||||||
|
}
|
||||||
|
'
|
|
@ -0,0 +1,2 @@
|
||||||
|
s2l
|
||||||
|
<8<18
|
|
@ -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
|
|
@ -12,10 +12,10 @@ then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
$xt -t "central frameserver" -e frameserver/frameserver &
|
$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
|
sleep 5
|
||||||
chromium-browser displayclienthtml/visionneuse.html ||
|
chromium-browser displayclient/html/visionneuse.html ||
|
||||||
x-www-browser displayclienthtml/visionneuse.html &
|
x-www-browser displayclient/html/visionneuse.html &
|
||||||
$xt -t "client: plasma" -e "python clients/plasma.py" &
|
$xt -t "client: plasma" -e "python clients/plasma.py" &
|
||||||
sleep 20
|
sleep 20
|
||||||
$xt -t "client: cellular" -e "python clients/cellular.py"
|
$xt -t "client: cellular" -e "python clients/cellular.py"
|
||||||
|
|
Loading…
Reference in New Issue