-
Notifications
You must be signed in to change notification settings - Fork 517
LED Strip (sorry the branch name is still neopixel_strip) #168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7399898
3513fc7
f740d66
43ea815
1f94a60
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| #include <Firmata.h> | ||
| #include <Ethernet.h> | ||
| #include <Wire.h> | ||
| #include <Servo.h> | ||
| #include <SPI.h> | ||
| #include <Adafruit_NeoPixel.h> | ||
|
|
||
| #include <utility/FirmataExt.h> | ||
| FirmataExt firmataExt; | ||
|
|
||
| #include "utility/neopixelFirmata.h" | ||
| NeopixelFirmata* neopixelFirmata = neopixelFirmataFactory(); | ||
|
|
||
| /*============================================================================== | ||
| * FUNCTIONS | ||
| *============================================================================*/ | ||
|
|
||
| void systemResetCallback() | ||
| { | ||
| // initialize a defalt state | ||
|
|
||
| // pins with analog capability default to analog input | ||
| // otherwise, pins default to digital output | ||
| for (byte i=0; i < TOTAL_PINS; i++) { | ||
| } | ||
|
|
||
| firmataExt.reset(); | ||
| } | ||
|
|
||
| /*============================================================================== | ||
| * SETUP() | ||
| *============================================================================*/ | ||
|
|
||
| void setup() | ||
| { | ||
| Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); | ||
| firmataExt.addFeature(*neopixelFirmata); | ||
| Firmata.attach(SYSTEM_RESET, systemResetCallback); | ||
|
|
||
| // start up the default Firmata using Serial interface: | ||
| Firmata.begin(57600); | ||
| systemResetCallback(); // reset to default config | ||
| } | ||
|
|
||
| /*============================================================================== | ||
| * LOOP() | ||
| *============================================================================*/ | ||
| void loop() | ||
| { | ||
|
|
||
| while(Firmata.available()) { | ||
| Firmata.processInput(); | ||
| } | ||
|
|
||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| #include "LedStripFirmata.h" | ||
| // Choose one pixel subtype to include | ||
| #include "NeopixelFirmata.h" | ||
| // #include "Ws2801PixelFirmata.h" // Not completed yet | ||
|
|
||
| void LedStripFirmata::handleCapability(byte pin) | ||
| { | ||
| if (IS_PIN_DIGITAL(pin)) | ||
| { | ||
| Firmata.write(LED_STRIP); | ||
| Firmata.write(1); // Not sure if this is necessary | ||
| } | ||
| } | ||
|
|
||
| boolean LedStripFirmata::handlePinMode(byte pin, int mode) | ||
| { | ||
| if (mode == LED_STRIP && IS_PIN_DIGITAL(pin)) | ||
| { | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| void LedStripFirmata::reportDone() | ||
| { | ||
| Firmata.write(START_SYSEX); | ||
| Firmata.write(LED_STRIP_DATA); | ||
| Firmata.write(LED_STRIP_CMD_DONE); | ||
| Firmata.write(END_SYSEX); | ||
| } | ||
|
|
||
| void LedStripFirmata::reportType() | ||
| { | ||
| Firmata.write(START_SYSEX); | ||
| Firmata.write(LED_STRIP_DATA); | ||
| Firmata.write(LED_STRIP_CMD_QUERY); | ||
| Firmata.write(ledType()); | ||
| Firmata.write(END_SYSEX); | ||
| } | ||
|
|
||
|
|
||
| boolean LedStripFirmata::handleSysex(byte command, byte argc, byte* argv) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Somewhere in this function you need to set the pin mode or the pin mode of LED_STRIP will not be set properly for the device. See the these lines in EncoderFirmatahttps://github.com/firmata/arduino/blob/configurable_dev/utility/EncoderFirmata.cpp#L50-L51 for an example. You also need to be sure to respect IGNORE pins. See an example here. In most cases there will not be a collision with IGNORE. The reason it was introduced is if a SPI device such as an ethernet or wi-fi controller are used, you can have conflicts with other Firmata features that may try to use one of the pins needed by the SPI interface. |
||
| { | ||
| if (command != LED_STRIP_DATA) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| byte npCommand = argv[0]; | ||
| if (!initialized && npCommand != LED_STRIP_CMD_INIT && npCommand != LED_STRIP_CMD_QUERY) | ||
| { | ||
| // Firmata.sendString("Led Strip Not Initialized: Not Initialized"); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This string is too long. Strings are extremely expensive in microcontrollers with limited SRAM such as the ATMega328p (Arduino Uno). For now, either leave this commented out as you have or shorten it to as few characters as possible. I had proposed a couple of new ways to handle errors a while back but was not able to get consensus around a solution. I need to reopen that discussion. |
||
| return false; | ||
| } | ||
|
|
||
| switch(npCommand) { | ||
| case LED_STRIP_CMD_QUERY: | ||
| reportType(); | ||
| return true; | ||
|
|
||
| default: | ||
| return handleStripCommand(npCommand, argc, argv); | ||
| } | ||
|
|
||
| return true; | ||
|
|
||
| } | ||
|
|
||
|
|
||
| LedStripFirmata* ledStripFirmataFactory() | ||
| { | ||
| #ifdef NeopixelFirmata_H | ||
| return new NeopixelFirmataImpl(); | ||
| #endif | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| #ifndef LedStripFirmata_H | ||
| #define LedStripFirmata_H | ||
|
|
||
| #include <Firmata.h> | ||
| #include "FirmataExt.h" | ||
|
|
||
| #define LED_STRIP_CMD_QUERY 0x00 | ||
| #define LED_STRIP_CMD_INIT 0x01 | ||
| #define LED_STRIP_CMD_PIXEL 0x02 | ||
| #define LED_STRIP_CMD_CLEAR 0x04 | ||
| #define LED_STRIP_CMD_SHOW 0x05 | ||
| #define LED_STRIP_CMD_BRIGHTNESS 0x06 | ||
| #define LED_STRIP_CMD_DONE 0x07 // Response | ||
|
|
||
| #define LED_STRIP_INIT_PARAM_PIN 0x01 | ||
| #define LED_STRIP_INIT_PARAM_COUNT 0x02 | ||
| #define LED_STRIP_INIT_PARAM_ORDER 0x04 | ||
| #define LED_STRIP_INIT_PARAM_SPEED 0x05 | ||
|
|
||
| #define LED_STRIP_PIXEL_PARAM_LOCATION 0x01 | ||
| #define LED_STRIP_PIXEL_PARAM_RED 0x03 | ||
| #define LED_STRIP_PIXEL_PARAM_GREEN 0x05 | ||
| #define LED_STRIP_PIXEL_PARAM_BLUE 0x07 | ||
|
|
||
| #define LED_STRIP_BRIGHTNESS_PARAM_VALUE 0x01 | ||
|
|
||
| #define LED_STRIP_TYPE_NEOPIXEL 0x00 | ||
| #define LED_STRIP_TYPE_WS2801 0x01 | ||
|
|
||
| class LedStripFirmata : public FirmataFeature | ||
| { | ||
| public: | ||
| LedStripFirmata() {} | ||
| void handleCapability(byte pin); | ||
| boolean handlePinMode(byte pin, int mode); | ||
| boolean handleSysex(byte command, byte argc, byte* argv); | ||
| virtual void reset() = 0; | ||
|
|
||
| protected: | ||
| virtual boolean handleStripCommand(byte command, byte argc, byte* argv) = 0; | ||
| void reportDone(); | ||
| void reportType(); | ||
| virtual byte ledType() = 0; | ||
|
|
||
| boolean initialized = false; | ||
| }; | ||
|
|
||
| LedStripFirmata* ledStripFirmataFactory(); | ||
|
|
||
| #endif // LedStripFirmata_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| #include "LedStripFirmata.h" | ||
| #include "NeopixelFirmata.h" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Try moving NeopixelFirmata.cpp and NeopixelFirmata.h to /utility/devices/ and compiling under both the latest version of Arduino 1.5.x and 1.0.x. Arduino keeps changing the way they compile files within subdirectories you may run into an issue here (with /devices/). I would prefer to keep device-specific code under a /devices/ subdirectory if possible. |
||
| #include <Adafruit_NeoPixel.h> | ||
|
|
||
| #define TOBYTE(loc) ((argv[loc] + (argv[loc+1] << 7))&0xFF) | ||
|
|
||
| NeopixelFirmataImpl::NeopixelFirmataImpl() | ||
| { | ||
| pixels = NULL; | ||
| } | ||
|
|
||
| boolean NeopixelFirmataImpl::handleStripCommand(byte npCommand, byte argc, byte* argv) | ||
| { | ||
| byte tmp; | ||
|
|
||
| switch(npCommand) { | ||
|
|
||
| case LED_STRIP_CMD_INIT: | ||
| initialize( | ||
| argv[LED_STRIP_INIT_PARAM_PIN], | ||
| TOBYTE(LED_STRIP_INIT_PARAM_COUNT), | ||
| argv[LED_STRIP_INIT_PARAM_ORDER], | ||
| argv[LED_STRIP_INIT_PARAM_SPEED] | ||
| ); | ||
| break; | ||
|
|
||
| case LED_STRIP_CMD_CLEAR: | ||
| pixels->clear(); | ||
| break; | ||
|
|
||
| case LED_STRIP_CMD_SHOW: | ||
| pixels->show(); | ||
| break; | ||
|
|
||
| case LED_STRIP_CMD_BRIGHTNESS: | ||
| if (argc>2) { | ||
| pixels->setBrightness(TOBYTE(LED_STRIP_BRIGHTNESS_PARAM_VALUE)); | ||
| } else { | ||
| reportBrightness(); | ||
| } | ||
| break; | ||
|
|
||
| case LED_STRIP_CMD_PIXEL: | ||
| tmp = TOBYTE(LED_STRIP_PIXEL_PARAM_LOCATION); | ||
|
|
||
| if(tmp > pixels->numPixels()) | ||
| { | ||
| // Firmata.sendString("NeoPixel: Location out of range"); | ||
| return false; | ||
| } | ||
|
|
||
| setPixel( | ||
| tmp, | ||
| TOBYTE(LED_STRIP_PIXEL_PARAM_RED), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use Encoder7Bit instead of the TOBYTE macro. You can refer to OneWireFirmata for examples of use. |
||
| TOBYTE(LED_STRIP_PIXEL_PARAM_GREEN), | ||
| TOBYTE(LED_STRIP_PIXEL_PARAM_BLUE) | ||
| ); | ||
| break; | ||
|
|
||
| default: | ||
| // Firmata.sendString("NeoPixel: Unknown Command"); | ||
| return false; | ||
| } | ||
|
|
||
| return true; | ||
|
|
||
| } | ||
|
|
||
| void NeopixelFirmataImpl::reset() | ||
| { | ||
| if (pixels != NULL) | ||
| { | ||
| delete pixels; | ||
| pixels = NULL; | ||
| } | ||
| } | ||
|
|
||
| void NeopixelFirmataImpl::initialize(byte pin, byte count, byte order, byte speed) | ||
| { | ||
| reset(); | ||
|
|
||
| pixels = new Adafruit_NeoPixel(count, pin, order + speed); | ||
| pixels->begin(); | ||
| for(int i=0; i<count; i++) { | ||
| pixels->setPixelColor(i, 0, 0, 255); | ||
| pixels->show(); | ||
| delay(50); | ||
| } | ||
| pixels->clear(); | ||
| pixels->show(); | ||
| reportDone(); | ||
| } | ||
|
|
||
| void NeopixelFirmataImpl::reportBrightness() | ||
| { | ||
| byte brightness = pixels->getBrightness(); | ||
| Firmata.write(START_SYSEX); | ||
| Firmata.write(LED_STRIP_DATA); | ||
| Firmata.write(LED_STRIP_CMD_BRIGHTNESS); | ||
| Firmata.write(brightness & 0x7F); | ||
| Firmata.write((brightness >> 7) & 0x7F); | ||
| Firmata.write(END_SYSEX); | ||
| } | ||
|
|
||
| void NeopixelFirmataImpl::setPixel(byte location, byte red, byte green, byte blue) | ||
| { | ||
| pixels->setPixelColor(location, red, green, blue); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| #ifndef NeopixelFirmata_H | ||
| #define NeopixelFirmata_H | ||
|
|
||
| #include "LedStripFirmata.h" | ||
| #include "Adafruit_Neopixel.h" | ||
|
|
||
| class NeopixelFirmataImpl : public LedStripFirmata | ||
| { | ||
| public: | ||
| NeopixelFirmataImpl(); | ||
| virtual void reset(); | ||
|
|
||
| protected: | ||
| byte ledType() { return LED_STRIP_TYPE_NEOPIXEL; } | ||
| virtual boolean handleStripCommand(byte command, byte argc, byte* argv); | ||
| bool initialized; | ||
|
|
||
| private: | ||
| Adafruit_NeoPixel* pixels; | ||
| void initialize(byte pin, byte count, byte order, byte speed); | ||
| void reportBrightness(); | ||
| void setPixel(byte position, byte red, byte green, byte blue); | ||
| }; | ||
|
|
||
| #endif // NeopixelFirmata_H | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's necessary per the protocol, but has no meaning for this particular device. For something like analog input or pwm it specifies the resolution in number of bits.