This allows an LPC1768 to take Art-Net data and send it to WS2812B LED's
Dependencies: mbed mbed-rtos EthernetInterface
Revision 15:c730bd607d9a, committed 2018-12-26
- Comitter:
- tonydbeck
- Date:
- Wed Dec 26 21:05:02 2018 +0000
- Parent:
- 14:72be2b8b7f24
- Commit message:
- Full Working Version - December 18
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ArtNet.h Wed Dec 26 21:05:02 2018 +0000 @@ -0,0 +1,94 @@ +#include "mbed.h" +#include "EthernetInterface.h" + +#define ArtMaxUniv 4 // Universe +#define SizeRecvBuffer 700 +#define ArtHeaderID "Art-Net" // packet header +#define ArtUDPPort 0x1936 // UDP port 6454 for Art-Net +#define ArtVersion 14 // Art-Net version +#define OP_Output 0x5000 //Art-Net DMX Packet 'Output' +#define OP_Poll 0x2000 // ArtPoll +#define OP_PollReply 0x2100 // ArtPoll Reply +#define StyleNode 0 +#define StyleServer 1 + +#define STR_LongName "Art-Net to WS2812B - By Tony Beck" +#define STR_ShortName "MBED ArtNet LED" + +// host to network short +#define htons( x ) ( (( (x) << 8 ) & 0xFF00) | (( (x) >> 8 ) & 0x00FF) ) +#define ntohs( x ) htons(x) +// host to network long +#define htonl( x ) ( (( (x) << 24 ) & 0xFF000000) \ + | (( (x) << 8 ) & 0x00FF0000) \ + | (( (x) >> 8 ) & 0x0000FF00) \ + | (( (x) >> 24 ) & 0x000000FF) ) +#define ntohl( x ) htonl(x) + +struct ArtAddr { + unsigned char IP[4]; // ip addess 0.1.2.3 + unsigned short Port; +} __attribute__((packed)); + +struct ArtPacketHeader { + char ID[8]; + unsigned short OpCode; // 0x5000 +} __attribute__((packed)); + + +// dmx transport packet +struct ArtDMX_Packet { + char ID[8]; + unsigned short OpCode; // 0x5000 + unsigned char VersionH; // 0 + unsigned char Version; // 14 + unsigned char Sequence; // 0 + unsigned char Physical; // 0 + unsigned short Universe; + unsigned short Length; // size of data segment + unsigned char Data[512]; // data segment +} __attribute__((packed)); + +struct ArtPoll_Packet { + char ID[8]; + unsigned short OpCode; // 0x5000 + unsigned char VersionH; // 0 + unsigned char Version; // 14 + unsigned char TalkToMe; // 0 +} __attribute__((packed)); + + +// a responce to a artpoll packet +struct ArtPollReply_Packet { + char ID[8]; + unsigned short OpCode; // 0x2000 + struct ArtAddr Addr; // our ip address and UDP port + unsigned char VersionH; + unsigned char Version; + unsigned char SubSwitchH; + unsigned char SubSwitch; + unsigned short OEM; + char UbeaVersion; + char Status; + unsigned short EstaMan; + char ShortName[18]; + char LongName[64]; + char NodeReport[64]; + unsigned char NumPortsH; + unsigned char NumPorts; + unsigned char PortType[4]; + unsigned char GoodInput[4]; + unsigned char GoodOutput[4]; + unsigned char Swin[4]; + unsigned char Swout[4]; + unsigned char SwVideo; + unsigned char SwMacro; + unsigned char SwRemote; + unsigned char Spare[3]; // three spare bytes + unsigned char Style; + unsigned char Mac[6]; + unsigned char Padding[32]; // padding +} __attribute__((packed)); + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NeoStrip/NeoCore.s Wed Dec 26 21:05:02 2018 +0000 @@ -0,0 +1,218 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; NeoCore.s +; +; Allen Wild +; March 2014 +; +; ARM assembly functions for writing to Adafruit NeoPixels +; with the mbed NXP LPC1768 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + AREA neo_core, CODE, READONLY + + IMPORT neo_fio_reg + IMPORT neo_bitmask + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +neo_write_pin +; Set the GPIO pin to the value passed in R0 +; Registers and bitmasks are stored in variables set by the C++ library + LDR R1, =neo_fio_reg ; load pointers to register values + LDR R2, =neo_bitmask + LDR R1, [R1] ; load actual values from memory + LDR R2, [R2] + + CMP R0, #0 ; VALUE == 0 ? + ITE EQ ; (IF-THEN-ELSE) ON NEXT TWO INSTRUCTIONS USING "EQ" FLAG + STREQ R2, [R1,#0x1C] ; if==0, CLEAR BIT + STRNE R2, [R1,#0x18] ; if==1, SET BIT + BX LR + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +neo_zero +; Output a NeoPixel zero, composed of a short +; HIGH pulse and a long LOW pulse + PUSH {LR} + MOV R0, #1 + BL neo_write_pin ; set pin high + + MOV R0, #10 ; delay for long enough + BL neo_delay + + MOV R0, #0 ; set pin low + BL neo_write_pin + + MOV R0, #20 ; delay + BL neo_delay + + POP {LR} + BX LR + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +neo_one +; Output a NeoPixel one, composed of a long +; HIGH pulse and a short LOW pulse + PUSH {LR} + MOV R0, #1 + BL neo_write_pin + + MOV R0, #86 + BL neo_delay + + MOV R0, #0 + BL neo_write_pin + + NOP ; really short delay + NOP + NOP + + POP {LR} + BX LR + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + EXPORT neo_out ; void neo_out(int *data, int n); +; Main function called from the C++ library +; R0 contains a pointer to the array of color data to send +; R1 contains the number of bytes of data to send +neo_out + PUSH {LR, R4, R5, R6, R7, R8} + MOV R7, R1 ; move length to R7 + MOV R6, R0 ; move address to R6 + +neo_byteloop + LDRB R5, [R6] ; load byte to send + MOV R4, #0x80 ; load initial bitmask + +neo_bitloop + AND R3, R5, R4 ; mask current byte + CMP R3, #0 + BLEQ neo_zero ; send current bit + BLNE neo_one + + LSR R4, R4, #1 ; shift bitmask right one + CMP R4, #0 ; if still more bits, loop back + BNE neo_bitloop + + ADD R6, R6, #1 ; increment address + SUB R7, R7, #1 ; decrement count + CMP R7, #0 + BNE neo_byteloop ; continue if not done + + MOV R0, #0 + BL neo_write_pin + POP {R8, R7, R6, R5, R4, LR} + BX LR + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +neo_delay +; delay the specified number of cycles in R0 with a bunch of nops + LDR R2, =neo_delay_end + SUB R2, R2, R0 + BX R2 + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP +neo_delay_end + BX LR + + END ; end code region + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NeoStrip/NeoStrip.cpp Wed Dec 26 21:05:02 2018 +0000 @@ -0,0 +1,93 @@ +/********************************************** + * NeoStrip.cpp + * + * Allen Wild + * March 2014 + * + * Controls a strip of Adafruit NeoPixels, addressable RGB LEDs + * Currently, because of the global nature of the IO register and bitmask variables, + * it is only possible to use one NeoStrip instance at a time. + * + * This library supports only the NXP LPC1768! + */ + +#include "mbed.h" +#include "NeoStrip.h" + +// function to write to the strip, implemented in ARM assembly +extern "C" void neo_out(NeoColor*, int); + +// FastIO register address and bitmask for the GPIO pin +// because these are imported in the assembly +uint32_t neo_fio_reg; +uint32_t neo_bitmask; + +NeoStrip::NeoStrip(PinName pin, int N) : N(N) +{ + bright = 0.5; + Nbytes = N * 3; + strip = (NeoColor*)malloc(N * sizeof(NeoColor)); + if (strip == NULL) + { + printf("NeoStrip: ERROR unable to malloc strip data"); + N = 0; + } + + gpio_init_out(&gpio, pin); // initialize GPIO registers + neo_fio_reg = (uint32_t)gpio.reg_dir; // set registers and bitmask for + neo_bitmask = 1 << ((int)pin & 0x1F); // the assembly to use +} + +void NeoStrip::setBrightness(float bright) +{ + this->bright = bright; +} + +void NeoStrip::setPixel(int p, int color) +{ + int red = (color & 0xFF0000) >> 16; + int green = (color & 0x00FF00) >> 8; + int blue = (color & 0x0000FF); + setPixel(p, red, green, blue); +} + +void NeoStrip::setPixel(int p, uint8_t red, uint8_t green, uint8_t blue) +{ + // set the given pixel's RGB values + // the array is indexed modulo N to avoid overflow + strip[p % N].red = (uint8_t)(red * bright); + strip[p % N].green = (uint8_t)(green * bright); + strip[p % N].blue = (uint8_t)(blue * bright); +} + +void NeoStrip::setPixels(int p, int n, const int *colors) +{ + int r, g, b; + for (int i = 0; i < n; i++) + { + r = (colors[i] & 0xFF0000) >> 16; + g = (colors[i] & 0x00FF00) >>8; + b = colors[i] & 0x0000FF; + setPixel(p+i, r, g, b); + } +} + +void NeoStrip::clear() +{ + for (int i = 0; i < N; i++) + { + strip[i].red = 0; + strip[i].green = 0; + strip[i].blue = 0; + } +} + +void NeoStrip::write() +{ + __disable_irq(); // disable interrupts + neo_out(strip, Nbytes); // output to the strip + __enable_irq(); // enable interrupts + wait_us(50); // wait 50us for the reset pulse +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NeoStrip/NeoStrip.h Wed Dec 26 21:05:02 2018 +0000 @@ -0,0 +1,107 @@ +/** + * NeoStrip.h + * + * Allen Wild + * March 2014 + * + * Library for the control of Adafruit NeoPixel addressable RGB LEDs. + */ + + +#ifndef NEOSTRIP_H +#define NEOSTRIP_H + +#ifndef TARGET_LPC1768 +#error NeoStrip only supports the NXP LPC1768! +#endif + +// NeoColor struct definition to hold 24 bit +// color data for each pixel, in GRB order +typedef struct _NeoColor +{ + uint8_t green; + uint8_t red; + uint8_t blue; +} NeoColor; + +/** + * NeoStrip objects manage the buffering and assigning of + * addressable NeoPixels + */ +class NeoStrip +{ + public: + + /** + * Create a NeoStrip object + * + * @param pin The mbed data pin name + * @param N The number of pixels in the strip + */ + NeoStrip(PinName pin, int N); + + /** + * Set an overall brightness scale for the entire strip. + * When colors are set using setPixel(), they are scaled + * according to this brightness. + * + * Because NeoPixels are very bright and draw a lot of current, + * the brightness is set to 0.5 by default. + * + * @param bright The brightness scale between 0 and 1.0 + */ + void setBrightness(float bright); + + /** + * Set a single pixel to the specified color. + * + * This method (and all other setPixel methods) uses modulo-N arithmetic + * when addressing pixels. If p >= N, the pixel address will wrap around. + * + * @param p The pixel number (starting at 0) to set + * @param color A 24-bit color packed into a single int, + * using standard hex color codes (e.g. 0xFF0000 is red) + */ + void setPixel(int p, int color); + + /** + * Set a single pixel to the specified color, with red, green, and blue + * values in separate arguments. + */ + void setPixel(int p, uint8_t red, uint8_t green, uint8_t blue); + + /** + * Set n pixels starting at pixel p. + * + * @param p The first pixel in the strip to set. + * @param n The number of pixels to set. + * @param colors An array of length n containing the 24-bit colors for each pixel + */ + void setPixels(int p, int n, const int *colors); + + /** + * Reset all pixels in the strip to be of (0x000000) + */ + void clear(); + + /** + * Write the colors out to the strip; this method must be called + * to see any hardware effect. + * + * This function disables interrupts while the strip data is being sent, + * each pixel takes approximately 30us to send, plus a 50us reset pulse + * at the end. + */ + void write(); + + protected: + NeoColor *strip; // pixel data buffer modified by setPixel() and used by neo_out() + int N; // the number of pixels in the strip + int Nbytes; // the number of bytes of pixel data (always N*3) + float bright; // the master strip brightness + gpio_t gpio; // gpio struct for initialization and getting register addresses +}; + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NeoStrip/gt.h Wed Dec 26 21:05:02 2018 +0000 @@ -0,0 +1,12 @@ +/**** gt.h ****/ + +const int gt_img[] = { + 0x122446, 0xffff00, 0xffff00, 0xffff00, 0xffff00, 0x122446, 0x122446, 0x122446, + 0xffff00, 0xffff00, 0x122446, 0x122446, 0x122446, 0x122446, 0x122446, 0x122446, + 0xffff00, 0x122446, 0x122446, 0x122446, 0x122446, 0x122446, 0x122446, 0x122446, + 0xffff00, 0x122446, 0x122446, 0xffff00, 0xffff00, 0xffff00, 0xffff00, 0xffff00, + 0xffff00, 0xffff00, 0x122446, 0x122446, 0xffff00, 0x122446, 0xffff00, 0x122446, + 0x122446, 0xffff00, 0xffff00, 0xffff00, 0xffff00, 0x122446, 0xffff00, 0x122446, + 0x122446, 0x122446, 0x122446, 0x122446, 0x122446, 0x122446, 0xffff00, 0x122446, + 0x122446, 0x122446, 0x122446, 0x122446, 0x122446, 0x122446, 0xffff00, 0x122446}; +
--- a/main.cpp Wed May 14 15:07:26 2014 +0000 +++ b/main.cpp Wed Dec 26 21:05:02 2018 +0000 @@ -1,12 +1,176 @@ +//Code adapted from ArtNode by Suga Koubou +//https://os.mbed.com/users/okini3939/code/ArtNode/file/e3d0bc58141e/main.cpp/ + + + + + #include "mbed.h" #include "EthernetInterface.h" +#include "ArtNet.h" +#include "NeoStrip.h" +#include "gt.h" + +#define STATIC +#define DNS_SERVER_ADDRESS(ipaddr) (ip4_addr_set_u32(ipaddr, ipaddr_addr("192.168.1.254"))) +#define ECHO_SERVER_PORT 0x1936 +#define DATA_PIN p18 +#define LED_COUNT 300 + + +const char *ipAddr = "192.168.1.130"; +const char *snMask = "255.255.255.0"; +const char *gwAddr = "192.168.1.254"; +int okToWrite; +//******************************************Art-Net Stuff******************************* +extern "C" void mbed_mac_address(char *s); +struct ArtPacketHeader ArtHead; +struct ArtDMX_Packet ArtDMX; +struct ArtPoll_Packet ArtPoll; +struct ArtAddr localaddr; +struct ArtPollReply_Packet ArtPollReply; +int rxlen = 0; +int LastRecievedUniverse; + +NeoStrip strip(DATA_PIN, LED_COUNT); + +void InitArtPollReplyDefaults () { + memcpy(ArtPollReply.ID, ArtHeaderID, 8); + ArtPollReply.OpCode = OP_PollReply; // reply packet + ArtPollReply.Version = ArtVersion; + + memcpy(&ArtPollReply.Addr, &localaddr, sizeof(localaddr)); + strncpy(ArtPollReply.ShortName, STR_ShortName, 18); + strncpy(ArtPollReply.LongName, STR_LongName, 64); + strncpy(ArtPollReply.NodeReport, "OK", 64); + ArtPollReply.Style = StyleNode; + + mbed_mac_address((char*)&ArtPollReply.Mac); + + ArtPollReply.NumPortsH = 0; + ArtPollReply.NumPorts = 2; + ArtPollReply.Swout[0] = 1; + ArtPollReply.Swout[1] = 2; + ArtPollReply.Swout[2] = 0; + ArtPollReply.Swout[3] = 0; + ArtPollReply.Swin[0] = 0; + ArtPollReply.Swin[1] = 0; + ArtPollReply.Swin[2] = 0; + ArtPollReply.Swin[3] = 0; + + ArtPollReply.GoodOutput[0] = 0; + ArtPollReply.GoodOutput[1] = 0; + ArtPollReply.GoodOutput[2] = 0; + ArtPollReply.GoodOutput[3] = 0; + ArtPollReply.PortType[0] = 0x40; // bit7:Can output from Art-Net network, bit0-5: 0 - type = DMX512 + ArtPollReply.PortType[1] = 0x40; + ArtPollReply.PortType[2] = 255; + ArtPollReply.PortType[3] = 255; + + } + + +void Init_ArtDMX () + { + // header stuff + okToWrite = 0; + memcpy(ArtDMX.ID, ArtHeaderID, 8); + ArtDMX.OpCode = OP_Output; + ArtDMX.Version = ArtVersion; + // dmx stuff + ArtDMX.Universe = 0; // this is the destination for the dmx + ArtDMX.Sequence = 0; + ArtDMX.Length = htons(512); +} +// Converts HSV to RGB with the given hue, assuming +// maximum saturation and value +int hueToRGB(float h) +{ + // lots of floating point magic from the internet and scratching my head + float r, g, b; + if (h > 360) + h -= 360; + if (h < 0) + h += 360; + int i = (int)(h / 60.0); + float f = (h / 60.0) - i; + float q = 1 - f; + + switch (i % 6) + { + case 0: r = 1; g = f; b = 0; break; + case 1: r = q; g = 1; b = 0; break; + case 2: r = 0; g = 1; b = f; break; + case 3: r = 0; g = q; b = 1; break; + case 4: r = f; g = 0; b = 1; break; + case 5: r = 1; g = 0; b = q; break; + default: r = 0; g = 0; b = 0; break; + } + + // scale to integers and return the packed value + uint8_t R = (uint8_t)(r * 255); + uint8_t G = (uint8_t)(g * 255); + uint8_t B = (uint8_t)(b * 255); + + return (R << 16) | (G << 8) | B; +} + +int makeword16 (int lsb, int msb) +{ + return (msb << 8) + lsb; +} +//************************************************************************************* + + + + + + +void thread1(void const *args) +{ + + while(true) + { + /* static float dh = 360.0 / LED_COUNT; + static float x = 0; + + for (int i = 0; i < LED_COUNT; i++) + strip.setPixel(i, hueToRGB((dh * i) - x)); + + x += 1; + if (x > 360) + x = 0;*/ + + + strip.write(); + + Thread::wait(10); + } +} + int main() { + strip.setBrightness(1.0); // set default brightness + strip.setPixels(0, LED_COUNT, gt_img); + strip.write(); + EthernetInterface eth; - eth.init(); //Use DHCP +#ifdef STATIC + eth.init(ipAddr,snMask,gwAddr); //Use DHCP +#else + eth.init(); +#endif eth.connect(); - printf("IP Address is %s\n", eth.getIPAddress()); + printf("\r\nIP Address is %s\r\n", eth.getIPAddress()); + + + + + + + + /* TCPSocketConnection sock; sock.connect("mbed.org", 80); @@ -26,6 +190,117 @@ sock.close(); eth.disconnect(); + */ + + + InitArtPollReplyDefaults(); + + ArtPollReply.PortType[0] = 128; + ArtPollReply.PortType[1] = 128; + ArtPollReply.PortType[2] = 64; + ArtPollReply.GoodInput[2] = 4; + ArtPollReply.PortType[3] = 64; + ArtPollReply.GoodInput[3] = 4; + + UDPSocket server; + server.bind(ECHO_SERVER_PORT); + server.set_broadcasting(); + + Endpoint client; + + char *RecvByte; + char buffer[1500]; + // char outputString[512]; + + + int pos; + int x,y; + + Thread t1(thread1); //start thread1 + //t1.set_priority(osPriorityRealtime); + + while (true) { + // printf("\r\nWaiting for UDP packet...\r\n"); + int n = server.receiveFrom(client, buffer, sizeof(buffer)); + buffer[n] = '\0'; + + + memcpy(&ArtHead,buffer,sizeof(ArtPacketHeader)); + if(strncmp(ArtHead.ID, ArtHeaderID, 8) == 0 ) + { + RecvByte = &buffer[10]; + // printf("Valid ArtNet packet\r\n"); + } + + // printf("\nID = %s \n",ArtHead.ID); + + switch(ArtHead.OpCode) + { + case OP_Output: + //printf("OPCode = Output,%#x Size = %d\r\n",ArtHead.OpCode,n); + ArtDMX.VersionH = RecvByte[0]; + ArtDMX.Version = RecvByte[1]; + ArtDMX.Sequence = RecvByte[2]; + ArtDMX.Physical = RecvByte[3]; + x = RecvByte[4]; + y = RecvByte[5]; + ArtDMX.Universe = makeword16(x,y); + LastRecievedUniverse = ArtDMX.Universe; + x = RecvByte[6]; + y = RecvByte[7]; + ArtDMX.Length = makeword16(y,x); + //printf("VerH: %d, VerL: %d, Seq: %d, Phys: %d, Univ: %d, Length: %d\r\n",ArtDMX.VersionH,ArtDMX.Version,ArtDMX.Sequence,ArtDMX.Physical,ArtDMX.Universe,ArtDMX.Length); //used for debugging + int byteLoc = 0; + if(ArtDMX.Universe == 1) + { + + for (pos = 0;pos<170;pos++) + { + byteLoc = (pos*3); + strip.setPixel(pos, RecvByte[8+byteLoc],RecvByte[9+byteLoc],RecvByte[10+byteLoc]); + // printf("%d, ",RecvByte[8+pos]) + } + + } + + if(ArtDMX.Universe == 2) + { + + for (pos = 170;pos<300;pos++) + { + byteLoc = ((pos-170)*3); + strip.setPixel(pos, RecvByte[8+byteLoc],RecvByte[9+byteLoc],RecvByte[10+byteLoc]); + + } + } + // strip.write(); + break; + + case OP_Poll: + printf("OpCode = Poll, %#x, Size: %d\r\n",ArtHead.OpCode,n); + ArtPoll.VersionH = RecvByte[0]; + ArtPoll.Version = RecvByte[1]; + ArtPoll.TalkToMe = RecvByte[2]; + printf("Sending Reply\r\n"); + server.sendTo(client, (char*)&ArtPollReply, sizeof(ArtPollReply)); + printf("Sent Reply Complete\r\n"); + break; + + default: + printf("No OPcode read, OPCode=%#x, Size: %d\r\n",ArtHead.ID,n); + break; + } + + + + // printf("Received packet from: %s\r\n", client.get_address()); + // printf("Packet contents : '%s'\r\n",buffer); + //printf("Sending Packet back to Client\n"); + //server.sendTo(client, buffer, n); + + } + + while(1) {} }