Skip to content
Permalink
master
Go to file
 
 
Cannot retrieve contributors at this time
238 lines (193 sloc) 7.14 KB
/***********************************************************
* DIY monome compatible grid w/ Adafruit NeoTrellis
* for Teensy
*
* This code makes the Adafruit Neotrellis boards into a Monome compatible grid via monome's mext protocol
* ----> https://www.adafruit.com/product/3954
*
* Code here is for a 16x8 grid, but can be modified for 4x8, 8x8, or 16x16 (untested on larger grid arrays)
*
* Many thanks to:
* scanner_darkly <https://github.com/scanner-darkly>,
* TheKitty <https://github.com/TheKitty>,
* Szymon Kaliski <https://github.com/szymonkaliski>,
* John Park, Todbot, Juanma, Gerald Stevens, and others
*
*/
#include "MonomeSerialDevice.h"
#include <Adafruit_NeoTrellis.h>
#include "debug.h"
#define NUM_ROWS 8 // DIM_Y number of rows of keys down
#define NUM_COLS 16 // DIM_X number of columns of keys across
#define INT_PIN 9
#define LED_PIN 13 // teensy LED
// This assumes you are using a USB breakout board to route power to the board
// If you are plugging directly into the teensy, you will need to adjust this brightness to a much lower value
#define BRIGHTNESS 255 // overall grid brightness - use gamma table below to adjust levels
// RGB values - vary for colors other than white
#define R 255
#define G 255
#define B 255
// amber-ish {255,191,0}
// warmer white? {255,255,200}
// Gamma table to customize 16 levels of brightness
// RGB values above will be scaled to these
const uint8_t gammaTable[16] = { 2, 3, 4, 6, 11, 18, 25, 32, 41, 59, 70, 80, 92, 103, 115, 128};
bool isInited = false;
elapsedMillis monomeRefresh;
// set your monome device name here
String deviceID = "neo-monome";
// Monome class setup
MonomeSerialDevice mdp;
int prevLedBuffer[mdp.MAXLEDCOUNT];
// NeoTrellis setup
/*
// 8x8 setup
Adafruit_NeoTrellis trellis_array[NUM_ROWS / 4][NUM_COLS / 4] = {
{ Adafruit_NeoTrellis(0x2F), Adafruit_NeoTrellis(0x2E) },
{ Adafruit_NeoTrellis(0x3E), Adafruit_NeoTrellis(0x36) }
};
*/
// 16x8
Adafruit_NeoTrellis trellis_array[NUM_ROWS / 4][NUM_COLS / 4] = {
{ Adafruit_NeoTrellis(0x32), Adafruit_NeoTrellis(0x30), Adafruit_NeoTrellis(0x2F), Adafruit_NeoTrellis(0x2E) }, // top row
{ Adafruit_NeoTrellis(0x33), Adafruit_NeoTrellis(0x31), Adafruit_NeoTrellis(0x3E), Adafruit_NeoTrellis(0x36) } // bottom row
};
/*
// 16x16
Adafruit_NeoTrellis trellis_array[NUM_ROWS / 4][NUM_COLS / 4] = {
{ Adafruit_NeoTrellis(0x33), Adafruit_NeoTrellis(0x31), Adafruit_NeoTrellis(0x2F), Adafruit_NeoTrellis(0x2E)}, // top row
{ Adafruit_NeoTrellis(0x35), Adafruit_NeoTrellis(0x39), Adafruit_NeoTrellis(0x3F), Adafruit_NeoTrellis(0x37)}, // bottom row
{ Adafruit_NeoTrellis(0x43), Adafruit_NeoTrellis(0x41), Adafruit_NeoTrellis(0x36), Adafruit_NeoTrellis(0x3E)},
{ Adafruit_NeoTrellis(0x45), Adafruit_NeoTrellis(0x49), Adafruit_NeoTrellis(0x4d), Adafruit_NeoTrellis(0x47)}
};
*/
Adafruit_MultiTrellis trellis((Adafruit_NeoTrellis *)trellis_array, NUM_ROWS / 4, NUM_COLS / 4);
// ***************************************************************************
// ** HELPERS **
// ***************************************************************************
// Pad a string of length 'len' with nulls
void pad_with_nulls(char* s, int len) {
int l = strlen(s);
for( int i=l;i<len; i++) {
s[i] = '\0';
}
}
// Input a value 0 to 255 to get a color value.
// The colors are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
if(WheelPos < 85) {
return seesaw_NeoPixel::Color(WheelPos * 3, 255 - WheelPos * 3, 0);
} else if(WheelPos < 170) {
WheelPos -= 85;
return seesaw_NeoPixel::Color(255 - WheelPos * 3, 0, WheelPos * 3);
} else {
WheelPos -= 170;
return seesaw_NeoPixel::Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
return 0;
}
// ***************************************************************************
// ** FUNCTIONS FOR TRELLIS **
// ***************************************************************************
// Define a callback for key presses
TrellisCallback keyCallback(keyEvent evt){
uint8_t x;
uint8_t y;
x = evt.bit.NUM % NUM_COLS; // NUM_COLS;
y = evt.bit.NUM / NUM_COLS; // NUM_COLS;
if(evt.bit.EDGE == SEESAW_KEYPAD_EDGE_RISING){
//on
//Serial.println(" pressed ");
mdp.sendGridKey(x, y, 1);
}else if(evt.bit.EDGE == SEESAW_KEYPAD_EDGE_FALLING){
//off
//Serial.println(" released ");
mdp.sendGridKey(x, y, 0);
}
return 0;
}
// ***************************************************************************
// ** SETUP **
// ***************************************************************************
void setup(){
uint8_t x, y;
Serial.begin(115200);
// monome connection setup
mdp.isMonome = true;
mdp.deviceID = deviceID;
mdp.setupAsGrid(NUM_ROWS, NUM_COLS);
monomeRefresh = 0;
isInited = true;
int var = 0;
while (var < 8) {
mdp.poll();
var++;
delay(100);
}
if (!trellis.begin()) {
Serial.println("trellis.begin() failed!");
Serial.println("check your addresses.");
Serial.println("reset to try again.");
while(1); // loop forever
}
// setup trellis key callbacks
for (y = 0; y < NUM_ROWS; y++) {
for (x = 0; x < NUM_COLS; x++) {
trellis.activateKey(x, y, SEESAW_KEYPAD_EDGE_RISING, true);
trellis.activateKey(x, y, SEESAW_KEYPAD_EDGE_FALLING, true);
trellis.registerCallback(x, y, keyCallback);
}
}
// set overall brightness for all pixels
for (x = 0; x < NUM_COLS / 4; x++) {
for (y = 0; y < NUM_ROWS / 4; y++) {
trellis_array[y][x].pixels.setBrightness(BRIGHTNESS);
}
}
// clear grid leds
// delay(100);
mdp.setAllLEDs(0);
sendLeds();
// Blink one led to show it's started up
trellis.setPixelColor(0, 0xFFFFFF);
trellis.show();
delay(100);
trellis.setPixelColor(0, 0x000000);
trellis.show();
}
// ***************************************************************************
// ** SEND LEDS **
// ***************************************************************************
void sendLeds(){
uint8_t value, prevValue = 0;
uint32_t hexColor;
bool isDirty = false;
for(int i=0; i< NUM_ROWS * NUM_COLS; i++){
value = mdp.leds[i];
prevValue = prevLedBuffer[i];
uint8_t gvalue = gammaTable[value];
if (value != prevValue) {
//hexColor = (((R * value) >> 4) << 16) + (((G * value) >> 4) << 8) + ((B * value) >> 4);
hexColor = (((gvalue*R)/256) << 16) + (((gvalue*G)/256) << 8) + (((gvalue*B)/256) << 0);
trellis.setPixelColor(i, hexColor);
prevLedBuffer[i] = value;
isDirty = true;
}
}
if (isDirty) {
trellis.show();
}
}
// ***************************************************************************
// ** LOOP **
// ***************************************************************************
void loop() {
mdp.poll(); // process incoming serial from Monomes
// refresh every 16ms or so
if (isInited && monomeRefresh > 16) {
trellis.read();
sendLeds();
monomeRefresh = 0;
}
}