Skip to content

Instantly share code, notes, and snippets.

@abachman
Last active May 13, 2017 01:07
Show Gist options
  • Save abachman/2138eeacc49b6333912af2f6940c8200 to your computer and use it in GitHub Desktop.
Save abachman/2138eeacc49b6333912af2f6940c8200 to your computer and use it in GitHub Desktop.
Untztrument Pretty Lights
// Untztrument: https://www.adafruit.com/product/1929
// Arduino 101: https://www.adafruit.com/product/3033
// requires the Adafruit Trellis and Intel Curie (Arduino 101) board support, both available through the Arduino app.
#include <Wire.h>
#include <Adafruit_Trellis.h>
#include <CurieBLE.h>
BLEPeripheral blePeripheral; // BLE Peripheral Device (the board you're programming)
BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // BLE LED Service
// BLE LED Switch Characteristic - custom 128-bit UUID, read and writable by central
BLECharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite, 8);
// Basic Trellis setup in the 2x2 Untztrument format
#define NUMTRELLIS 4
Adafruit_Trellis matrix[NUMTRELLIS] = {
Adafruit_Trellis(), Adafruit_Trellis(),
Adafruit_Trellis(), Adafruit_Trellis()
};
Adafruit_TrellisSet trellis = Adafruit_TrellisSet(
&matrix[0], &matrix[1], &matrix[2], &matrix[3]
);
#define numKeys (NUMTRELLIS * 16)
// convert from Untz's 2x2 grid to a single large grid
const int UNTZ_TRANSLATE[64] = {
0, 1, 2, 3, 16, 17, 18, 19,
4, 5, 6, 7, 20, 21, 22, 23,
8, 9, 10, 11, 24, 25, 26, 27,
12, 13, 14, 15, 28, 29, 30, 31,
32, 33, 34, 35, 48, 49, 50, 51,
36, 37, 38, 39, 52, 53, 54, 55,
40, 41, 42, 43, 56, 57, 58, 59,
44, 45, 46, 47, 60, 61, 62, 63
};
void setup() {
Serial.begin(9600);
// set advertised local name and service UUID:
blePeripheral.setLocalName("Untz Screen");
blePeripheral.setAdvertisedServiceUuid(ledService.uuid());
// add service and characteristic:
blePeripheral.addAttribute(ledService);
blePeripheral.addAttribute(switchCharacteristic);
// set the initial value for the characeristic:
const unsigned char defaultVal[8] = { 0,0,0,0,0,0,0.0 };
switchCharacteristic.setValue(defaultVal, 8);
// begin advertising BLE service:
blePeripheral.begin();
Serial.println("BLE LED Peripheral");
// begin() with the addresses of each panel.
// I find it easiest if the addresses are in order.
trellis.begin(0x70, 0x71, 0x72, 0x73);
// light up all the LEDs in order
for (uint8_t i=0; i<numKeys; i++) {
trellis.setLED(UNTZ_TRANSLATE[i]);
trellis.writeDisplay();
delay(10);
}
// then turn them off
for (uint8_t i=0; i<numKeys; i++) {
trellis.clrLED(UNTZ_TRANSLATE[i]);
trellis.writeDisplay();
delay(10);
}
}
void loop() {
// listen for BLE peripherals to connect:
BLECentral central = blePeripheral.central();
// if a central is connected to peripheral:
if (central) {
Serial.print("Connected to central: ");
// print the central's MAC address:
Serial.println(central.address());
// while the central is still connected to peripheral:
while (central.connected()) {
// if the remote device wrote to the characteristic,
// use the value to control the LEDs:
if (switchCharacteristic.written()) {
// get the BLE Characteristic as an array of char values, we only care about the first 8
char *image_val = (char *)switchCharacteristic.value();
for (uint8_t r=0; r < 8; r++) {
char row = image_val[r];
for (uint8_t c=0; c < 8; c++) {
if ((1 << c) & row) {
trellis.setLED(UNTZ_TRANSLATE[(c * 8) + r]);
} else {
trellis.clrLED(UNTZ_TRANSLATE[(c * 8) + r]);
}
}
}
trellis.writeDisplay();
}
}
// when the central disconnects, print it out:
Serial.print(F("Disconnected from central: "));
Serial.println(central.address());
// clear the display
for (uint8_t i=0; i<numKeys; i++) {
trellis.clrLED(i);
}
trellis.writeDisplay();
}
}
/*
Original code retrieved from https://www.arduino.cc/en/Reference/BLEPeripheralAddAttribute
Copyright (c) 2016 Intel Corporation. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
var noble = require('noble');
var untzUuid = 'd5d5cb20f57044d5b5268955ba3e84e6';
var ledServiceUuid = '19b10000e8f2537e4f6cd104768a1214';
// positioned upper left, right shift (>>) 4 and & to combine
var chars = {
0: Buffer.from([0x70, 0x50, 0x50, 0x50, 0x70, 0x00, 0x00, 0x00]),
1: Buffer.from([0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00]),
2: Buffer.from([0x70, 0x10, 0x70, 0x40, 0x70, 0x00, 0x00, 0x00]),
3: Buffer.from([0x70, 0x10, 0x30, 0x10, 0x70, 0x00, 0x00, 0x00]),
4: Buffer.from([0x50, 0x50, 0x70, 0x10, 0x10, 0x00, 0x00, 0x00]),
5: Buffer.from([0x70, 0x40, 0x70, 0x10, 0x70, 0x00, 0x00, 0x00]),
6: Buffer.from([0x60, 0x40, 0x70, 0x50, 0x70, 0x00, 0x00, 0x00]),
7: Buffer.from([0x70, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, 0x00]),
8: Buffer.from([0x70, 0x50, 0x70, 0x50, 0x70, 0x00, 0x00, 0x00]),
9: Buffer.from([0x70, 0x50, 0x70, 0x10, 0x70, 0x00, 0x00, 0x00])
}
// pack the last two digits of the given number into an 8-byte buffer as pixel data
function digits(n) {
const r = n % 10;
const l = (n - r) / 10;
console.log('from', n, l, r);
const rc = chars[r];
const lc = chars[l];
const out = Buffer.alloc(8);
for (let i=0; i < 8; i++) {
out.writeUInt8(lc[i] | (rc[i] >> 4), i);
}
console.log("WRITE", out);
return out;
}
function onDiscover(peripheral) {
console.log("FOUND", peripheral.uuid)
if (peripheral.uuid === untzUuid) {
// ready to go!
noble.stopScanning();
}
peripheral.connect(function (err) {
if (err) {
console.error(err);
}
peripheral.discoverServices([ledServiceUuid], function (err, services) {
services.forEach(function(service) {
//
// This must be the service we were looking for.
//
console.log('found service:', service.uuid);
if (err) {
console.error(err);
}
console.log('found service:', services.uuid);
service.discoverCharacteristics([], function(err, characteristics) {
characteristics.forEach(function(characteristic) {
//
// Loop through each characteristic and match them to the
// UUIDs that we know about.
//
console.log('found characteristic:', characteristic.uuid);
var crust = Buffer.alloc(8);
var name = Buffer.from([ 0x70, 0x50, 0x76, 0x55, 0x56, 0x05, 0x06, 0x00 ]);
var face = Buffer.from([ 0x66, 0x66, 0x00, 0x81, 0xff, 0x99, 0x42, 0x3c ]);
var send_num = 0;
setInterval(function () {
if (send_num % 100 === 0) {
characteristic.write(name, false);
} else if (send_num % 100 === 10) {
characteristic.write(face, false);
} else {
characteristic.write(digits(send_num % 100), false);
}
send_num += 1;
}, 1000);
})
})
})
})
})
}
noble.on('discover', onDiscover);
noble.on('stateChange', function(state) {
console.log("stateChange", state)
if (state === 'poweredOn') {
noble.startScanning();
} else {
noble.stopScanning();
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment