#include "MonomeSerialDevice.h" #include "debug.h" MonomeSerialDevice::MonomeSerialDevice() {} void MonomeSerialDevice::initialize() { active = false; isMonome = false; isGrid = true; rows = 0; columns = 0; encoders = 0; //clearQueue(); clearAllLeds(); arcDirty = false; gridDirty = false; } void MonomeSerialDevice::setupAsGrid(uint8_t _rows, uint8_t _columns) { initialize(); active = true; isMonome = true; isGrid = true; rows = _rows; columns = _columns; gridDirty = true; debugfln(INFO, "GRID rows: %d columns %d", rows, columns); } void MonomeSerialDevice::setupAsArc(uint8_t _encoders) { initialize(); active = true; isMonome = true; isGrid = false; encoders = _encoders; arcDirty = true; debugfln(INFO, "ARC encoders: %d", encoders); } void MonomeSerialDevice::setTiltActive(uint8_t sensor, bool active) { if (sensor < 4) { tiltActive[sensor] = active; } } void MonomeSerialDevice::sendTiltEvent(uint8_t sensor, int16_t x, int16_t y, int16_t z) { if (sensor < 4 && tiltActive[sensor]) { lastTiltX[sensor] = x; lastTiltY[sensor] = y; lastTiltZ[sensor] = z; Serial.write((uint8_t)0x81); // tiltイベントのプレフィックス Serial.write(sensor); Serial.write((uint8_t)(x >> 8)); Serial.write((uint8_t)(x & 0xFF)); Serial.write((uint8_t)(y >> 8)); Serial.write((uint8_t)(y & 0xFF)); Serial.write((uint8_t)(z >> 8)); Serial.write((uint8_t)(z & 0xFF)); } } void MonomeSerialDevice::getDeviceInfo() { //debugln(INFO, "MonomeSerialDevice::getDeviceInfo"); Serial.write(uint8_t(0)); } void MonomeSerialDevice::poll() { //while (isMonome && Serial.available()) { processSerial(); }; if (Serial.available()) { processSerial(); } //Serial.println("processSerial"); } void MonomeSerialDevice::setAllLEDs(int value) { for (int i = 0; i < MAXLEDCOUNT; i++) leds[i] = value; } void MonomeSerialDevice::setGridLed(uint8_t x, uint8_t y, uint8_t level) { // int index = x + (y * columns); // if (index < MAXLEDCOUNT) leds[index] = level; if (x < columns && y < rows) { uint32_t index = y * columns + x; leds[index] = level; } //debugfln(INFO, "LED index: %d x %d y %d", index, x, y); } void MonomeSerialDevice::clearGridLed(uint8_t x, uint8_t y) { setGridLed(x, y, 0); //Serial.println("clearGridLed"); } void MonomeSerialDevice::setArcLed(uint8_t enc, uint8_t led, uint8_t level) { int index = led + (enc << 6); if (index < MAXLEDCOUNT) leds[index] = level; //Serial.println("setArcLed"); } void MonomeSerialDevice::clearArcLed(uint8_t enc, uint8_t led) { setArcLed(enc, led, 0); //Serial.println("clearArcLed"); } void MonomeSerialDevice::clearAllLeds() { for (int i = 0; i < MAXLEDCOUNT; i++) leds[i] = 0; //Serial.println("clearAllLeds"); } void MonomeSerialDevice::clearArcRing(uint8_t ring) { for (int i = ring << 6, upper = i + 64; i < upper; i++) leds[i] = 0; //Serial.println("clearArcRing"); } void MonomeSerialDevice::refreshGrid() { gridDirty = true; //Serial.println("refreshGrid"); } void MonomeSerialDevice::refreshArc() { arcDirty = true; //Serial.println("refreshArc"); } void MonomeSerialDevice::sendSysSize() { Serial.write((uint8_t)0x05); // system / get grid size Serial.write((uint8_t)columns); Serial.write((uint8_t)rows); } void MonomeSerialDevice::sendSysRotation() { // Note: The original Monome protocol doesn't have a direct command for rotation. // This is a custom implementation. You may need to adjust how the host interprets this. Serial.write((uint8_t)0x0F); // Using 0x0F (system / report firmware version) as a custom command Serial.write((uint8_t)0xF0); // Custom identifier for rotation Serial.write((uint8_t)gridRotation); } void MonomeSerialDevice::refresh() { /* uint8_t buf[35]; int ind, led; if (gridDirty) { //Serial.println("gridDirty"); buf[0] = 0x1A; buf[1] = 0; buf[2] = 0; ind = 3; for (int y = 0; y < 8; y++) for (int x = 0; x < 8; x += 2) { led = (y << 4) + x; buf[ind++] = (leds[led] << 4) | leds[led + 1]; } Serial.write(buf, 35); ind = 3; buf[1] = 8; for (int y = 0; y < 8; y++) for (int x = 8; x < 16; x += 2) { led = (y << 4) + x; buf[ind++] = (leds[led] << 4) | leds[led + 1]; } Serial.write(buf, 35); ind = 3; buf[1] = 0; buf[2] = 8; for (int y = 8; y < 16; y++) for (int x = 0; x < 8; x += 2) { led = (y << 4) + x; buf[ind++] = (leds[led] << 4) | leds[led + 1]; } Serial.write(buf, 35); ind = 3; buf[1] = 8; for (int y = 8; y < 16; y++) for (int x = 8; x < 16; x += 2) { led = (y << 4) + x; buf[ind++] = (leds[led] << 4) | leds[led + 1]; } Serial.write(buf, 35); gridDirty = false; } if (arcDirty) { //Serial.print("arcDirty"); buf[0] = 0x92; buf[1] = 0; ind = 2; for (led = 0; led < 64; led += 2) buf[ind++] = (leds[led] << 4) | leds[led + 1]; Serial.write(buf, 34); buf[1] = 1; ind = 2; for (led = 64; led < 128; led += 2) buf[ind++] = (leds[led] << 4) | leds[led + 1]; Serial.write(buf, 34); buf[1] = 2; ind = 2; for (led = 128; led < 192; led += 2) buf[ind++] = (leds[led] << 4) | leds[led + 1]; Serial.write(buf, 34); buf[1] = 3; ind = 2; for (led = 192; led < 256; led += 2) buf[ind++] = (leds[led] << 4) | leds[led + 1]; Serial.write(buf, 34); buf[1] = 4; ind = 2; for (led = 256; led < 320; led += 2) buf[ind++] = (leds[led] << 4) | leds[led + 1]; Serial.write(buf, 34); buf[1] = 5; ind = 2; for (led = 320; led < 384; led += 2) buf[ind++] = (leds[led] << 4) | leds[led + 1]; Serial.write(buf, 34); buf[1] = 6; ind = 2; for (led = 384; led < 448; led += 2) buf[ind++] = (leds[led] << 4) | leds[led + 1]; Serial.write(buf, 34); buf[1] = 7; ind = 2; for (led = 448; led < 512; led += 2) buf[ind++] = (leds[led] << 4) | leds[led + 1]; Serial.write(buf, 34); arcDirty = 0; } */ } void MonomeSerialDevice::processSerial() { uint8_t identifierSent; // command byte sent from controller to matrix uint8_t index, readX, readY, readN, readA; uint8_t dummy, gridNum, deviceAddress; // for reading in data not used by the matrix uint8_t n, x, y, z, i; uint8_t intensity = 15; uint8_t gridKeyX; uint8_t gridKeyY; int8_t delta; uint8_t gridX = columns; // Will be either 8 or 16 uint8_t gridY = rows; uint8_t numQuads = columns / rows; // get command identifier: first byte of packet is identifier in the form: [(a << 4) + b] // a = section (ie. system, key-grid, digital, encoder, led grid, tilt) // b = command (ie. query, enable, led, key, frame) identifierSent = Serial.read(); switch (identifierSent) { case 0x00: // device information // [null, "led-grid", "key-grid", "digital-out", "digital-in", "encoder", "analog-in", "analog-out", "tilt", "led-ring"] //Serial.println("0x00 system / query ----------------------"); Serial.write((uint8_t)0x00); // action: response, 0x00 = system Serial.write((uint8_t)0x01); // section id, 1 = led-grid, 2 = key-grid, 5 = encoder/arc Serial.write((uint8_t)numQuads); // one Quad is 64 buttons Serial.write((uint8_t)0x00); // send again with 2 = key-grid Serial.write((uint8_t)0x02); // Serial.write((uint8_t)numQuads); break; case 0x01: // system / ID Serial.write((uint8_t)0x01); // action: response, 0x01 for (i = 0; i < 32; i++) { // has to be 32 if (i < deviceID.length()) { Serial.write(deviceID[i]); } else { Serial.write((uint8_t)0x00); } } break; case 0x02: // system / write ID //Serial.println("0x02"); for (int i = 0; i < 32; i++) { // has to be 32 deviceID[i] = Serial.read(); } break; case 0x03: // system / report grid offset //Serial.println("0x03"); Serial.write((uint8_t)0x02); // system / request grid offset - bytes: 1 - [0x03] Serial.write((uint8_t)0x01); Serial.write((uint8_t)0); // x offset - could be 0 or 8 ### NEEDS grid size variable Serial.write((uint8_t)0); // y offset break; case 0x04: // system / report ADDR //Serial.println("0x04"); gridNum = Serial.read(); // grid number readX = Serial.read(); // x offset readY = Serial.read(); // y offset break; case 0x05: // _SYS_GET_GRID_SIZE //Serial.println("0x05"); Serial.write((uint8_t)0x03); // system / request grid size Serial.write((uint8_t)gridX); // gridX Serial.write((uint8_t)gridY); // gridY break; case 0x06: readX = Serial.read(); // system / set grid size - ignored readY = Serial.read(); break; case 0x07: break; // I2C get addr (scan) - ignored case 0x08: deviceAddress = Serial.read(); // I2C set addr - ignored dummy = Serial.read(); break; case 0x0F: // system / report firmware version // Serial.println("0x0F"); for (int i = 0; i < 8; i++) { // 8 character string //Serial.print(Serial.read()); } break; // 0x10-0x1F are for an LED Grid Control. All bytes incoming, no responses back case 0x10: // /prefix/led/set x y [0/1] / led off readX = Serial.read(); readY = Serial.read(); setGridLed(readX, readY, 0); break; case 0x11: // /prefix/led/set x y [0/1] / led on readX = Serial.read(); readY = Serial.read(); setGridLed(readX, readY, 15); // need global brightness variable? break; case 0x12: // /prefix/led/all [0/1] / all off clearAllLeds(); break; case 0x13: // /prefix/led/all [0/1] / all on setAllLEDs(15); break; case 0x14: // /prefix/led/map x y d[8] / map (frame) readX = Serial.read(); while (readX > 16) { readX += 16; } // hacky shit to deal with negative numbers from rotation readX &= 0xF8; // floor the offset to 0 or 8 readY = Serial.read(); // y offset while (readY > 16) { readY += 16; } // hacky shit to deal with negative numbers from rotation readY &= 0xF8; // floor the offset to 0 or 8 for (y = 0; y < 8; y++) { // each i will be a row intensity = Serial.read(); // read one byte of 8 bits on/off for (x = 0; x < 8; x++) { // for 8 LEDs on a row if ((intensity >> x) & 0x01) { // if intensity bit set, light led full brightness setGridLed(readX + x, readY + y, 15); } else { setGridLed(readX + x, readY + y, 0); } } } break; case 0x15: // /prefix/led/row x y d readX = Serial.read(); // led-grid / set row while (readX > 16) { readX += 16; } // hacky shit to deal with negative numbers from rotation readX &= 0xF8; // floor the offset to 0 or 8 readY = Serial.read(); // intensity = Serial.read(); // read one byte of 8 bits on/off for (x = 0; x < 8; x++) { // for the next 8 lights in row if ((intensity >> x) & 0x01) { // if intensity bit set, light led full brightness setGridLed(readX + x, readY, 15); } else { setGridLed(readX + x, readY, 0); } } break; case 0x16: // /prefix/led/col x y d readX = Serial.read(); // led-grid / column set readY = Serial.read(); while (readY > 16) { readY += 16; } // hacky shit to deal with negative numbers from rotation readY &= 0xF8; // floor the offset to 0 or 8 intensity = Serial.read(); // read one byte of 8 bits on/off for (y = 0; y < 8; y++) { // for the next 8 lights in column if ((intensity >> y) & 0x01) { // if intensity bit set, light led full brightness setGridLed(readX, readY + y, 15); } else { setGridLed(readX, readY + y, 0); } } break; case 0x17: // /prefix/led/intensity i intensity = Serial.read(); // set brightness for entire grid // this is probably not right setAllLEDs(intensity); break; case 0x18: // /prefix/led/level/set x y i readX = Serial.read(); // led-grid / set LED intensity readY = Serial.read(); // read the x and y coordinates intensity = Serial.read(); // read the intensity setGridLed(readX, readY, intensity); break; case 0x19: // /prefix/led/level/all s intensity = Serial.read(); // set all leds setAllLEDs(intensity); break; case 0x1A: // /prefix/led/level/map x y d[64] // set 8x8 block readX = Serial.read(); // x offset while (readX > 16) { readX += 16; } // hacky shit to deal with negative numbers from rotation readX &= 0xF8; // floor the offset to 0 or 8 readY = Serial.read(); // y offset while (readY > 16) { readY += 16; } // hacky shit to deal with negative numbers from rotation readY &= 0xF8; // floor the offset to 0 or 8 z = 0; for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) { if (z % 2 == 0) { intensity = Serial.read(); if (((intensity >> 4) & 0x0F) > variMonoThresh) { // even bytes, use upper nybble setGridLed(readX + x, readY + y, (intensity >> 4) & 0x0F); } else { setGridLed(readX + x, readY + y, 0); } } else { if ((intensity & 0x0F) > variMonoThresh) { // odd bytes, use lower nybble setGridLed(readX + x, readY + y, intensity & 0x0F); } else { setGridLed(readX + x, readY + y, 0); } } z++; } } /* } else { for (int q = 0; q<32; q++){ Serial.read(); } }*/ break; case 0x1B: // /prefix/led/level/row x y d[8] readX = Serial.read(); // x offset while (readX > 16) { readX += 16; } // hacky shit to deal with negative numbers from rotation readX &= 0xF8; // floor the offset to 0 or 8 readY = Serial.read(); // y offset while (readY > 16) { readY += 16; } // hacky shit to deal with negative numbers from rotation readY &= 0xF8; // floor the offset to 0 or 8 for (x = 0; x < 8; x++) { if (x % 2 == 0) { intensity = Serial.read(); if ((intensity >> 4 & 0x0F) > variMonoThresh) { // even bytes, use upper nybble setGridLed(readX + x, readY, (intensity >> 4) & 0x0F); } else { setGridLed(readX + x, readY, 0); } } else { if ((intensity & 0x0F) > variMonoThresh) { // odd bytes, use lower nybble setGridLed(readX + x, readY, intensity & 0x0F); } else { setGridLed(readX + x, readY, 0); } } } break; case 0x1C: // /prefix/led/level/col x y d[8] readX = Serial.read(); // x offset while (readX > 16) { readX += 16; } // hacky shit to deal with negative numbers from rotation readX &= 0xF8; // floor the offset to 0 or 8 readY = Serial.read(); // y offset while (readY > 16) { readY += 16; } // hacky shit to deal with negative numbers from rotation readY &= 0xF8; // floor the offset to 0 or 8 for (y = 0; y < 8; y++) { if (y % 2 == 0) { intensity = Serial.read(); if ((intensity >> 4 & 0x0F) > variMonoThresh) { // even bytes, use upper nybble setGridLed(readX, readY + y, (intensity >> 4) & 0x0F); } else { setGridLed(readX, readY + y, 0); } } else { if ((intensity & 0x0F) > variMonoThresh) { // odd bytes, use lower nybble setGridLed(readX, readY + y, intensity & 0x0F); } else { setGridLed(readX, readY + y, 0); } } } break; // 0x20 and 0x21 are for a Key inputs (grid) - see readKeys() function case 0x20: /* 0x20 key-grid / key up bytes: 3 structure: [0x20, x, y] description: key up at (x,y) */ gridKeyX = Serial.read(); gridKeyY = Serial.read(); addGridEvent(gridKeyX, gridKeyY, 0); /* Serial.print("grid key: "); Serial.print(gridKeyX); Serial.print(" "); Serial.print(gridKeyY); Serial.print(" up - "); */ break; case 0x21: /* 0x21 key-grid / key down bytes: 3 structure: [0x21, x, y] description: key down at (x,y) */ gridKeyX = Serial.read(); gridKeyY = Serial.read(); addGridEvent(gridKeyX, gridKeyY, 1); /* Serial.print("grid key: "); Serial.print(gridKeyX); Serial.print(" "); Serial.print(gridKeyY); Serial.print(" dn - "); */ break; // 0x5x are encoder case 0x50: // bytes: 3 // structure: [0x50, n, d] // n = encoder number // 0-255 // d = delta // (-128)-127 (two's comp 8 bit) // description: encoder position change index = Serial.read(); delta = Serial.read(); addArcEvent(index, delta); /* Serial.print("Encoder: "); Serial.print(index); Serial.print(" : "); Serial.print(delta); Serial.println(); */ break; case 0x51: // /prefix/enc/key n (key up) // Serial.println("0x51"); n = Serial.read(); /* Serial.print("key: "); Serial.print(n); Serial.println(" up"); */ // bytes: 2 // structure: [0x51, n] // n = encoder number // 0-255 // description: encoder switch up break; case 0x52: // /prefix/enc/key n (key down) // Serial.println("0x52"); n = Serial.read(); /* Serial.print("key: "); Serial.print(n); Serial.println(" down"); */ // bytes: 2 // structure: [0x52, n] // n = encoder number // 0-255 // description: encoder switch down break; case 0x80: // tilt / set active { uint8_t sensor = Serial.read(); uint8_t active = Serial.read(); setTiltActive(sensor, active == 1); // send Serial.write((uint8_t)0x80); Serial.write(sensor); Serial.write(active); } break; case 0x81: // tilt data request { uint8_t sensor = Serial.read(); if (sensor < 4 && tiltActive[sensor]) { // recent data send sendTiltEvent(sensor, lastTiltX[sensor], lastTiltY[sensor], lastTiltZ[sensor]); } } break; // 0x90 variable 64 LED ring case 0x90: //pattern: /prefix/ring/set n x a //desc: set led x of ring n to value a //args: n = ring number // x = led number // a = value (0-15) //serial: [0x90, n, x, a] readN = Serial.read(); readX = Serial.read(); readA = Serial.read(); //led_array[readN][readX] = readA; setArcLed(readN, readX, readA); break; case 0x91: //pattern: /prefix/ring/all n a //desc: set all leds of ring n to a //args: n = ring number // a = value //serial: [0x91, n, a] readN = Serial.read(); readA = Serial.read(); for (int q = 0; q < 64; q++) { setArcLed(readN, q, readA); //led_array[readN][q]=readA; } break; case 0x92: //pattern: /prefix/ring/map n d[32] //desc: set leds of ring n to array d //args: n = ring number // d[32] = 64 states, 4 bit values, in 32 consecutive bytes // d[0] (0:3) value 0 // d[0] (4:7) value 1 // d[1] (0:3) value 2 // .... // d[31] (0:3) value 62 // d[31] (4:7) value 63 //serial: [0x92, n d[32]] readN = Serial.read(); for (y = 0; y < 64; y++) { if (y % 2 == 0) { intensity = Serial.read(); if ((intensity >> 4 & 0x0F) > 0) { // even bytes, use upper nybble //led_array[readN][y] = (intensity >> 4 & 0x0F); setArcLed(readN, y, (intensity >> 4 & 0x0F)); } else { //led_array[readN][y]=0; setArcLed(readN, y, 0); } } else { if ((intensity & 0x0F) > 0) { // odd bytes, use lower nybble //led_array[readN][y] = (intensity & 0x0F); setArcLed(readN, y, (intensity & 0x0F)); } else { //led_array[readN][y]=0; setArcLed(readN, y, 0); } } } break; case 0x93: //pattern: /prefix/ring/range n x1 x2 a //desc: set leds inclusive from x1 and x2 of ring n to a //args: n = ring number // x1 = starting position // x2 = ending position // a = value //serial: [0x93, n, x1, x2, a] readN = Serial.read(); readX = Serial.read(); // x1 readY = Serial.read(); // x2 readA = Serial.read(); //memset(led_array[readN],0,sizeof(led_array[readN])); if (readX < readY) { for (y = readX; y < readY; y++) { //led_array[readN][y] = readA; setArcLed(readN, y, readA); } } else { // wrapping? for (y = readX; y < 64; y++) { //led_array[readN][y] = readA; setArcLed(readN, y, readA); } for (x = 0; x < readY; x++) { //led_array[readN][x] = readA; setArcLed(readN, y, readA); } } //note: set range x1-x2 (inclusive) to a. wrapping supported, ie. set range 60,4 would set values 60,61,62,63,0,1,2,3,4. // always positive direction sweep. ie. 4,10 = 4,5,6,7,8,9,10 whereas 10,4 = 10,11,12,13...63,0,1,2,3,4 break; default: break; } } void MonomeEventQueue::addGridEvent(uint8_t x, uint8_t y, uint8_t pressed) { if (gridEventCount >= MAXEVENTCOUNT) return; uint8_t ind = (gridFirstEvent + gridEventCount) % MAXEVENTCOUNT; gridEvents[ind].x = x; gridEvents[ind].y = y; gridEvents[ind].pressed = pressed; gridEventCount++; } bool MonomeEventQueue::gridEventAvailable() { return gridEventCount > 0; } MonomeGridEvent MonomeEventQueue::readGridEvent() { if (gridEventCount == 0) return emptyGridEvent; gridEventCount--; uint8_t index = gridFirstEvent; gridFirstEvent = (gridFirstEvent + 1) % MAXEVENTCOUNT; return gridEvents[index]; } void MonomeEventQueue::addArcEvent(uint8_t index, int8_t delta) { if (arcEventCount >= MAXEVENTCOUNT) return; uint8_t ind = (arcFirstEvent + arcEventCount) % MAXEVENTCOUNT; arcEvents[ind].index = index; arcEvents[ind].delta = delta; arcEventCount++; } bool MonomeEventQueue::arcEventAvailable() { return arcEventCount > 0; } MonomeArcEvent MonomeEventQueue::readArcEvent() { if (arcEventCount == 0) return emptyArcEvent; arcEventCount--; uint8_t index = arcFirstEvent; arcFirstEvent = (arcFirstEvent + 1) % MAXEVENTCOUNT; return arcEvents[index]; } void MonomeEventQueue::sendArcDelta(uint8_t index, int8_t delta) { /* Serial.print("Encoder:"); Serial.print(index); Serial.print(" "); Serial.print(delta); Serial.println(" "); */ Serial.write((uint8_t)0x50); Serial.write((uint8_t)index); Serial.write((int8_t)delta); /* byte buf[3]; buf[0] = 0x50; buf[1] = index; buf[2] = delta; Serial.write(buf, sizeof(buf)); */ } void MonomeEventQueue::sendArcKey(uint8_t index, uint8_t pressed) { /* Serial.print("key:"); Serial.print(index); Serial.print(" "); Serial.println(pressed); */ uint8_t buf[2]; if (pressed == 1) { buf[0] = 0x52; } else { buf[0] = 0x51; } buf[1] = index; Serial.write(buf, 2); } void MonomeEventQueue::sendGridKey(uint8_t x, uint8_t y, uint8_t pressed) { uint8_t buf[2]; if (pressed == 1) { buf[0] = 0x21; } else { buf[0] = 0x20; } Serial.write((uint8_t)buf[0]); Serial.write((uint8_t)x); Serial.write((uint8_t)y); }