Refactored for teensy 4.0, xEvi hardware
- Switched to platformio, ino -> cpp - MPRLS for pressure sensor - Added basic ICM support - Removed widi, battery, other features not supported in xEvi - Removed legacy options/processing - Added LED strip support - Added encoder support - Reworked menu code to use encoders/be more flexible
This commit is contained in:
parent
c58c3f9e46
commit
01d193c9b3
92 changed files with 69119 additions and 73272 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -1,3 +1,3 @@
|
|||
.vscode/ipch
|
||||
*.o
|
||||
.DS_STORE
|
||||
.vscode/ipch
|
||||
*.o
|
||||
.DS_STORE
|
||||
|
|
|
|||
8
.gitmodules
vendored
8
.gitmodules
vendored
|
|
@ -1,4 +1,4 @@
|
|||
[submodule "simulation/imgui"]
|
||||
path = simulation/imgui
|
||||
url = https://github.com/ocornut/imgui.git
|
||||
ignore = untracked
|
||||
[submodule "simulation/imgui"]
|
||||
path = simulation/imgui
|
||||
url = https://github.com/ocornut/imgui.git
|
||||
ignore = untracked
|
||||
|
|
|
|||
1348
LICENSE.md
1348
LICENSE.md
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
5
NuEVI/.gitignore
vendored
Normal file
5
NuEVI/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
10
NuEVI/.vscode/extensions.json
vendored
Normal file
10
NuEVI/.vscode/extensions.json
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"ms-vscode.cpptools-extension-pack"
|
||||
]
|
||||
}
|
||||
9
NuEVI/.vscode/settings.json
vendored
Normal file
9
NuEVI/.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"type_traits": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"ostream": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"array": "cpp"
|
||||
}
|
||||
}
|
||||
2356
NuEVI/NuEVI.ino
2356
NuEVI/NuEVI.ino
File diff suppressed because it is too large
Load diff
|
|
@ -1,593 +0,0 @@
|
|||
#include <Arduino.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include <Adafruit_MPR121.h>
|
||||
|
||||
#include "menu.h"
|
||||
#include "numenu.h"
|
||||
#include "globals.h"
|
||||
#include "config.h"
|
||||
#include "hardware.h"
|
||||
#include "settings.h"
|
||||
|
||||
//***********************************************************
|
||||
|
||||
extern Adafruit_SSD1306 display;
|
||||
#if defined(NURAD)
|
||||
extern Adafruit_MPR121 touchSensorRH;
|
||||
extern Adafruit_MPR121 touchSensorLH;
|
||||
extern Adafruit_MPR121 touchSensorRollers;
|
||||
#else
|
||||
extern Adafruit_MPR121 touchSensor;
|
||||
#endif
|
||||
extern byte cursorNow;
|
||||
#if defined(NURAD)
|
||||
extern int calOffsetRollers[6];
|
||||
extern int calOffsetRH[12];
|
||||
extern int calOffsetLH[12];
|
||||
#endif
|
||||
|
||||
//***********************************************************
|
||||
// Variables used for the adjust menu
|
||||
static byte forcePix;
|
||||
|
||||
static uint16_t pos1;
|
||||
static uint16_t pos2;
|
||||
|
||||
static int16_t adjustOption;
|
||||
static int16_t adjustCurrent;
|
||||
|
||||
static int16_t sensorPixelPos1 = -1;
|
||||
static int16_t sensorPixelPos2 = -1;
|
||||
|
||||
static bool refreshScreen;
|
||||
|
||||
//***********************************************************
|
||||
|
||||
static void breathSave(const AdjustMenuEntry& e) {
|
||||
writeSetting(BREATH_THR_ADDR, *e.entries[0].value);
|
||||
writeSetting(BREATH_MAX_ADDR, *e.entries[1].value);
|
||||
}
|
||||
|
||||
const AdjustMenuEntry breathAdjustMenu = {
|
||||
"BREATH",
|
||||
{
|
||||
{ &breathThrVal, breathLoLimit, breathHiLimit },
|
||||
{ &breathMaxVal, breathLoLimit, breathHiLimit }
|
||||
},
|
||||
breathSave
|
||||
};
|
||||
|
||||
static void portamentoSave(const AdjustMenuEntry& e) {
|
||||
writeSetting(PORTAM_THR_ADDR, *e.entries[0].value);
|
||||
writeSetting(PORTAM_MAX_ADDR, *e.entries[1].value);
|
||||
}
|
||||
|
||||
const AdjustMenuEntry portamentoAdjustMenu = {
|
||||
"BITE",
|
||||
{
|
||||
{ &portamThrVal, portamLoLimit, portamHiLimit },
|
||||
{ &portamMaxVal, portamLoLimit, portamHiLimit }
|
||||
},
|
||||
portamentoSave
|
||||
};
|
||||
|
||||
static void pbSave(const AdjustMenuEntry& e) {
|
||||
writeSetting(PITCHB_THR_ADDR, *e.entries[0].value);
|
||||
writeSetting(PITCHB_MAX_ADDR, *e.entries[1].value);
|
||||
}
|
||||
|
||||
const AdjustMenuEntry pitchBendAdjustMenu = {
|
||||
"BEND",
|
||||
{
|
||||
{ &pitchbThrVal, pitchbLoLimit, pitchbHiLimit },
|
||||
{ &pitchbMaxVal, pitchbLoLimit, pitchbHiLimit }
|
||||
},
|
||||
pbSave
|
||||
};
|
||||
|
||||
static void extracSave(const AdjustMenuEntry& e) {
|
||||
writeSetting(EXTRAC_THR_ADDR, *e.entries[0].value);
|
||||
writeSetting(EXTRAC_MAX_ADDR, *e.entries[1].value);
|
||||
}
|
||||
|
||||
const AdjustMenuEntry extraSensorAdjustMenu = {
|
||||
"LIP/EC",
|
||||
{
|
||||
{ &extracThrVal, extracLoLimit, extracHiLimit },
|
||||
{ &extracMaxVal, extracLoLimit, extracHiLimit }
|
||||
},
|
||||
extracSave
|
||||
};
|
||||
|
||||
|
||||
static void ctouchThrSave(const AdjustMenuEntry& e) {
|
||||
writeSetting(CTOUCH_THR_ADDR, *e.entries[0].value);
|
||||
}
|
||||
|
||||
const AdjustMenuEntry ctouchAdjustMenu = {
|
||||
"TOUCH",
|
||||
{
|
||||
{ &ctouchThrVal, ctouchLoLimit, ctouchHiLimit },
|
||||
{ nullptr, 0, 0 }
|
||||
},
|
||||
ctouchThrSave
|
||||
};
|
||||
|
||||
|
||||
static void leverSave(const AdjustMenuEntry& e) {
|
||||
writeSetting(LEVER_THR_ADDR, *e.entries[0].value);
|
||||
writeSetting(LEVER_MAX_ADDR, *e.entries[1].value);
|
||||
}
|
||||
|
||||
const AdjustMenuEntry leverAdjustMenu = {
|
||||
"LEVER",
|
||||
{
|
||||
{ &leverThrVal, leverLoLimit, leverHiLimit },
|
||||
{ &leverMaxVal, leverLoLimit, leverHiLimit }
|
||||
},
|
||||
leverSave
|
||||
};
|
||||
|
||||
|
||||
const AdjustMenuEntry* adjustMenuEntries[] = {
|
||||
&breathAdjustMenu,
|
||||
&portamentoAdjustMenu,
|
||||
&pitchBendAdjustMenu,
|
||||
&extraSensorAdjustMenu,
|
||||
&ctouchAdjustMenu,
|
||||
&leverAdjustMenu,
|
||||
};
|
||||
|
||||
static const int numAdjustEntries = ARR_LEN(adjustMenuEntries);
|
||||
|
||||
//***********************************************************
|
||||
|
||||
|
||||
|
||||
void autoCalSelected() {
|
||||
int calRead;
|
||||
int calReadNext;
|
||||
// NuRAD/NuEVI sensor calibration
|
||||
// Extra Controller
|
||||
if(adjustOption == 3) {
|
||||
calRead = touchRead(extraPin);
|
||||
extracThrVal = constrain(calRead+200, extracLoLimit, extracHiLimit);
|
||||
extracMaxVal = constrain(extracThrVal+600, extracLoLimit, extracHiLimit);
|
||||
writeSetting(EXTRAC_THR_ADDR, extracThrVal);
|
||||
writeSetting(EXTRAC_MAX_ADDR, extracMaxVal);
|
||||
}
|
||||
// Breath sensor
|
||||
if(adjustOption == 0) {
|
||||
calRead = analogRead(breathSensorPin);
|
||||
breathThrVal = constrain(calRead+200, breathLoLimit, breathHiLimit);
|
||||
breathMaxVal = constrain(breathThrVal+1500, breathLoLimit, breathHiLimit);
|
||||
writeSetting(BREATH_THR_ADDR, breathThrVal);
|
||||
writeSetting(BREATH_MAX_ADDR, breathMaxVal);
|
||||
}
|
||||
// Pitch Bend
|
||||
if(adjustOption == 2) {
|
||||
calRead = touchRead(pbUpPin);
|
||||
calReadNext = touchRead(pbDnPin);
|
||||
if (calReadNext > calRead) calRead = calReadNext; //use highest value
|
||||
pitchbThrVal = constrain(calRead+200, pitchbLoLimit, pitchbHiLimit);
|
||||
pitchbMaxVal = constrain(pitchbThrVal+800, pitchbLoLimit, pitchbHiLimit);
|
||||
writeSetting(PITCHB_THR_ADDR, pitchbThrVal);
|
||||
writeSetting(PITCHB_MAX_ADDR, pitchbMaxVal);
|
||||
}
|
||||
// Lever
|
||||
if(adjustOption == 5) {
|
||||
#if defined(SEAMUS)
|
||||
calRead = touchRead(vibratoPin);
|
||||
#else
|
||||
calRead = 3000-touchRead(vibratoPin);
|
||||
#endif
|
||||
leverThrVal = constrain(calRead+60, leverLoLimit, leverHiLimit);
|
||||
leverMaxVal = constrain(calRead+120, leverLoLimit, leverHiLimit);
|
||||
writeSetting(LEVER_THR_ADDR, leverThrVal);
|
||||
writeSetting(LEVER_MAX_ADDR, leverMaxVal);
|
||||
}
|
||||
#if defined(NURAD) // NuRAD sensor calibration
|
||||
// Bite Pressure sensor
|
||||
if(adjustOption == 1) {
|
||||
calRead = analogRead(bitePressurePin);
|
||||
portamThrVal = constrain(calRead+300, portamLoLimit, portamHiLimit);
|
||||
portamMaxVal = constrain(portamThrVal+600, portamLoLimit, portamHiLimit);
|
||||
writeSetting(PORTAM_THR_ADDR, portamThrVal);
|
||||
writeSetting(PORTAM_MAX_ADDR, portamMaxVal);
|
||||
}
|
||||
// Touch sensors
|
||||
if(adjustOption == 4) {
|
||||
calRead = ctouchHiLimit;
|
||||
for (byte i = 0; i < 6; i++) {
|
||||
calReadNext = touchSensorRollers.filteredData(i) * (300-calOffsetRollers[i])/300;
|
||||
if (calReadNext < calRead) calRead = calReadNext; //use lowest value
|
||||
}
|
||||
for (byte i = 0; i < 12; i++) {
|
||||
calReadNext = touchSensorRH.filteredData(i) * (300-calOffsetRH[i])/300;
|
||||
if (calReadNext < calRead) calRead = calReadNext; //use lowest value
|
||||
}
|
||||
for (byte i = 0; i < 12; i++) {
|
||||
calReadNext = touchSensorLH.filteredData(i) * (300-calOffsetLH[i])/300;
|
||||
if (calReadNext < calRead) calRead = calReadNext; //use lowest value
|
||||
}
|
||||
ctouchThrVal = constrain(calRead-20, ctouchLoLimit, ctouchHiLimit);
|
||||
touch_Thr = map(ctouchThrVal,ctouchHiLimit,ctouchLoLimit,ttouchLoLimit,ttouchHiLimit);
|
||||
writeSetting(CTOUCH_THR_ADDR, ctouchThrVal);
|
||||
}
|
||||
#else // NuEVI sensor calibration
|
||||
// Bite sensor
|
||||
if(adjustOption == 1) {
|
||||
if (digitalRead(biteJumperPin)){ //PBITE (if pulled low with jumper, pressure sensor is used instead of capacitive bite sensing)
|
||||
// Capacitive sensor
|
||||
calRead = touchRead(bitePin);
|
||||
portamThrVal = constrain(calRead+200, portamLoLimit, portamHiLimit);
|
||||
portamMaxVal = constrain(portamThrVal+600, portamLoLimit, portamHiLimit);
|
||||
writeSetting(PORTAM_THR_ADDR, portamThrVal);
|
||||
writeSetting(PORTAM_MAX_ADDR, portamMaxVal);
|
||||
} else {
|
||||
// Pressure sensor
|
||||
calRead = analogRead(bitePressurePin);
|
||||
portamThrVal = constrain(calRead+300, portamLoLimit, portamHiLimit);
|
||||
portamMaxVal = constrain(portamThrVal+600, portamLoLimit, portamHiLimit);
|
||||
writeSetting(PORTAM_THR_ADDR, portamThrVal);
|
||||
writeSetting(PORTAM_MAX_ADDR, portamMaxVal);
|
||||
}
|
||||
}
|
||||
// Touch sensors
|
||||
if(adjustOption == 4) {
|
||||
calRead = ctouchHiLimit;
|
||||
for (byte i = 0; i < 12; i++) {
|
||||
calReadNext = touchSensor.filteredData(i);
|
||||
if (calReadNext < calRead) calRead = calReadNext; //use lowest value
|
||||
}
|
||||
calReadNext=map(touchRead(halfPitchBendKeyPin),ttouchLoLimit,ttouchHiLimit,ctouchHiLimit,ctouchLoLimit);
|
||||
if (calReadNext < calRead) calRead = calReadNext; //use lowest value
|
||||
calReadNext=map(touchRead(specialKeyPin),ttouchLoLimit,ttouchHiLimit,ctouchHiLimit,ctouchLoLimit);
|
||||
if (calReadNext < calRead) calRead = calReadNext; //use lowest value
|
||||
ctouchThrVal = constrain(calRead-20, ctouchLoLimit, ctouchHiLimit);
|
||||
touch_Thr = map(ctouchThrVal,ctouchHiLimit,ctouchLoLimit,ttouchLoLimit,ttouchHiLimit);
|
||||
writeSetting(CTOUCH_THR_ADDR, ctouchThrVal);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//***********************************************************
|
||||
|
||||
static void drawAdjCursor(byte color) {
|
||||
display.drawTriangle(16,4,20,4,18,1,color);
|
||||
display.drawTriangle(16,6,20,6,18,9,color);
|
||||
}
|
||||
|
||||
static void drawAdjustFrame(int line) {
|
||||
display.drawLine(25,line,120,line,WHITE); // Top line
|
||||
display.drawLine(25,line+12,120,line+12,WHITE); // Bottom line
|
||||
|
||||
display.drawLine(25,line+1,25,line+2,WHITE);
|
||||
display.drawLine(120,line+1,120,line+2,WHITE);
|
||||
|
||||
display.drawLine(120,line+10,120,line+11,WHITE);
|
||||
display.drawLine(25,line+10,25,line+11,WHITE);
|
||||
}
|
||||
|
||||
static void drawAdjustBase(const char* title, bool all) {
|
||||
display.clearDisplay();
|
||||
|
||||
drawAdjustFrame(17);
|
||||
|
||||
// sensor marker lines.
|
||||
display.drawLine(25,36,25,40,WHITE);
|
||||
display.drawLine(120,36,120,40,WHITE);
|
||||
|
||||
display.setTextSize(1);
|
||||
display.setCursor(25,2);
|
||||
display.println(title);
|
||||
|
||||
display.setCursor(0,20);
|
||||
display.println("THR");
|
||||
display.setCursor(0,35);
|
||||
display.println("SNS");
|
||||
|
||||
|
||||
if(all) {
|
||||
drawAdjustFrame(47);
|
||||
display.setCursor(0,50);
|
||||
display.println("MAX");
|
||||
}
|
||||
cursorNow = WHITE;
|
||||
drawAdjCursor(WHITE);
|
||||
}
|
||||
|
||||
static void drawLineCursor(uint16_t hPos, uint16_t vPos, int color) {
|
||||
display.drawLine(hPos, vPos,hPos, vPos+6, color);
|
||||
}
|
||||
|
||||
static bool updateAdjustLineCursor(uint32_t timeNow, uint16_t hPos, uint16_t vPos ) {
|
||||
if ((timeNow - cursorBlinkTime) > cursorBlinkInterval) {
|
||||
if (cursorNow == WHITE) cursorNow = BLACK; else cursorNow = WHITE;
|
||||
drawLineCursor(hPos, vPos, cursorNow);
|
||||
cursorBlinkTime = timeNow;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void drawAdjustMenu(const AdjustMenuEntry *menu) {
|
||||
|
||||
bool haveSecondValue = menu->entries[1].value != nullptr;
|
||||
drawAdjustBase( menu->title, haveSecondValue );
|
||||
|
||||
pos1 = map( *menu->entries[0].value, menu->entries[0].limitLow, menu->entries[0].limitHigh, 27, 119);
|
||||
display.drawLine( pos1, 20, pos1, 26, WHITE );
|
||||
|
||||
if(haveSecondValue) {
|
||||
pos2 = map( *menu->entries[1].value, menu->entries[1].limitLow, menu->entries[1].limitHigh, 27, 119);
|
||||
display.drawLine( pos2, 50, pos2, 56, WHITE );
|
||||
}
|
||||
display.fillRect(64,0,64,9,BLACK);
|
||||
display.setTextSize(1);
|
||||
if(haveSecondValue) {
|
||||
display.setCursor(68,2);
|
||||
display.print(*menu->entries[0].value);
|
||||
display.print("|");
|
||||
display.print(*menu->entries[1].value);
|
||||
} else {
|
||||
display.setCursor(104,2);
|
||||
display.print(*menu->entries[0].value);
|
||||
}
|
||||
}
|
||||
|
||||
//***********************************************************
|
||||
|
||||
static bool updateSensorPixel(int pos, int pos2) {
|
||||
bool update = pos != sensorPixelPos1 || pos2 != sensorPixelPos2;
|
||||
if(update) {
|
||||
display.drawFastHLine(28, 38, 119-28, BLACK); // Clear old line
|
||||
display.drawPixel(pos, 38, WHITE);
|
||||
if( pos2 >= 0) display.drawPixel(pos2, 38, WHITE);
|
||||
|
||||
sensorPixelPos1 = pos;
|
||||
sensorPixelPos2 = pos2;
|
||||
}
|
||||
return update;
|
||||
}
|
||||
|
||||
void plotSensorPixels(){
|
||||
int redraw = 0;
|
||||
|
||||
if(forcePix)
|
||||
sensorPixelPos1 = -1;
|
||||
|
||||
// This is hacky. It depends on the order of items in the adjust menu list.
|
||||
if(adjustOption == 0) {
|
||||
int pos = map(constrain(pressureSensor, breathLoLimit, breathHiLimit), breathLoLimit, breathHiLimit, 28, 118);
|
||||
redraw = updateSensorPixel(pos, -1);
|
||||
}
|
||||
else if(adjustOption == 1) {
|
||||
if (biteJumper) { //PBITE (if pulled low with jumper or if on a NuRAD, use pressure sensor instead of capacitive bite sensor)
|
||||
biteSensor=analogRead(bitePressurePin); // alternative kind bite sensor (air pressure tube and sensor) PBITE
|
||||
} else {
|
||||
biteSensor = touchRead(bitePin); // get sensor data, do some smoothing - SENSOR PIN 17 - PCB PINS LABELED "BITE" (GND left, sensor pin right)
|
||||
}
|
||||
int pos = map(constrain(biteSensor,portamLoLimit,portamHiLimit), portamLoLimit, portamHiLimit, 28, 118);
|
||||
redraw = updateSensorPixel(pos, -1);
|
||||
}
|
||||
else if(adjustOption == 2) {
|
||||
int pos = map(constrain(pbUp, pitchbLoLimit, pitchbHiLimit), pitchbLoLimit, pitchbHiLimit, 28, 118);
|
||||
int pos2 = map(constrain(pbDn, pitchbLoLimit, pitchbHiLimit), pitchbLoLimit, pitchbHiLimit, 28, 118);
|
||||
redraw = updateSensorPixel(pos, pos2);
|
||||
}
|
||||
else if(adjustOption == 3) {
|
||||
int pos = map(constrain(exSensor, extracLoLimit, extracHiLimit), extracLoLimit, extracHiLimit, 28, 118);
|
||||
redraw = updateSensorPixel(pos, -1);
|
||||
}
|
||||
#if defined(NURAD)
|
||||
else if(adjustOption == 4) {
|
||||
display.drawLine(28,37,118,37,BLACK);
|
||||
for (byte i=0; i<12; i++){
|
||||
//int pos = map(constrain(touchSensorRH.filteredData(i) - calOffsetRH[i], ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
|
||||
int pos = map(constrain(touchSensorRH.filteredData(i) * (300-calOffsetRH[i])/300, ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
|
||||
display.drawPixel(pos, 37, WHITE);
|
||||
}
|
||||
display.drawLine(28,38,118,38,BLACK);
|
||||
for (byte i=0; i<12; i++){
|
||||
//int pos = map(constrain(touchSensorLH.filteredData(i) - calOffsetLH[i], ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
|
||||
int pos = map(constrain(touchSensorLH.filteredData(i) * (300-calOffsetLH[i])/300, ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
|
||||
display.drawPixel(pos, 38, WHITE);
|
||||
}
|
||||
display.drawLine(28,39,118,39,BLACK);
|
||||
for (byte i=0; i<6; i++){
|
||||
//int pos = map(constrain(touchSensorRollers.filteredData(i) - calOffsetRollers[i], ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
|
||||
int pos = map(constrain(touchSensorRollers.filteredData(i) * (300-calOffsetRollers[i])/300, ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
|
||||
display.drawPixel(pos, 39, WHITE);
|
||||
}
|
||||
redraw = 1;
|
||||
}
|
||||
#else //NuEVI
|
||||
else if(adjustOption == 4) {
|
||||
display.drawLine(28,39,118,39,BLACK);
|
||||
for (byte i=0; i<12; i++){
|
||||
int pos = map(constrain(touchSensor.filteredData(i), ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
|
||||
display.drawPixel(pos, 39, WHITE);
|
||||
}
|
||||
|
||||
int posRead = map(touchRead(halfPitchBendKeyPin),ttouchLoLimit,ttouchHiLimit,ctouchHiLimit,ctouchLoLimit);
|
||||
int pos = map(constrain(posRead, ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
|
||||
|
||||
posRead = map(touchRead(specialKeyPin),ttouchLoLimit,ttouchHiLimit,ctouchHiLimit,ctouchLoLimit);
|
||||
int pos2 = map(constrain(posRead, ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118);
|
||||
|
||||
updateSensorPixel(pos, pos2);
|
||||
|
||||
redraw = 1;
|
||||
}
|
||||
#endif
|
||||
else if(adjustOption == 5) {
|
||||
#if defined(SEAMUS)
|
||||
int pos = map(constrain(touchRead(vibratoPin), leverLoLimit, leverHiLimit), leverLoLimit, leverHiLimit, 28, 118);
|
||||
#else
|
||||
int pos = map(constrain(3000-touchRead(vibratoPin), leverLoLimit, leverHiLimit), leverLoLimit, leverHiLimit, 28, 118);
|
||||
#endif
|
||||
redraw = updateSensorPixel(pos, -1);
|
||||
}
|
||||
|
||||
|
||||
if (redraw){
|
||||
display.display();
|
||||
}
|
||||
forcePix = 0;
|
||||
}
|
||||
|
||||
//***********************************************************
|
||||
|
||||
static bool drawAdjustBar(uint16_t buttons, int row, const AdjustValue* entry, uint16_t *pos) {
|
||||
bool updated = false;
|
||||
uint16_t step = (entry->limitHigh-entry->limitLow)/92;
|
||||
int val = *entry->value;
|
||||
switch(buttons) {
|
||||
case BTN_UP:
|
||||
val += step;
|
||||
updated = true;
|
||||
break;
|
||||
|
||||
case BTN_DOWN:
|
||||
val -= step;
|
||||
updated = true;
|
||||
break;
|
||||
|
||||
}
|
||||
if(updated) {
|
||||
*entry->value = constrain(val, entry->limitLow, entry->limitHigh);
|
||||
auto p = *pos;
|
||||
display.drawLine(p, row, p, row+6, BLACK);
|
||||
*pos = p = map(*entry->value, entry->limitLow, entry->limitHigh, 27, 119);
|
||||
display.drawLine(p, row, p, row+6, WHITE);
|
||||
cursorNow = BLACK;
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
static bool updateAdjustCursor(uint32_t timeNow) {
|
||||
if ((timeNow - cursorBlinkTime) > cursorBlinkInterval) {
|
||||
if (cursorNow == WHITE) cursorNow = BLACK; else cursorNow = WHITE;
|
||||
drawAdjCursor(cursorNow);
|
||||
cursorBlinkTime = timeNow;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool handleInput(const AdjustMenuEntry *currentMenu, uint32_t timeNow, uint8_t buttons, uint16_t *xpos, int ypos, int index) {
|
||||
bool haveSecondValue = currentMenu->entries[1].value != nullptr;
|
||||
if (buttons) {
|
||||
if (buttons == BTN_DOWN+BTN_UP){
|
||||
display.fillRect(26,35,90,7,BLACK);
|
||||
display.setTextSize(1);
|
||||
display.setTextColor(WHITE);
|
||||
display.setCursor(53,35);
|
||||
display.println("AUTOCAL");
|
||||
display.display();
|
||||
delay(2000);
|
||||
autoCalSelected();
|
||||
display.fillRect(26,35,90,7,BLACK);
|
||||
display.display();
|
||||
drawAdjustMenu(currentMenu);
|
||||
forcePix = 1;
|
||||
plotSensorPixels();
|
||||
} else
|
||||
drawAdjustBar( buttons, ypos, ¤tMenu->entries[index], xpos );
|
||||
|
||||
display.fillRect(64,0,64,9,BLACK);
|
||||
display.setTextSize(1);
|
||||
if(haveSecondValue) {
|
||||
display.setCursor(68,2);
|
||||
display.print(*currentMenu->entries[0].value);
|
||||
display.print("|");
|
||||
display.print(*currentMenu->entries[1].value);
|
||||
} else {
|
||||
display.setCursor(104,2);
|
||||
display.print(*currentMenu->entries[0].value);
|
||||
}
|
||||
|
||||
int last = adjustCurrent;
|
||||
if(buttons == BTN_ENTER) adjustCurrent += 1;
|
||||
else if( buttons == BTN_MENU) adjustCurrent = 0;
|
||||
|
||||
if(last != adjustCurrent) drawLineCursor(*xpos, ypos, WHITE);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return updateAdjustLineCursor(timeNow, *xpos, ypos);
|
||||
}
|
||||
}
|
||||
|
||||
int updateAdjustMenu(uint32_t timeNow, KeyState &input, bool firstRun, bool drawSensor) {
|
||||
bool redraw = false;
|
||||
int result = 0;
|
||||
|
||||
const AdjustMenuEntry *currentMenu = adjustMenuEntries[adjustOption];
|
||||
|
||||
uint8_t buttons = input.changed ? input.current : 0;
|
||||
|
||||
if(firstRun || refreshScreen) {
|
||||
adjustCurrent = 0;
|
||||
refreshScreen = false;
|
||||
drawAdjustMenu(currentMenu);
|
||||
// the sensor pixel stuff should be refactored (to work again)
|
||||
forcePix = 1;
|
||||
sensorPixelPos1 = -1; // Force draw of sensor pixels
|
||||
}
|
||||
|
||||
if(adjustCurrent == 0) {
|
||||
// Currently selecting what option to modify
|
||||
redraw |= updateAdjustCursor(timeNow);
|
||||
|
||||
bool save = false;
|
||||
if( buttons == BTN_DOWN ) {
|
||||
adjustOption += 1;
|
||||
refreshScreen = 1;
|
||||
save = true;
|
||||
}
|
||||
else if ( buttons == BTN_UP ) {
|
||||
adjustOption -= 1;
|
||||
refreshScreen = 1;
|
||||
save = true;
|
||||
}
|
||||
else if ( buttons == BTN_ENTER ) {
|
||||
adjustCurrent = 1;
|
||||
}
|
||||
else if (buttons == BTN_MENU ) {
|
||||
adjustCurrent = 0;
|
||||
result = -1;
|
||||
save = true;
|
||||
}
|
||||
|
||||
if(save && currentMenu->saveFunc)
|
||||
currentMenu->saveFunc(*currentMenu);
|
||||
|
||||
} else if( adjustCurrent == 1) {
|
||||
redraw |= handleInput(currentMenu, timeNow, buttons, &pos1, 20, 0);
|
||||
} else {
|
||||
redraw |= handleInput(currentMenu, timeNow, buttons, &pos2, 50, 1);
|
||||
}
|
||||
|
||||
// Keep adjustCurrent in range
|
||||
if( (adjustCurrent > 2) || ((adjustCurrent == 2) && (currentMenu->entries[1].value == nullptr)))
|
||||
adjustCurrent = 0;
|
||||
|
||||
// Keep adjust option in range.
|
||||
if(adjustOption < 0)
|
||||
adjustOption = numAdjustEntries-1;
|
||||
else if (adjustOption >= numAdjustEntries)
|
||||
adjustOption = 0;
|
||||
|
||||
|
||||
if(drawSensor) {
|
||||
plotSensorPixels();
|
||||
}
|
||||
|
||||
if(result >= 0)
|
||||
result = redraw;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
|
||||
#ifndef __CONFIG_H
|
||||
#define __CONFIG_H
|
||||
|
||||
|
||||
// Compile options, comment/uncomment to change
|
||||
|
||||
#define FIRMWARE_VERSION "1.6.0" // FIRMWARE VERSION NUMBER HERE <<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
#define ON_Delay 20 // Set Delay after ON threshold before velocity is checked (wait for tounging peak)
|
||||
#define CCN_Port 5 // Controller number for portamento level
|
||||
#define CCN_PortOnOff 65// Controller number for portamento on/off
|
||||
#define CCN_PortSE02 9 // Controller number for portamento type on Roland SE-02
|
||||
|
||||
// Send breath CC data no more than every CC_BREATH_INTERVAL
|
||||
// milliseconds
|
||||
#define CC_BREATH_INTERVAL 5
|
||||
#define SLOW_MIDI_ADD 7
|
||||
#define CC_INTERVAL 9
|
||||
#define CC_INTERVAL2 13
|
||||
#define CC_INTERVAL3 37
|
||||
#define LVL_TIMER_INTERVAL 15
|
||||
#define CVPORTATUNE 2
|
||||
|
||||
#define maxSamplesNum 120
|
||||
|
||||
#define breathLoLimit 0
|
||||
#define breathHiLimit 4095
|
||||
#define portamLoLimit 700
|
||||
#define portamHiLimit 4700
|
||||
#define pitchbLoLimit 500
|
||||
#define pitchbHiLimit 4000
|
||||
#define extracLoLimit 500
|
||||
#define extracHiLimit 4000
|
||||
#define ctouchLoLimit 50
|
||||
#define ctouchHiLimit 350
|
||||
#define ttouchLoLimit 50
|
||||
#define ttouchHiLimit 1900
|
||||
#define leverLoLimit 1400
|
||||
#define leverHiLimit 2000
|
||||
|
||||
|
||||
#define MIN_LED_BRIGHTNESS 5 // lowest PWM value that still is visible
|
||||
#define BREATH_LED_BRIGHTNESS 600 // up to 4095, PWM
|
||||
#define PORTAM_LED_BRIGHTNESS 300 // up to 4095, PWM
|
||||
#define EXTCON_LED_BRIGHTNESS 300 // up to 4095, PWM
|
||||
#define SPCKEY_LED_BRIGHTNESS 700 // up to 4095, PWM
|
||||
|
||||
#define ALK_BAT_FULL 2800 // about 4.6V
|
||||
#define NMH_BAT_FULL 2380 // about 3.9V
|
||||
#define LIP_BAT_FULL 2540 // about 4.2V
|
||||
#define ALK_BAT_LOW 2300 // about 3.8V
|
||||
#define NMH_BAT_LOW 2200 // about 3.6V
|
||||
#define LIP_BAT_LOW 2250 // about 3.7V
|
||||
|
||||
|
||||
#endif
|
||||
234
NuEVI/globals.h
234
NuEVI/globals.h
|
|
@ -1,234 +0,0 @@
|
|||
#ifndef __GLOBALS_H
|
||||
#define __GLOBALS_H
|
||||
|
||||
#include "wiring.h"
|
||||
|
||||
|
||||
// The three states of our main state machine
|
||||
|
||||
// No note is sounding
|
||||
#define NOTE_OFF 1
|
||||
|
||||
// We've observed a transition from below to above the
|
||||
// threshold value. We wait a while to see how fast the
|
||||
// breath velocity is increasing
|
||||
#define RISE_WAIT 2
|
||||
|
||||
// A note is sounding
|
||||
#define NOTE_ON 3
|
||||
|
||||
|
||||
//Magic values
|
||||
#define PBD 12
|
||||
#define EC2 25
|
||||
#define ECSW 26
|
||||
#define LVL 27
|
||||
#define LVLP 28
|
||||
#define GLD 29
|
||||
#define ECH 30
|
||||
#define QTN 31
|
||||
|
||||
#define MOD 13
|
||||
|
||||
//Vibrato direction
|
||||
#define UPWD 1
|
||||
#define DNWD 0
|
||||
|
||||
|
||||
enum PolySelect : unsigned short {
|
||||
EHarmonizerOff = 0,
|
||||
ETriadMajorGospelRoot = 1, // MGR
|
||||
ETriadMajorGospelDominant = 2, // MGD
|
||||
EMajorAddNine = 3,
|
||||
EMinorDorian = 4,
|
||||
EMinorAeolian = 5,
|
||||
EMinorFourVoiceHip = 6,
|
||||
EFourWayCloseHarmonizer = 7,
|
||||
ERotatorA = 8,
|
||||
ERotatorB = 9,
|
||||
ERotatorC = 10,
|
||||
};
|
||||
|
||||
struct Rotator
|
||||
{
|
||||
uint16_t parallel; // Semitones
|
||||
uint16_t rotations[4];
|
||||
};
|
||||
|
||||
|
||||
extern const unsigned short* const curves[];
|
||||
extern const unsigned short curveIn[];
|
||||
|
||||
#if defined(NURAD)
|
||||
extern int calOffsetRollers[6];
|
||||
extern int calOffsetRH[12];
|
||||
extern int calOffsetLH[12];
|
||||
#endif
|
||||
|
||||
extern unsigned short breathThrVal;
|
||||
extern unsigned short breathMaxVal;
|
||||
extern unsigned short portamThrVal;
|
||||
extern unsigned short portamMaxVal;
|
||||
extern unsigned short pitchbThrVal;
|
||||
extern unsigned short pitchbMaxVal;
|
||||
extern unsigned short extracThrVal;
|
||||
extern unsigned short extracMaxVal;
|
||||
extern unsigned short ctouchThrVal;
|
||||
extern unsigned short leverThrVal;
|
||||
extern unsigned short leverMaxVal;
|
||||
extern unsigned short transpose;
|
||||
extern unsigned short MIDIchannel;
|
||||
extern unsigned short breathCC; // OFF:MW:BR:VL:EX:MW+:BR+:VL+:EX+:CF:UNO
|
||||
extern unsigned short breathCC2; // OFF:1-127
|
||||
extern unsigned short breathCC2Rise; // 1X:2X:3X:4X:5X
|
||||
extern unsigned short breathAT;
|
||||
extern unsigned short velocity;
|
||||
extern unsigned short portamento;// switching on cc65? just cc5 enabled? SW:ON:OFF
|
||||
extern unsigned short portLimit; // 1-127
|
||||
extern unsigned short PBdepth; // OFF:1-12 divider
|
||||
extern unsigned short extraCT; // OFF:MW:FP:CF:SP
|
||||
extern unsigned short vibrato; // OFF:1-9
|
||||
extern unsigned short deglitch; // 0-70 ms in steps of 5
|
||||
extern unsigned short patch; // 1-128
|
||||
extern unsigned short octave;
|
||||
extern unsigned short curve;
|
||||
extern unsigned short velSmpDl; // 0-30 ms
|
||||
extern unsigned short velBias; // 0-9
|
||||
extern unsigned short pinkySetting; // 0 - 11 (QuickTranspose -12 to -1), 12 (pb/2), 13 - 24 (QuickTranspose +1 to +12), 25 (EC2), 26 (ECSW), 27 (LVL), 28 (LVLP)
|
||||
extern unsigned short dipSwBits; // virtual dip switch settings for special modes (work in progress)
|
||||
extern unsigned short priority; // mono priority for rotator chords
|
||||
extern unsigned short vibSens; // vibrato sensitivity
|
||||
extern unsigned short vibRetn; // vibrato return speed
|
||||
extern unsigned short vibSquelch; //vibrato signal squelch
|
||||
extern unsigned short vibDirection; //direction of first vibrato wave UPWD or DNWD
|
||||
extern unsigned short vibSensBite; // vibrato sensitivity (bite)
|
||||
extern unsigned short vibSquelchBite; //vibrato signal squelch (bite)
|
||||
extern unsigned short vibControl;
|
||||
extern unsigned short fastPatch[7];
|
||||
extern unsigned short extraCT2; // OFF:1-127
|
||||
extern unsigned short levelCC; // 0-127
|
||||
extern unsigned short levelVal; // 0-127
|
||||
extern unsigned short fingering; // 0-4 EWI,EWX,SAX,EVI,EVR
|
||||
extern unsigned short rollerMode; //0-2
|
||||
extern unsigned short lpinky3; // 0-25 (OFF, -12 - MOD - +12)
|
||||
extern unsigned short batteryType; // 0-2 ALK,NIM,LIP
|
||||
extern unsigned short harmSetting; // 0-7
|
||||
extern unsigned short harmSelect; // 0-5
|
||||
extern unsigned short brHarmSetting; // 0-7
|
||||
extern unsigned short brHarmSelect; // 0-3
|
||||
extern PolySelect polySelect; // OFF, MGR, MGD, MND, MNH, FWC, RTA, RTB or RTC
|
||||
extern unsigned short fwcType; // 6, m6, 7, m7
|
||||
extern unsigned short fwcLockH; // OFF:ON
|
||||
extern unsigned short fwcDrop2; // OFF:ON
|
||||
extern unsigned short hmzKey; // 0-11 (0 is C)
|
||||
extern unsigned short hmzLimit; // 2-5
|
||||
extern unsigned short otfKey; //OFF:ON
|
||||
extern unsigned short breathInterval; // 3-15
|
||||
extern unsigned short biteControl; // OFF, VIB, GLD, CC
|
||||
extern unsigned short leverControl; // OFF, VIB, GLD, CC
|
||||
extern unsigned short biteCC; // 0 - 127
|
||||
extern unsigned short leverCC; // 0 -127
|
||||
extern unsigned short cvTune; // 1 - 199 representing -99 to +99 in menu (offset of 100 to keep postitive)
|
||||
extern unsigned short cvScale; // 1 - 199 representing -99 to +99 in menu (offset of 100 to keep postitive)
|
||||
extern unsigned short cvVibRate; // OFF, 1 - 8 CV extra controller LFO vibrato rate 4.5Hz to 8Hz
|
||||
extern uint16_t gateOpenEnable;
|
||||
extern uint16_t specialKeyEnable;
|
||||
extern byte rotatorOn;
|
||||
extern byte currentRotation;
|
||||
|
||||
extern Rotator rotations_a;
|
||||
extern Rotator rotations_b;
|
||||
extern Rotator rotations_c;
|
||||
|
||||
extern uint16_t bcasMode; //Legacy CASSIDY compile flag
|
||||
extern uint16_t trill3_interval;
|
||||
extern uint16_t fastBoot;
|
||||
extern uint16_t dacMode;
|
||||
|
||||
|
||||
extern int touch_Thr;
|
||||
|
||||
extern int leverPortZero;
|
||||
|
||||
extern unsigned long cursorBlinkTime; // the last time the cursor was toggled
|
||||
|
||||
extern byte activePatch;
|
||||
extern byte doPatchUpdate;
|
||||
|
||||
extern uint16_t legacy;
|
||||
extern uint16_t legacyBrAct;
|
||||
|
||||
extern byte widiOn;
|
||||
|
||||
extern int pressureSensor; // pressure data from breath sensor, for midi breath cc and breath threshold checks
|
||||
extern int lastPressure;
|
||||
|
||||
extern int biteSensor; // capacitance data from bite sensor, for midi cc and threshold checks
|
||||
extern int lastBite;
|
||||
extern byte biteJumper;
|
||||
extern byte widiJumper;
|
||||
extern int exSensor;
|
||||
extern int exSensorIndicator;
|
||||
|
||||
extern int pitchBend;
|
||||
extern int pbSend;
|
||||
|
||||
extern int pbUp;
|
||||
extern int pbDn;
|
||||
|
||||
extern byte vibLedOff;
|
||||
extern byte oldpkey;
|
||||
|
||||
extern int vibThr; // this gets auto calibrated in setup
|
||||
extern int vibThrLo;
|
||||
extern int vibZero;
|
||||
extern int vibZeroBite;
|
||||
extern int vibThrBite;
|
||||
extern int vibThrBiteLo;
|
||||
|
||||
extern int battAvg;
|
||||
|
||||
extern int breathLevel;
|
||||
extern byte portIsOn;
|
||||
extern int oldport;
|
||||
|
||||
#if defined(NURAD)
|
||||
// Key variables, TRUE (1) for pressed, FALSE (0) for not pressed
|
||||
extern byte LHs;
|
||||
extern byte LH1; // Left Hand key 1 (pitch change -2)
|
||||
extern byte LHb; // Left Hand bis key (pitch change -1 unless both LH1 and LH2 are pressed)
|
||||
extern byte LH2; // Left Hand key 2 (with LH1 also pressed pitch change is -2, otherwise -1)
|
||||
extern byte LH3; // Left Hand key 3 (pitch change -2)
|
||||
extern byte LHp1; // Left Hand pinky key 1 (pitch change +1)
|
||||
extern byte LHp2; // Left Hand pinky key 2 (pitch change -1)
|
||||
extern byte LHp3;
|
||||
extern byte RHs; // Right Hand side key (pitch change -2 unless LHp1 is pressed)
|
||||
extern byte RH1; // Right Hand key 1 (with LH3 also pressed pitch change is -2, otherwise -1)
|
||||
extern byte RH2; // Right Hand key 2 (pitch change -1)
|
||||
extern byte RH3; // Right Hand key 3 (pitch change -2)
|
||||
extern byte RHp1; // Right Hand pinky key 1 (pitch change +1)
|
||||
extern byte RHp2; // Right Hand pinky key 2 (pitch change -1)
|
||||
extern byte RHp3; // Right Hand pinky key 3 (pitch change -2)
|
||||
extern byte Tr1; // Trill key 1 (pitch change +2) (EVI fingering)
|
||||
extern byte Tr2; // Trill key 2 (pitch change +1)
|
||||
extern byte Tr3; // Trill key 3 (pitch change +4)
|
||||
#endif
|
||||
|
||||
// Key variables, TRUE (1) for pressed, FALSE (0) for not pressed
|
||||
extern byte K1; // Valve 1 (pitch change -2)
|
||||
extern byte K2; // Valve 2 (pitch change -1)
|
||||
extern byte K3; // Valve 3 (pitch change -3)
|
||||
extern byte K4; // Left Hand index finger (pitch change -5)
|
||||
extern byte K5; // Trill key 1 (pitch change +2)
|
||||
extern byte K6; // Trill key 2 (pitch change +1)
|
||||
extern byte K7; // Trill key 3 (pitch change +4)
|
||||
|
||||
extern byte halfPitchBendKey;
|
||||
extern byte quarterToneTrigger;
|
||||
extern byte specialKey;
|
||||
extern byte pinkyKey;
|
||||
extern byte patchKey;
|
||||
|
||||
extern unsigned int multiMap(unsigned short val, const unsigned short * _in, const unsigned short * _out, uint8_t size);
|
||||
|
||||
#endif
|
||||
199
NuEVI/hardware.h
199
NuEVI/hardware.h
|
|
@ -1,199 +0,0 @@
|
|||
#ifndef __HARDWARE_H
|
||||
#define __HARDWARE_H
|
||||
|
||||
#define REVB
|
||||
//#define NURAD
|
||||
//#define SEAMUS
|
||||
|
||||
//#define I2CSCANNER
|
||||
|
||||
#if defined(NURAD) //NuRAD <<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
// Pin definitions
|
||||
|
||||
// Teensy pins
|
||||
|
||||
//Capacitive sensor pins (on-board teensy)
|
||||
#define bitePin 17
|
||||
#define extraPin 16
|
||||
#define pbUpPin 1
|
||||
#define pbDnPin 0
|
||||
#define vibratoPin 15
|
||||
|
||||
//Analog pressure sensors. Breath and optional bite
|
||||
#define breathSensorPin A0
|
||||
#define bitePressurePin A7
|
||||
|
||||
//Digital pins for menu buttons
|
||||
#define dPin 3
|
||||
#define ePin 4
|
||||
#define uPin 5
|
||||
#define mPin 6
|
||||
|
||||
//Output pins for LEDs (breath, power, status)
|
||||
#define bLedPin 10
|
||||
#define pLedPin 9
|
||||
#define eLedPin 22
|
||||
#define sLedPin 23
|
||||
#define statusLedPin 13
|
||||
|
||||
//Pins for WIDI board management
|
||||
#define widiJumperPin 28
|
||||
#define widiJumperGndPin 27
|
||||
#define widiPowerPin 33
|
||||
|
||||
//Analog input for measuring voltage
|
||||
#define vMeterPin A11
|
||||
|
||||
//DAC outputs for analog and pwm
|
||||
#define dacPin A14
|
||||
#define pwmDacPin A6
|
||||
|
||||
//Which serial port to use for MIDI
|
||||
#define MIDI_SERIAL Serial3
|
||||
#define WIDI_SERIAL Serial2
|
||||
|
||||
// MPR121 Rollers 0x5D
|
||||
|
||||
#define rPin1 0
|
||||
#define rPin2 1
|
||||
#define rPin3 2
|
||||
#define rPin4 3
|
||||
#define rPin5 4
|
||||
#define rPin6 5
|
||||
|
||||
// MPR121 RH 0x5C
|
||||
|
||||
#define RHsPin 3
|
||||
#define RH1Pin 4
|
||||
#define RH2Pin 2
|
||||
#define RH3Pin 1
|
||||
#define RHp1Pin 0
|
||||
#define RHp2Pin 8
|
||||
#define RHp3Pin 7
|
||||
#define spec1Pin 10
|
||||
#define spec2Pin 9
|
||||
#define patchPin 5
|
||||
|
||||
// MPR121 LH 0x5B
|
||||
|
||||
#define LHsPin 8
|
||||
#define LH1Pin 7
|
||||
#define LHbPin 1
|
||||
#define LH2Pin 9
|
||||
#define LH3Pin 10
|
||||
#define LHp1Pin 11
|
||||
#define LHp2Pin 3
|
||||
#define LHp3Pin 4
|
||||
|
||||
#else //NuEVI <<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
// Pin definitions
|
||||
|
||||
// Teensy pins
|
||||
|
||||
#define specialKeyPin 0 // SK or S2
|
||||
#define halfPitchBendKeyPin 1 // PD or S1
|
||||
|
||||
|
||||
//Capacitive sensor pins (on-board teensy)
|
||||
#define bitePin 17
|
||||
#define extraPin 16
|
||||
#define pbUpPin 23
|
||||
#define pbDnPin 22
|
||||
#define vibratoPin 15
|
||||
|
||||
//Pins jumpered to enable bite pressure sensor
|
||||
#define biteJumperPin 11
|
||||
#define biteJumperGndPin 12
|
||||
|
||||
//Pins for WIDI board management
|
||||
#define widiJumperPin 28
|
||||
#define widiJumperGndPin 27
|
||||
#define widiPowerPin 33
|
||||
|
||||
//Analog pressure sensors. Breath and optional bite
|
||||
#define breathSensorPin A0
|
||||
#define bitePressurePin A7
|
||||
|
||||
//Digital pins for menu buttons
|
||||
#define dPin 3
|
||||
#define ePin 4
|
||||
#define uPin 5
|
||||
#define mPin 6
|
||||
|
||||
//Output pins for LEDs (breath, power, status)
|
||||
#define bLedPin 10
|
||||
#define pLedPin 9
|
||||
#define statusLedPin 13
|
||||
|
||||
//Analog input for measuring voltage
|
||||
#define vMeterPin A11
|
||||
|
||||
//DAC outputs for analog and pwm
|
||||
#define dacPin A14
|
||||
#define pwmDacPin 20
|
||||
|
||||
//Which serial port to use for MIDI
|
||||
#define MIDI_SERIAL Serial3
|
||||
#define WIDI_SERIAL Serial2
|
||||
|
||||
#if defined(REVB)
|
||||
|
||||
// MPR121 pins Rev B (angled pins at top edge for main keys and rollers)
|
||||
|
||||
#define R1Pin 0
|
||||
#define R2Pin 2
|
||||
#define R3Pin 4
|
||||
#define R4Pin 6
|
||||
#define R5Pin 8
|
||||
|
||||
#define K4Pin 10
|
||||
#define K1Pin 1
|
||||
#define K2Pin 3
|
||||
#define K3Pin 5
|
||||
#define K5Pin 7
|
||||
#define K6Pin 9
|
||||
#define K7Pin 11
|
||||
|
||||
/*
|
||||
* PINOUT ON PCB vs PINS ON MPR121 - Rev. B
|
||||
*
|
||||
* (R1) (R2) (R3/6) (R4) (R5) (K4) <-> (00) (02) (04) (06) (08) (10)
|
||||
*
|
||||
* (K1) (K2) (K3) (K5) (K6) (K7) <-> (01) (03) (05) (07) (09) (11)
|
||||
*
|
||||
*/
|
||||
|
||||
# else //REV A
|
||||
|
||||
// MPR121 pins Rev A (upright pins below MPR121 for main keys and rollers)
|
||||
|
||||
#define R1Pin 10
|
||||
#define R2Pin 11
|
||||
#define R3Pin 8
|
||||
#define R4Pin 9
|
||||
#define R5Pin 6
|
||||
|
||||
#define K4Pin 7
|
||||
#define K1Pin 4
|
||||
#define K2Pin 5
|
||||
#define K3Pin 2
|
||||
#define K5Pin 3
|
||||
#define K6Pin 0
|
||||
#define K7Pin 1
|
||||
|
||||
/*
|
||||
* PINOUT ON PCB vs PINS ON MPR121 - Rev. A
|
||||
*
|
||||
* (R2) (R4) (K4) (K2) (K5) (K7) <-> (11) (09) (07) (05) (03) (01)
|
||||
*
|
||||
* (R1) (R3/6) (R5) (K1) (K3) (K6) <-> (10) (08) (06) (04) (02) (00)
|
||||
*
|
||||
*/
|
||||
|
||||
#endif //REVB
|
||||
#endif //NURAD
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
#include <Arduino.h>
|
||||
#include "hardware.h"
|
||||
#include "globals.h"
|
||||
#include "config.h"
|
||||
|
||||
// Do things with status LED.
|
||||
void statusLedOn() {
|
||||
digitalWrite(statusLedPin, HIGH);
|
||||
#if defined(SEAMUS)
|
||||
analogWrite(sLedPin, SPCKEY_LED_BRIGHTNESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
void statusLedOff() {
|
||||
digitalWrite(statusLedPin, LOW);
|
||||
#if defined(SEAMUS)
|
||||
analogWrite(sLedPin, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void statusLed(bool state) {
|
||||
digitalWrite(statusLedPin, state);
|
||||
#if defined(SEAMUS)
|
||||
analogWrite(sLedPin, state*SPCKEY_LED_BRIGHTNESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
void statusLedFlip() {
|
||||
digitalWrite(statusLedPin, !digitalRead(statusLedPin));
|
||||
#if defined(SEAMUS)
|
||||
if (digitalRead(statusLedPin)) analogWrite(sLedPin, SPCKEY_LED_BRIGHTNESS); else analogWrite(sLedPin, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void statusLedFlash(uint16_t delayTime) {
|
||||
statusLedOff();
|
||||
delay(delayTime/2);
|
||||
statusLedOn();
|
||||
delay(delayTime/2);
|
||||
}
|
||||
|
||||
void statusLedBlink() {
|
||||
statusLedFlash(300);
|
||||
statusLedFlash(300);
|
||||
}
|
||||
|
||||
void updateSensorLEDs() {
|
||||
if (breathLevel > breathThrVal) { // breath indicator LED, labeled "B" on PCB
|
||||
//analogWrite(bLedPin, map(breathLevel,0,4096,5,breathLedBrightness));
|
||||
analogWrite(bLedPin, map(constrain(breathLevel, breathThrVal, breathMaxVal), breathThrVal, breathMaxVal, MIN_LED_BRIGHTNESS, BREATH_LED_BRIGHTNESS));
|
||||
} else {
|
||||
analogWrite(bLedPin, 0);
|
||||
}
|
||||
if (portIsOn) { // portamento indicator LED, labeled "P" on PCB
|
||||
//analogWrite(pLedPin, map(biteSensor,0,4096,5,portamLedBrightness));
|
||||
analogWrite(pLedPin, map(constrain(oldport, 0, 127), 0, 127, MIN_LED_BRIGHTNESS, PORTAM_LED_BRIGHTNESS));
|
||||
} else {
|
||||
analogWrite(pLedPin, 0);
|
||||
}
|
||||
#if defined(NURAD)
|
||||
if (exSensorIndicator){
|
||||
analogWrite(eLedPin, map(constrain(exSensorIndicator, 0, 127), 0, 127, MIN_LED_BRIGHTNESS, EXTCON_LED_BRIGHTNESS));
|
||||
} else {
|
||||
analogWrite(eLedPin, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ledMeter(byte indicatedValue){
|
||||
analogWrite(bLedPin, map(constrain(indicatedValue, 0, 127), 0, 127, 0, BREATH_LED_BRIGHTNESS)); // full glow at maximum value
|
||||
analogWrite(pLedPin, map(constrain(indicatedValue, 0, 127), 127, 0, 0, PORTAM_LED_BRIGHTNESS)); // full glow at minimum value
|
||||
}
|
||||
2453
NuEVI/menu.cpp
2453
NuEVI/menu.cpp
File diff suppressed because it is too large
Load diff
52
NuEVI/menu.h
52
NuEVI/menu.h
|
|
@ -1,52 +0,0 @@
|
|||
#ifndef __MENU_H
|
||||
#define __MENU_H
|
||||
|
||||
#include "wiring.h"
|
||||
#include "numenu.h"
|
||||
|
||||
#define MENU_ROW_HEIGHT 9
|
||||
#define MENU_HEADER_OFFSET 12
|
||||
#define MENU_NUM_ROWS 6
|
||||
|
||||
//display states
|
||||
#define DISPLAYOFF_IDL 0
|
||||
#define MAIN_MENU 1
|
||||
#define PATCH_VIEW 2
|
||||
#define ADJUST_MENU 3
|
||||
#define SETUP_BR_MENU 4
|
||||
#define SETUP_CT_MENU 5
|
||||
#define ROTATOR_MENU 6
|
||||
#define VIBRATO_MENU 7
|
||||
#define ABOUT_MENU 8
|
||||
#define EXTRAS_MENU 9
|
||||
#define ROTA_MENU 10
|
||||
#define ROTB_MENU 11
|
||||
#define ROTC_MENU 12
|
||||
|
||||
#define ARR_LEN(a) (sizeof (a) / sizeof (a[0]))
|
||||
|
||||
#define BTN_DOWN 1
|
||||
#define BTN_ENTER 2
|
||||
#define BTN_UP 4
|
||||
#define BTN_MENU 8
|
||||
|
||||
|
||||
extern const unsigned long debounceDelay; // the debounce time; increase if the output flickers
|
||||
extern const unsigned long buttonRepeatInterval;
|
||||
extern const unsigned long buttonRepeatDelay;
|
||||
extern const unsigned long cursorBlinkInterval; // the cursor blink toggle interval time
|
||||
extern const unsigned long patchViewTimeUp; // ms until patch view shuts off
|
||||
extern const unsigned long menuTimeUp; // menu shuts off after one minute of button inactivity
|
||||
|
||||
extern byte subVibSquelch; // TODO: This is broken <- subVibSquelch is never set, we need another way to expose what menu is open.
|
||||
|
||||
void initDisplay();
|
||||
void showVersion();
|
||||
void menu();
|
||||
void drawSensorPixels();
|
||||
void i2cScanDisplay();
|
||||
|
||||
int updateAdjustMenu(uint32_t timeNow, KeyState &input, bool firstRun, bool drawSensor);
|
||||
bool adjustPageUpdate(KeyState &input, uint32_t timeNow);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
Notes on the original menu implementation
|
||||
|
||||
# Menus
|
||||
|
||||
## Main Menu
|
||||
|
||||
### Transpose
|
||||
Sub menu with values -12 to 12.
|
||||
|
||||
### Octave
|
||||
Sub menu with values -3 to +3
|
||||
|
||||
### MIDI CH
|
||||
|
||||
Sub menu with values 0 to 16. Should be 1 to 16, but there might be a bug
|
||||
either in my simulation code, my changes to the menu or a bug in the original
|
||||
menu.
|
||||
|
||||
### Adjust
|
||||
|
||||
This is a special option where the Adjust menu mode is entered. It take over
|
||||
the display and draw horizontal indicators for threshold and such. More on
|
||||
this in a later section.
|
||||
|
||||
### SETUP BR
|
||||
|
||||
Breath setup. Opens a new menu with breath specific stuff.
|
||||
|
||||
|
||||
### SETUP CTL
|
||||
|
||||
Controls setup. Opens a new menu.
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
#ifndef __NUMENU_H
|
||||
#define __NUMENU_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
//***********************************************************
|
||||
|
||||
struct KeyState {
|
||||
uint8_t current;
|
||||
uint8_t changed;
|
||||
};
|
||||
|
||||
//***********************************************************
|
||||
|
||||
enum MenuType {
|
||||
ESub,
|
||||
EStateChange,
|
||||
};
|
||||
|
||||
enum MenuEntryFlags {
|
||||
ENone = 0,
|
||||
EMenuEntryWrap = (1u<<0),
|
||||
EMenuEntryCustom = (1u<<1),
|
||||
EMenuEntryEnterHandler = (1u<<2),
|
||||
};
|
||||
|
||||
enum MenuPageFlags {
|
||||
EMenuPageCustom = (1u<<0),
|
||||
EMenuPageRoot = (1u<<1),
|
||||
EMenuCustomTitle = (1u << 2),
|
||||
};
|
||||
|
||||
|
||||
struct MenuEntry {
|
||||
enum MenuType type;
|
||||
const char* title;
|
||||
};
|
||||
|
||||
struct MenuEntrySub;
|
||||
typedef const MenuEntrySub& SubMenuRef;
|
||||
|
||||
struct MenuEntrySub {
|
||||
enum MenuType type;
|
||||
const char* title;
|
||||
const char* subTitle;
|
||||
uint16_t* valuePtr;
|
||||
uint16_t min;
|
||||
uint16_t max;
|
||||
uint16_t flags;
|
||||
void (*getSubTextFunc)(SubMenuRef, char*textBuffer, const char**label);
|
||||
void (*applyFunc)(SubMenuRef);
|
||||
bool (*onEnterFunc)(void);
|
||||
};
|
||||
|
||||
struct MenuEntryStateCh {
|
||||
enum MenuType type;
|
||||
const char* title;
|
||||
uint8_t state;
|
||||
};
|
||||
|
||||
struct MenuPage {
|
||||
const char* title;
|
||||
uint16_t flags;
|
||||
uint8_t cursor;
|
||||
uint8_t parentPage;
|
||||
uint8_t numEntries;
|
||||
const MenuEntry** entries;
|
||||
};
|
||||
|
||||
struct MenuPageCustom {
|
||||
const char* title;
|
||||
uint16_t flags;
|
||||
bool (*menuUpdateFunc)(KeyState &input, uint32_t timeNow);
|
||||
};
|
||||
|
||||
//***********************************************************
|
||||
|
||||
struct AdjustValue {
|
||||
uint16_t *value;
|
||||
uint16_t limitLow;
|
||||
uint16_t limitHigh;
|
||||
};
|
||||
|
||||
struct AdjustMenuEntry {
|
||||
const char* title;
|
||||
AdjustValue entries[2];
|
||||
void (*saveFunc)(const AdjustMenuEntry&);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,16 +1,23 @@
|
|||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:teensy31]
|
||||
platform = teensy
|
||||
board = teensy31
|
||||
framework = arduino
|
||||
build_flags = -D USB_MIDI -D TEENSY_OPT_FASTER
|
||||
board_build.f_cpu = 96000000L
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:teensy40]
|
||||
platform = teensy
|
||||
board = teensy40
|
||||
framework = arduino
|
||||
build_flags = -D USB_MIDI_SERIAL -D TEENSY_OPT_FASTER
|
||||
board_build.f_cpu = 528000000L
|
||||
lib_deps =
|
||||
adafruit/Adafruit MPR121@^1.1.1
|
||||
adafruit/Adafruit MPRLS Library@^1.2.0
|
||||
adafruit/Adafruit SSD1306@^2.5.7
|
||||
mkalkbrenner/WS2812Serial@^0.1.0
|
||||
adafruit/Adafruit ICM20X@^2.0.5
|
||||
paulstoffregen/Encoder@^1.4.2
|
||||
|
|
|
|||
|
|
@ -1,618 +0,0 @@
|
|||
#include <Arduino.h>
|
||||
#include <EEPROM.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
|
||||
|
||||
#include "settings.h"
|
||||
#include "globals.h"
|
||||
#include "menu.h"
|
||||
#include "hardware.h"
|
||||
#include "config.h"
|
||||
#include "midi.h"
|
||||
#include "led.h"
|
||||
|
||||
//Read settings from eeprom. Returns wether or not anything was written (due to factory reset or upgrade)
|
||||
void readEEPROM(const bool factoryReset) {
|
||||
|
||||
// if stored settings are not for current version, or Enter+Menu are pressed at startup, they are replaced by factory settings
|
||||
uint16_t settingsVersion = readSetting(VERSION_ADDR);
|
||||
|
||||
// blank eeprom will be 0xFFFF. For a full reset, call it "version 0" so everything gets overwritten.
|
||||
if (factoryReset || settingsVersion == 0xffffu) {
|
||||
settingsVersion = 0;
|
||||
}
|
||||
|
||||
|
||||
if(settingsVersion != EEPROM_VERSION) {
|
||||
|
||||
if(settingsVersion < 24) { //Oldest version from which any settings are recognized
|
||||
writeSetting(BREATH_THR_ADDR, BREATH_THR_FACTORY);
|
||||
writeSetting(BREATH_MAX_ADDR, BREATH_MAX_FACTORY);
|
||||
#if defined(NURAD)
|
||||
writeSetting(PORTAM_THR_ADDR, PORTPR_THR_FACTORY);
|
||||
writeSetting(PORTAM_MAX_ADDR, PORTPR_MAX_FACTORY);
|
||||
#else
|
||||
if (digitalRead(biteJumperPin)){ //PBITE (if pulled low with jumper, pressure sensor is used instead of capacitive bite sensing)
|
||||
writeSetting(PORTAM_THR_ADDR, PORTAM_THR_FACTORY);
|
||||
writeSetting(PORTAM_MAX_ADDR, PORTAM_MAX_FACTORY);
|
||||
} else {
|
||||
writeSetting(PORTAM_THR_ADDR, PORTPR_THR_FACTORY);
|
||||
writeSetting(PORTAM_MAX_ADDR, PORTPR_MAX_FACTORY);
|
||||
}
|
||||
#endif
|
||||
writeSetting(PITCHB_THR_ADDR, PITCHB_THR_FACTORY);
|
||||
writeSetting(PITCHB_MAX_ADDR, PITCHB_MAX_FACTORY);
|
||||
writeSetting(EXTRAC_THR_ADDR, EXTRAC_THR_FACTORY);
|
||||
writeSetting(EXTRAC_MAX_ADDR, EXTRAC_MAX_FACTORY);
|
||||
writeSetting(CTOUCH_THR_ADDR, CTOUCH_THR_FACTORY);
|
||||
|
||||
writeSetting(TRANSP_ADDR, TRANSP_FACTORY);
|
||||
writeSetting(MIDI_ADDR, MIDI_FACTORY);
|
||||
writeSetting(BREATH_CC_ADDR, BREATH_CC_FACTORY);
|
||||
writeSetting(BREATH_AT_ADDR, BREATH_AT_FACTORY);
|
||||
writeSetting(VELOCITY_ADDR, VELOCITY_FACTORY);
|
||||
writeSetting(PORTAM_ADDR, PORTAM_FACTORY);
|
||||
writeSetting(PB_ADDR, PB_FACTORY);
|
||||
writeSetting(EXTRA_ADDR, EXTRA_FACTORY);
|
||||
writeSetting(VIBRATO_ADDR, VIBRATO_FACTORY);
|
||||
writeSetting(DEGLITCH_ADDR, DEGLITCH_FACTORY);
|
||||
writeSetting(PATCH_ADDR, PATCH_FACTORY);
|
||||
writeSetting(OCTAVE_ADDR, OCTAVE_FACTORY);
|
||||
writeSetting(BREATHCURVE_ADDR, BREATHCURVE_FACTORY);
|
||||
writeSetting(VEL_SMP_DL_ADDR, VEL_SMP_DL_FACTORY);
|
||||
writeSetting(VEL_BIAS_ADDR, VEL_BIAS_FACTORY);
|
||||
writeSetting(PINKY_KEY_ADDR, PINKY_KEY_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 26) {
|
||||
writeSetting(FP1_ADDR, 0);
|
||||
writeSetting(FP2_ADDR, 0);
|
||||
writeSetting(FP3_ADDR, 0);
|
||||
writeSetting(FP4_ADDR, 0);
|
||||
writeSetting(FP5_ADDR, 0);
|
||||
writeSetting(FP6_ADDR, 0);
|
||||
writeSetting(FP7_ADDR, 0);
|
||||
writeSetting(DIPSW_BITS_ADDR, DIPSW_BITS_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 28) {
|
||||
writeSetting(PARAL_ADDR, PARAL_FACTORY);
|
||||
writeSetting(ROTN1_ADDR, ROTN1_FACTORY);
|
||||
writeSetting(ROTN2_ADDR, ROTN2_FACTORY);
|
||||
writeSetting(ROTN3_ADDR, ROTN3_FACTORY);
|
||||
writeSetting(ROTN4_ADDR, ROTN4_FACTORY);
|
||||
writeSetting(PRIO_ADDR, PRIO_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 29) {
|
||||
writeSetting(VIB_SENS_ADDR, VIB_SENS_FACTORY);
|
||||
writeSetting(VIB_RETN_ADDR, VIB_RETN_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 31) {
|
||||
writeSetting(VIB_SQUELCH_ADDR, VIB_SQUELCH_FACTORY);
|
||||
writeSetting(VIB_DIRECTION_ADDR, VIB_DIRECTION_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 32) {
|
||||
writeSetting(BREATH_CC2_ADDR, BREATH_CC2_FACTORY);
|
||||
writeSetting(BREATH_CC2_RISE_ADDR, BREATH_CC2_RISE_FACTORY);
|
||||
writeSetting(VIB_SENS_BITE_ADDR, VIB_SENS_BITE_FACTORY);
|
||||
writeSetting(VIB_SQUELCH_BITE_ADDR, VIB_SQUELCH_BITE_FACTORY);
|
||||
writeSetting(VIB_CONTROL_ADDR, VIB_CONTROL_FACTORY);
|
||||
writeSetting(TRILL3_INTERVAL_ADDR, TRILL3_INTERVAL_FACTORY);
|
||||
writeSetting(DAC_MODE_ADDR, DAC_MODE_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 33) {
|
||||
writeSetting(EXTRA2_ADDR, EXTRA2_FACTORY);
|
||||
writeSetting(LEVEL_CC_ADDR, LEVEL_CC_FACTORY);
|
||||
writeSetting(LEVEL_VAL_ADDR, LEVEL_VAL_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 34) {
|
||||
writeSetting(FINGER_ADDR, FINGER_FACTORY);
|
||||
writeSetting(LPINKY3_ADDR, LPINKY3_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 35) {
|
||||
writeSetting(BATTYPE_ADDR, BATTYPE_FACTORY);
|
||||
writeSetting(HARMSET_ADDR, HARMSET_FACTORY);
|
||||
writeSetting(HARMSEL_ADDR, HARMSEL_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 36) {
|
||||
writeSetting(PARAB_ADDR, PARAB_FACTORY);
|
||||
writeSetting(ROTB1_ADDR, ROTB1_FACTORY);
|
||||
writeSetting(ROTB2_ADDR, ROTB2_FACTORY);
|
||||
writeSetting(ROTB3_ADDR, ROTB3_FACTORY);
|
||||
writeSetting(ROTB4_ADDR, ROTB4_FACTORY);
|
||||
writeSetting(PARAC_ADDR, PARAC_FACTORY);
|
||||
writeSetting(ROTC1_ADDR, ROTC1_FACTORY);
|
||||
writeSetting(ROTC2_ADDR, ROTC2_FACTORY);
|
||||
writeSetting(ROTC3_ADDR, ROTC3_FACTORY);
|
||||
writeSetting(ROTC4_ADDR, ROTC4_FACTORY);
|
||||
writeSetting(POLYSEL_ADDR, POLYSEL_FACTORY);
|
||||
writeSetting(FWCTYPE_ADDR, FWCTYPE_FACTORY);
|
||||
writeSetting(HMZKEY_ADDR, HMZKEY_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 37) {
|
||||
writeSetting(FWCLCH_ADDR, FWCLCH_FACTORY);
|
||||
writeSetting(FWCDP2_ADDR, FWCDP2_FACTORY);
|
||||
}
|
||||
|
||||
|
||||
if(settingsVersion < 38) {
|
||||
writeSetting(HMZLIMIT_ADDR, HMZLIMIT_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 39) {
|
||||
writeSetting(BRINTERV_ADDR, BRINTERV_FACTORY);
|
||||
writeSetting(OTFKEY_ADDR, OTFKEY_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 40) {
|
||||
writeSetting(PORTLIMIT_ADDR, PORTLIMIT_FACTORY);
|
||||
writeSetting(LEVER_THR_ADDR, LEVER_THR_FACTORY);
|
||||
writeSetting(LEVER_MAX_ADDR, LEVER_MAX_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 41) {
|
||||
writeSetting(BRHARMSET_ADDR, BRHARMSET_FACTORY);
|
||||
writeSetting(BRHARMSEL_ADDR, BRHARMSEL_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 42) {
|
||||
writeSetting(BITECTL_ADDR, BITECTL_FACTORY);
|
||||
writeSetting(BITECC_ADDR, BITECC_FACTORY);
|
||||
writeSetting(LEVERCTL_ADDR, LEVERCTL_FACTORY);
|
||||
writeSetting(LEVERCC_ADDR, LEVERCC_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 43) {
|
||||
writeSetting(CVTUNE_ADDR, CVTUNE_FACTORY);
|
||||
writeSetting(CVSCALE_ADDR, CVSCALE_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 44) {
|
||||
writeSetting(CVRATE_ADDR, CVRATE_FACTORY);
|
||||
}
|
||||
|
||||
if(settingsVersion < 45) {
|
||||
writeSetting(ROLLER_ADDR, ROLLER_FACTORY);
|
||||
}
|
||||
|
||||
writeSetting(VERSION_ADDR, EEPROM_VERSION);
|
||||
}
|
||||
|
||||
// read all settings from EEPROM
|
||||
breathThrVal = readSettingBounded(BREATH_THR_ADDR, breathLoLimit, breathHiLimit, BREATH_THR_FACTORY);
|
||||
breathMaxVal = readSettingBounded(BREATH_MAX_ADDR, breathLoLimit, breathHiLimit, BREATH_MAX_FACTORY);
|
||||
portamThrVal = readSettingBounded(PORTAM_THR_ADDR, portamLoLimit, portamHiLimit, PORTAM_THR_FACTORY);
|
||||
portamMaxVal = readSettingBounded(PORTAM_MAX_ADDR, portamLoLimit, portamHiLimit, PORTAM_MAX_FACTORY);
|
||||
pitchbThrVal = readSettingBounded(PITCHB_THR_ADDR, pitchbLoLimit, pitchbHiLimit, PITCHB_THR_FACTORY);
|
||||
pitchbMaxVal = readSettingBounded(PITCHB_MAX_ADDR, pitchbLoLimit, pitchbHiLimit, PITCHB_MAX_FACTORY);
|
||||
transpose = readSettingBounded(TRANSP_ADDR, 0, 24, TRANSP_FACTORY);
|
||||
MIDIchannel = readSettingBounded(MIDI_ADDR, 1, 16, MIDI_FACTORY);
|
||||
breathCC = readSettingBounded(BREATH_CC_ADDR, 0, 10, BREATH_CC_FACTORY);
|
||||
breathAT = readSettingBounded(BREATH_AT_ADDR, 0, 1, BREATH_AT_FACTORY);
|
||||
velocity = readSettingBounded(VELOCITY_ADDR, 0, 127, VELOCITY_FACTORY);
|
||||
portamento = readSettingBounded(PORTAM_ADDR, 0, 5, PORTAM_FACTORY);
|
||||
PBdepth = readSettingBounded(PB_ADDR, 0, 12, PB_FACTORY);
|
||||
extraCT = readSettingBounded(EXTRA_ADDR, 0, 4, EXTRA_FACTORY);
|
||||
vibrato = readSettingBounded(VIBRATO_ADDR, 0, 9, VIBRATO_FACTORY);
|
||||
deglitch = readSettingBounded(DEGLITCH_ADDR, 0, 70, DEGLITCH_FACTORY);
|
||||
extracThrVal = readSettingBounded(EXTRAC_THR_ADDR, extracLoLimit, extracHiLimit, EXTRAC_THR_FACTORY);
|
||||
extracMaxVal = readSettingBounded(EXTRAC_MAX_ADDR, extracLoLimit, extracHiLimit, EXTRAC_MAX_FACTORY);
|
||||
patch = readSettingBounded(PATCH_ADDR, 0, 127, PATCH_FACTORY);
|
||||
octave = readSettingBounded(OCTAVE_ADDR, 0, 6, OCTAVE_FACTORY);
|
||||
ctouchThrVal = readSettingBounded(CTOUCH_THR_ADDR, ctouchLoLimit, ctouchHiLimit, CTOUCH_THR_FACTORY);
|
||||
curve = readSettingBounded(BREATHCURVE_ADDR, 0, 12, BREATHCURVE_FACTORY);
|
||||
velSmpDl = readSettingBounded(VEL_SMP_DL_ADDR, 0, 30, VEL_SMP_DL_FACTORY);
|
||||
velBias = readSettingBounded(VEL_BIAS_ADDR, 0, 9, VEL_BIAS_FACTORY);
|
||||
pinkySetting = readSettingBounded(PINKY_KEY_ADDR, 0, 31, PINKY_KEY_FACTORY);
|
||||
fastPatch[0] = readSettingBounded(FP1_ADDR, 0, 127, 0);
|
||||
fastPatch[1] = readSettingBounded(FP2_ADDR, 0, 127, 0);
|
||||
fastPatch[2] = readSettingBounded(FP3_ADDR, 0, 127, 0);
|
||||
fastPatch[3] = readSettingBounded(FP4_ADDR, 0, 127, 0);
|
||||
fastPatch[4] = readSettingBounded(FP5_ADDR, 0, 127, 0);
|
||||
fastPatch[5] = readSettingBounded(FP6_ADDR, 0, 127, 0);
|
||||
fastPatch[6] = readSettingBounded(FP7_ADDR, 0, 127, 0);
|
||||
dipSwBits = readSetting(DIPSW_BITS_ADDR);
|
||||
rotations_a.parallel = readSettingBounded(PARAL_ADDR, 0, 48, PARAL_FACTORY);
|
||||
rotations_a.rotations[0] = readSettingBounded(ROTN1_ADDR, 0, 48, ROTN1_FACTORY);
|
||||
rotations_a.rotations[1] = readSettingBounded(ROTN2_ADDR, 0, 48, ROTN2_FACTORY);
|
||||
rotations_a.rotations[2] = readSettingBounded(ROTN3_ADDR, 0, 48, ROTN3_FACTORY);
|
||||
rotations_a.rotations[3] = readSettingBounded(ROTN4_ADDR, 0, 48, ROTN4_FACTORY);
|
||||
priority = readSettingBounded(PRIO_ADDR, 0, 1, PRIO_FACTORY);
|
||||
vibSens = readSettingBounded(VIB_SENS_ADDR, 1, 12, VIB_SENS_FACTORY);
|
||||
vibRetn = readSettingBounded(VIB_RETN_ADDR, 0, 4, VIB_RETN_FACTORY);
|
||||
vibSquelch = readSettingBounded(VIB_SQUELCH_ADDR, 1, 30, VIB_SQUELCH_FACTORY);
|
||||
vibDirection = readSettingBounded(VIB_DIRECTION_ADDR, 0, 1, VIB_DIRECTION_FACTORY);
|
||||
breathCC2 = readSettingBounded(BREATH_CC2_ADDR, 0, 127, BREATH_CC2_FACTORY);
|
||||
breathCC2Rise = readSettingBounded(BREATH_CC2_RISE_ADDR, 1, 10, BREATH_CC2_RISE_FACTORY);
|
||||
vibSensBite = readSettingBounded(VIB_SENS_BITE_ADDR, 1, 17, VIB_SENS_BITE_FACTORY);
|
||||
vibSquelchBite = readSettingBounded(VIB_SQUELCH_BITE_ADDR, 1, 30, VIB_SQUELCH_BITE_FACTORY);
|
||||
vibControl = readSettingBounded(VIB_CONTROL_ADDR, 0, 2, VIB_CONTROL_FACTORY);
|
||||
dacMode = readSettingBounded(DAC_MODE_ADDR, DAC_MODE_BREATH, DAC_MODE_PITCH, DAC_MODE_FACTORY);
|
||||
trill3_interval = readSettingBounded(TRILL3_INTERVAL_ADDR, 3, 4, TRILL3_INTERVAL_FACTORY);
|
||||
extraCT2 = readSettingBounded(EXTRA2_ADDR, 0, 127, EXTRA2_FACTORY);
|
||||
levelCC = readSettingBounded(LEVEL_CC_ADDR, 0, 127, LEVEL_CC_FACTORY);
|
||||
levelVal = readSettingBounded(LEVEL_VAL_ADDR, 0, 127, LEVEL_VAL_FACTORY);
|
||||
#if defined(NURAD)
|
||||
fingering = readSettingBounded(FINGER_ADDR, 0, 4, FINGER_FACTORY);
|
||||
#else
|
||||
fingering = readSettingBounded(FINGER_ADDR, 0, 3, FINGER_FACTORY);
|
||||
#endif
|
||||
lpinky3 = readSettingBounded(LPINKY3_ADDR, 0, 25, LPINKY3_FACTORY);
|
||||
batteryType = readSettingBounded(BATTYPE_ADDR, 0, 2, BATTYPE_FACTORY);
|
||||
harmSetting = readSettingBounded(HARMSET_ADDR, 0, 6, HARMSET_FACTORY);
|
||||
harmSelect = readSettingBounded(HARMSEL_ADDR, 0, 7, HARMSEL_FACTORY);
|
||||
polySelect = (PolySelect)readSettingBounded(POLYSEL_ADDR, 0, 10, POLYSEL_FACTORY);
|
||||
fwcType = readSettingBounded(FWCTYPE_ADDR, 0, 4, FWCTYPE_FACTORY);
|
||||
fwcLockH = readSettingBounded(FWCLCH_ADDR, 0, 1, FWCLCH_FACTORY);
|
||||
fwcDrop2 = readSettingBounded(FWCDP2_ADDR, 0, 1, FWCDP2_FACTORY);
|
||||
hmzKey = readSettingBounded(HMZKEY_ADDR, 0, 11, HMZKEY_FACTORY);
|
||||
hmzLimit = readSettingBounded(HMZLIMIT_ADDR, 2, 5, HMZLIMIT_FACTORY);
|
||||
rotations_b.parallel = readSettingBounded(PARAB_ADDR, 0, 48, PARAB_FACTORY);
|
||||
rotations_b.rotations[0] = readSettingBounded(ROTB1_ADDR, 0, 48, ROTB1_FACTORY);
|
||||
rotations_b.rotations[1] = readSettingBounded(ROTB2_ADDR, 0, 48, ROTB2_FACTORY);
|
||||
rotations_b.rotations[2] = readSettingBounded(ROTB3_ADDR, 0, 48, ROTB3_FACTORY);
|
||||
rotations_b.rotations[3] = readSettingBounded(ROTB4_ADDR, 0, 48, ROTB4_FACTORY);
|
||||
rotations_c.parallel = readSettingBounded(PARAC_ADDR, 0, 48, PARAC_FACTORY);
|
||||
rotations_c.rotations[0] = readSettingBounded(ROTC1_ADDR, 0, 48, ROTC1_FACTORY);
|
||||
rotations_c.rotations[1] = readSettingBounded(ROTC2_ADDR, 0, 48, ROTC2_FACTORY);
|
||||
rotations_c.rotations[2] = readSettingBounded(ROTC3_ADDR, 0, 48, ROTC3_FACTORY);
|
||||
rotations_c.rotations[3] = readSettingBounded(ROTC4_ADDR, 0, 48, ROTC4_FACTORY);
|
||||
otfKey = readSettingBounded(OTFKEY_ADDR, 0, 1, OTFKEY_FACTORY);
|
||||
breathInterval = readSettingBounded(BRINTERV_ADDR, 3, 15, BRINTERV_FACTORY);
|
||||
portLimit = readSettingBounded(PORTLIMIT_ADDR, 1, 127, PORTLIMIT_FACTORY);
|
||||
leverThrVal = readSettingBounded(LEVER_THR_ADDR, leverLoLimit, leverHiLimit, LEVER_THR_FACTORY);
|
||||
leverMaxVal = readSettingBounded(LEVER_MAX_ADDR, leverLoLimit, leverHiLimit, LEVER_MAX_FACTORY);
|
||||
brHarmSetting = readSettingBounded(BRHARMSET_ADDR, 0, 6, BRHARMSET_FACTORY);
|
||||
brHarmSelect = readSettingBounded(BRHARMSEL_ADDR, 0, 3, BRHARMSEL_FACTORY);
|
||||
biteControl = readSettingBounded(BITECTL_ADDR, 0, 3, BITECTL_FACTORY);
|
||||
leverControl = readSettingBounded(LEVERCTL_ADDR, 0, 3, LEVERCTL_FACTORY);
|
||||
biteCC = readSettingBounded(BITECC_ADDR, 0, 127, BITECC_FACTORY);
|
||||
leverCC = readSettingBounded(LEVERCC_ADDR, 0, 127, LEVERCC_FACTORY);
|
||||
cvTune = readSettingBounded(CVTUNE_ADDR, 1, 199, CVTUNE_FACTORY);
|
||||
cvScale = readSettingBounded(CVSCALE_ADDR, 1, 199, CVSCALE_FACTORY);
|
||||
cvVibRate = readSettingBounded(CVRATE_ADDR, 0, 8, CVRATE_FACTORY);
|
||||
rollerMode = readSettingBounded(ROLLER_ADDR, 0, 3, ROLLER_FACTORY);
|
||||
|
||||
//Flags stored in bit field
|
||||
fastBoot = (dipSwBits & (1<<DIPSW_FASTBOOT))?1:0;
|
||||
legacy = (dipSwBits & (1<<DIPSW_LEGACY))?1:0;
|
||||
legacyBrAct = (dipSwBits & (1<<DIPSW_LEGACYBRACT))?1:0;
|
||||
widiOn = (dipSwBits & (1<<DIPSW_WIDION))?1:0;
|
||||
gateOpenEnable = (dipSwBits & (1<<DIPSW_GATEOPEN))?1:0;
|
||||
specialKeyEnable = (dipSwBits & (1<<DIPSW_SPKEYENABLE))?1:0;
|
||||
bcasMode = (dipSwBits & (1<<DIPSW_BCASMODE))?1:0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Poke at a certain bit in a bit field
|
||||
void setBit(uint16_t &bitfield, const uint8_t pos, const uint16_t value) {
|
||||
bitfield = (bitfield & ~(1<<pos)) | ((value?1:0)<<pos);
|
||||
}
|
||||
|
||||
|
||||
//Read and write EEPROM data
|
||||
void writeSetting(const uint16_t address, const uint16_t value) {
|
||||
union {
|
||||
uint8_t v[2];
|
||||
uint16_t val;
|
||||
} data;
|
||||
data.val = value;
|
||||
EEPROM.update(address, data.v[0]);
|
||||
EEPROM.update(address+1, data.v[1]);
|
||||
}
|
||||
|
||||
uint16_t readSetting(const uint16_t address) {
|
||||
union {
|
||||
uint8_t v[2];
|
||||
uint16_t val;
|
||||
} data;
|
||||
data.v[0] = EEPROM.read(address);
|
||||
data.v[1] = EEPROM.read(address+1);
|
||||
return data.val;
|
||||
}
|
||||
|
||||
uint16_t readSettingBounded(const uint16_t address, const uint16_t min, const uint16_t max, const uint16_t defaultValue) {
|
||||
uint16_t val = readSetting(address);
|
||||
if(val < min || val > max) {
|
||||
val = defaultValue;
|
||||
writeSetting(address, val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//Functions to send and receive config (and other things) via USB MIDI SysEx messages
|
||||
uint32_t crc32(const uint8_t *message, const size_t length) {
|
||||
size_t pos=0;
|
||||
uint32_t crc=0xFFFFFFFF;
|
||||
|
||||
while (pos<length) {
|
||||
crc ^= message[pos++]; //Get next byte and increment position
|
||||
for (uint8_t j=0; j<8; ++j) { //Mask off 8 next bits
|
||||
crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1));
|
||||
}
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Send EEPROM config dump as sysex message. Message format is structured like this:
|
||||
|
||||
+------------------------------------------------------------------------------------+
|
||||
| vendor(3) | "NuEVIc01" (8) | Payload size (2) | EEPROM data (variable) | crc32 (4) |
|
||||
+------------------------------------------------------------------------------------+
|
||||
|
||||
Payload size is for the EEPROM data chunk (not including anything else before or after
|
||||
CRC32 covers the entire buffer up to and including the eeprom data (but not the checksum itself)
|
||||
|
||||
This currently operates under the assumption that the whole EEPROM chunk only consists of unsigned 16 bit ints, only using the range 0-16383
|
||||
|
||||
*/
|
||||
void sendSysexSettings() {
|
||||
const char *header = "NuEVIc01"; //NuEVI config dump 01
|
||||
|
||||
//Build a send buffer of all the things
|
||||
size_t sysex_size = 3 + strlen(header) + 2 + EEPROM_SIZE + 4;
|
||||
uint8_t *sysex_data = (uint8_t*)malloc(sysex_size);
|
||||
|
||||
//Positions (offsets) of parts in send buffer
|
||||
int header_pos = 3;
|
||||
int size_pos = header_pos + strlen(header);
|
||||
int payload_pos = size_pos + 2;
|
||||
int checksum_pos = payload_pos + EEPROM_SIZE;
|
||||
|
||||
//SysEX manufacturer ID
|
||||
memcpy(sysex_data, sysex_id, 3);
|
||||
|
||||
//Header with command code
|
||||
memcpy(sysex_data+header_pos, header, strlen(header));
|
||||
|
||||
//Payload length
|
||||
*(uint16_t*)(sysex_data+size_pos) = convertToMidiValue(EEPROM_SIZE);
|
||||
|
||||
//Config data
|
||||
uint16_t* config_buffer_start = (uint16_t*)(sysex_data+payload_pos);
|
||||
|
||||
//Read one settings item at a time, change data format, and put in send buffer
|
||||
for(uint16_t idx=0; idx<EEPROM_SIZE/2; idx++) {
|
||||
uint16_t eepromval = readSetting(idx*2);
|
||||
config_buffer_start[idx] = convertToMidiValue(eepromval);
|
||||
}
|
||||
|
||||
uint32_t checksum = crc32(sysex_data, checksum_pos);
|
||||
|
||||
*(uint32_t*)(sysex_data+checksum_pos) = convertToMidiCRC(checksum);
|
||||
|
||||
usbMIDI.sendSysEx(sysex_size, sysex_data);
|
||||
|
||||
free(sysex_data);
|
||||
}
|
||||
|
||||
//Send a simple 3-byte message code as sysex
|
||||
void sendSysexMessage(const char* messageCode) {
|
||||
char sysexMessage[] = "vvvNuEVIccc"; //Placeholders for vendor and code
|
||||
|
||||
memcpy(sysexMessage, sysex_id, 3);
|
||||
memcpy(sysexMessage+8, messageCode, 3);
|
||||
|
||||
usbMIDI.sendSysEx(11, (const uint8_t *)sysexMessage);
|
||||
}
|
||||
|
||||
|
||||
bool receiveSysexSettings(const uint8_t* data, const uint16_t length) {
|
||||
|
||||
//Expected size of data (vendor+NuEVIc02+len+payload+crc32)
|
||||
uint16_t expected_size = 3 + 8 + 2 + EEPROM_SIZE + 4;
|
||||
|
||||
|
||||
//Positions (offsets) of parts in buffer
|
||||
int size_pos = 11;
|
||||
int payload_pos = size_pos + 2;
|
||||
int checksum_pos = payload_pos + EEPROM_SIZE;
|
||||
|
||||
//Make sure length of receive buffer is enough to read all we need to. We can accept extra junk at the end though.
|
||||
if(length<expected_size) {
|
||||
configShowMessage("Invalid config format");
|
||||
return false;
|
||||
}
|
||||
|
||||
//No need to verify vendor or header/command, already done before we get here.
|
||||
|
||||
//Calculate checksum of stuff received (everything before checksum), transform to midi format
|
||||
//(being a one-way operation, we can't do the reverse anyway)
|
||||
uint32_t crc=convertToMidiCRC(crc32(data, checksum_pos));
|
||||
uint32_t crc_rcv;
|
||||
memcpy(&crc_rcv, data+checksum_pos, 4);
|
||||
if(crc != crc_rcv && crc_rcv != NO_CHECKSUM) {
|
||||
configShowMessage("Invalid checksum");
|
||||
return false;
|
||||
}
|
||||
|
||||
//Verify that payload size matches the size of our EEPROM config
|
||||
uint16_t payload_size = convertFromMidiValue(data+size_pos);
|
||||
if(payload_size != EEPROM_SIZE) {
|
||||
configShowMessage("Invalid config size");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
uint16_t eeprom_version_rcv = convertFromMidiValue(data+(payload_pos+VERSION_ADDR));
|
||||
if(eeprom_version_rcv != EEPROM_VERSION) {
|
||||
configShowMessage("Invalid config version");
|
||||
return false;
|
||||
}
|
||||
|
||||
//Grab all the items in payload and save to EEPROM
|
||||
for(uint16_t i=0; i<payload_size/2; i++) {
|
||||
uint16_t addr = i*2;
|
||||
uint16_t val;
|
||||
val = convertFromMidiValue(data+(payload_pos+addr));
|
||||
|
||||
//Skip sensor calibration values if they are "out of bounds". This makes it possible to send a config that does
|
||||
//not overwrite sensor calibration.
|
||||
if(addr == BREATH_THR_ADDR || addr == BREATH_MAX_ADDR) {
|
||||
if(val<breathLoLimit || val>breathHiLimit) continue;
|
||||
}
|
||||
|
||||
if(addr == PORTAM_THR_ADDR || addr == PORTAM_MAX_ADDR) {
|
||||
if(val<portamLoLimit || val>portamHiLimit) continue;
|
||||
}
|
||||
|
||||
if(addr == PITCHB_THR_ADDR || addr == PITCHB_MAX_ADDR) {
|
||||
if(val<pitchbLoLimit || val>pitchbHiLimit) continue;
|
||||
}
|
||||
|
||||
if(addr == EXTRAC_THR_ADDR || addr == EXTRAC_MAX_ADDR) {
|
||||
if(val<extracLoLimit || val>extracHiLimit) continue;
|
||||
}
|
||||
|
||||
if(addr == CTOUCH_THR_ADDR) {
|
||||
if(val<ctouchLoLimit || val>ctouchHiLimit) continue;
|
||||
}
|
||||
|
||||
writeSetting(addr, val);
|
||||
}
|
||||
|
||||
//All went well
|
||||
return true;
|
||||
}
|
||||
|
||||
//Send EEPROM and firmware versions
|
||||
void sendSysexVersion() {
|
||||
char sysexMessage[] = "vvvNuEVIc04eevvvvvvvv"; //Placeholders for vendor and code
|
||||
uint8_t fwStrLen = min(strlen(FIRMWARE_VERSION), 8); //Limit firmware version string to 8 bytes
|
||||
|
||||
memcpy(sysexMessage, sysex_id, 3);
|
||||
memcpy(sysexMessage+13, FIRMWARE_VERSION, fwStrLen);
|
||||
|
||||
*(uint16_t*)(sysexMessage+11) = convertToMidiValue(EEPROM_VERSION);
|
||||
|
||||
uint8_t message_length = 13+fwStrLen;
|
||||
|
||||
usbMIDI.sendSysEx(message_length, (const uint8_t *)sysexMessage);
|
||||
}
|
||||
|
||||
extern Adafruit_SSD1306 display;
|
||||
|
||||
void configShowMessage(const char* message) {
|
||||
display.fillRect(0,32,128,64,BLACK);
|
||||
display.setCursor(0,32);
|
||||
display.setTextColor(WHITE);
|
||||
|
||||
display.print(message);
|
||||
|
||||
display.display();
|
||||
}
|
||||
|
||||
uint8_t* sysex_rcv_buffer = NULL;
|
||||
uint16_t sysex_buf_size = 0;
|
||||
|
||||
|
||||
void handleSysexChunk(const uint8_t *data, uint16_t length, bool last) {
|
||||
uint16_t pos;
|
||||
|
||||
if(!sysex_rcv_buffer) {
|
||||
//Start out with an empty buffer
|
||||
pos = 0;
|
||||
sysex_buf_size = length;
|
||||
sysex_rcv_buffer = (uint8_t *)malloc(sysex_buf_size);
|
||||
} else {
|
||||
//Increase size of current buffer
|
||||
pos = sysex_buf_size;
|
||||
sysex_buf_size += length;
|
||||
sysex_rcv_buffer = (uint8_t *)realloc(sysex_rcv_buffer, sysex_buf_size);
|
||||
}
|
||||
|
||||
//Append this chunk to buffer
|
||||
memcpy(sysex_rcv_buffer + pos, data, length);
|
||||
|
||||
//If it's the last one, call the regular handler to process it
|
||||
if(last) {
|
||||
handleSysex(sysex_rcv_buffer, sysex_buf_size);
|
||||
|
||||
//Discard the buffer
|
||||
free(sysex_rcv_buffer);
|
||||
sysex_rcv_buffer = NULL;
|
||||
sysex_buf_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void handleSysex(uint8_t *data, unsigned int length) {
|
||||
//Note: Sysex data as received here contains sysex start and end markers (0xF0 and 0xF7)
|
||||
|
||||
//Too short to even contain a 3-byte vendor id is not for us.
|
||||
if(length<4) return;
|
||||
|
||||
//Verify vendor
|
||||
if(strncmp((char*)(data+1), sysex_id, 3)) return; //Silently ignore different vendor id
|
||||
|
||||
//Verify header. Min length is 3+5+3 bytes (vendor+header+message code)
|
||||
if(length<12 || strncmp((char*)(data+4), "NuEVI", 5)) {
|
||||
configShowMessage("Invalid message.");
|
||||
sendSysexMessage("e00");
|
||||
return;
|
||||
}
|
||||
|
||||
//Get message code
|
||||
char messageCode[3];
|
||||
strncpy(messageCode, (char*)(data+9), 3);
|
||||
|
||||
if(!strncmp(messageCode, "c00", 3)) { //Config dump request
|
||||
configShowMessage("Sending config...");
|
||||
sendSysexSettings();
|
||||
configShowMessage("Config sent.");
|
||||
} else if(!strncmp(messageCode, "c03", 3)) { //Version info request
|
||||
configShowMessage("Sending version.");
|
||||
sendSysexVersion();
|
||||
} else if(!strncmp(messageCode, "c02", 3)) { //New config incoming
|
||||
configShowMessage("Receiving config...");
|
||||
|
||||
//Tell receiveSysexSettings about what's between sysex start and end markers
|
||||
if(receiveSysexSettings(data+1, length-2)) configShowMessage("New config saved.");
|
||||
} else {
|
||||
configShowMessage("Unknown message.");
|
||||
sendSysexMessage("e01"); //Unimplemented message code
|
||||
}
|
||||
}
|
||||
|
||||
void configModeSetup() {
|
||||
statusLedFlash(500);
|
||||
|
||||
display.clearDisplay();
|
||||
display.setCursor(0,0);
|
||||
display.setTextColor(WHITE);
|
||||
display.setTextSize(0);
|
||||
|
||||
display.println("Config mgmt");
|
||||
display.println("Power off NuEVI");
|
||||
display.println("to exit");
|
||||
display.display();
|
||||
|
||||
usbMIDI.setHandleSystemExclusive(handleSysexChunk);
|
||||
|
||||
statusLedFlash(500);
|
||||
|
||||
sendSysexVersion(); //Friendly hello
|
||||
|
||||
configShowMessage("Ready.");
|
||||
}
|
||||
|
||||
//"Main loop". Just sits and wait for midi messages and lets the sysex handler do all the work.
|
||||
void configModeLoop() {
|
||||
usbMIDI.read();
|
||||
}
|
||||
226
NuEVI/settings.h
226
NuEVI/settings.h
|
|
@ -1,226 +0,0 @@
|
|||
#ifndef __SETTINGS_H
|
||||
#define __SETTINGS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// EEPROM addresses for settings
|
||||
#define VERSION_ADDR 0
|
||||
#define BREATH_THR_ADDR 2
|
||||
#define BREATH_MAX_ADDR 4
|
||||
#define PORTAM_THR_ADDR 6
|
||||
#define PORTAM_MAX_ADDR 8
|
||||
#define PITCHB_THR_ADDR 10
|
||||
#define PITCHB_MAX_ADDR 12
|
||||
#define TRANSP_ADDR 14
|
||||
#define MIDI_ADDR 16
|
||||
#define BREATH_CC_ADDR 18
|
||||
#define BREATH_AT_ADDR 20
|
||||
#define VELOCITY_ADDR 22
|
||||
#define PORTAM_ADDR 24
|
||||
#define PB_ADDR 26
|
||||
#define EXTRA_ADDR 28
|
||||
#define VIBRATO_ADDR 30
|
||||
#define DEGLITCH_ADDR 32
|
||||
#define EXTRAC_THR_ADDR 34
|
||||
#define EXTRAC_MAX_ADDR 36
|
||||
#define PATCH_ADDR 38
|
||||
#define OCTAVE_ADDR 40
|
||||
#define CTOUCH_THR_ADDR 42
|
||||
#define BREATHCURVE_ADDR 44
|
||||
#define VEL_SMP_DL_ADDR 46
|
||||
#define VEL_BIAS_ADDR 48
|
||||
#define PINKY_KEY_ADDR 50
|
||||
#define FP1_ADDR 52
|
||||
#define FP2_ADDR 54
|
||||
#define FP3_ADDR 56
|
||||
#define FP4_ADDR 58
|
||||
#define FP5_ADDR 60
|
||||
#define FP6_ADDR 62
|
||||
#define FP7_ADDR 64
|
||||
#define DIPSW_BITS_ADDR 66
|
||||
#define PARAL_ADDR 68
|
||||
#define ROTN1_ADDR 70
|
||||
#define ROTN2_ADDR 72
|
||||
#define ROTN3_ADDR 74
|
||||
#define ROTN4_ADDR 76
|
||||
#define PRIO_ADDR 78
|
||||
#define VIB_SENS_ADDR 80
|
||||
#define VIB_RETN_ADDR 82
|
||||
#define VIB_SQUELCH_ADDR 84
|
||||
#define VIB_DIRECTION_ADDR 86
|
||||
#define BREATH_CC2_ADDR 88
|
||||
#define BREATH_CC2_RISE_ADDR 90
|
||||
#define VIB_SENS_BITE_ADDR 92
|
||||
#define VIB_SQUELCH_BITE_ADDR 94
|
||||
#define VIB_CONTROL_ADDR 96
|
||||
#define TRILL3_INTERVAL_ADDR 98
|
||||
#define DAC_MODE_ADDR 100
|
||||
#define EXTRA2_ADDR 102
|
||||
#define LEVEL_CC_ADDR 104
|
||||
#define LEVEL_VAL_ADDR 106
|
||||
#define FINGER_ADDR 108
|
||||
#define LPINKY3_ADDR 110
|
||||
#define BATTYPE_ADDR 112
|
||||
#define HARMSET_ADDR 114
|
||||
#define HARMSEL_ADDR 116
|
||||
#define PARAB_ADDR 118
|
||||
#define ROTB1_ADDR 120
|
||||
#define ROTB2_ADDR 122
|
||||
#define ROTB3_ADDR 124
|
||||
#define ROTB4_ADDR 126
|
||||
#define PARAC_ADDR 128
|
||||
#define ROTC1_ADDR 130
|
||||
#define ROTC2_ADDR 132
|
||||
#define ROTC3_ADDR 134
|
||||
#define ROTC4_ADDR 136
|
||||
#define POLYSEL_ADDR 138
|
||||
#define FWCTYPE_ADDR 140
|
||||
#define HMZKEY_ADDR 150
|
||||
#define FWCLCH_ADDR 152
|
||||
#define FWCDP2_ADDR 154
|
||||
#define HMZLIMIT_ADDR 156
|
||||
#define BRINTERV_ADDR 158
|
||||
#define OTFKEY_ADDR 160
|
||||
#define PORTLIMIT_ADDR 162
|
||||
#define LEVER_THR_ADDR 164
|
||||
#define LEVER_MAX_ADDR 166
|
||||
#define BRHARMSET_ADDR 168
|
||||
#define BRHARMSEL_ADDR 170
|
||||
#define BITECTL_ADDR 172
|
||||
#define BITECC_ADDR 174
|
||||
#define LEVERCTL_ADDR 176
|
||||
#define LEVERCC_ADDR 178
|
||||
#define CVTUNE_ADDR 180
|
||||
#define CVSCALE_ADDR 182
|
||||
#define CVRATE_ADDR 184
|
||||
#define ROLLER_ADDR 186
|
||||
|
||||
#define EEPROM_SIZE 188 //Last address +2
|
||||
|
||||
|
||||
//DAC output modes
|
||||
#define DAC_MODE_BREATH 0
|
||||
#define DAC_MODE_PITCH 1
|
||||
|
||||
#define DIPSW_FASTBOOT 0
|
||||
#define DIPSW_LEGACY 1
|
||||
#define DIPSW_LEGACYBRACT 2
|
||||
#define DIPSW_WIDION 3
|
||||
#define DIPSW_GATEOPEN 4
|
||||
#define DIPSW_SPKEYENABLE 5
|
||||
#define DIPSW_BCASMODE 6
|
||||
|
||||
|
||||
//"factory" values for settings
|
||||
#define EEPROM_VERSION 45
|
||||
|
||||
#define BREATH_THR_FACTORY 1400
|
||||
#define BREATH_MAX_FACTORY 4000
|
||||
#define PORTAM_THR_FACTORY 2600
|
||||
#define PORTAM_MAX_FACTORY 3300
|
||||
#define PORTPR_THR_FACTORY 1200
|
||||
#define PORTPR_MAX_FACTORY 2000
|
||||
#define PITCHB_THR_FACTORY 2000
|
||||
#define PITCHB_MAX_FACTORY 3000
|
||||
#define EXTRAC_THR_FACTORY 2800
|
||||
#define EXTRAC_MAX_FACTORY 3500
|
||||
#define LEVER_THR_FACTORY 1700
|
||||
#define LEVER_MAX_FACTORY 1800
|
||||
#define TRANSP_FACTORY 12 // 12 is 0 transpose
|
||||
#define MIDI_FACTORY 1 // 1-16
|
||||
#define BREATH_CC_FACTORY 2 //thats CC#2, see ccList
|
||||
#define BREATH_AT_FACTORY 0 //aftertouch default off
|
||||
#define VELOCITY_FACTORY 0 // 0 is dynamic/breath controlled velocity
|
||||
#define PORTAM_FACTORY 2 // 0 - OFF, 1 - ON, 2 - SW
|
||||
#define PB_FACTORY 1 // 0 - OFF, 1 - 12
|
||||
#define EXTRA_FACTORY 1 // 0 - OFF, 1 - Modulation wheel, 2 - Foot pedal, 3 - Filter Cutoff, 4 - Sustain pedal
|
||||
#define VIBRATO_FACTORY 4 // 0 - OFF, 1 - 9 depth
|
||||
#define DEGLITCH_FACTORY 20 // 0 - OFF, 5 to 70 ms in steps of 5
|
||||
#define PATCH_FACTORY 1 // MIDI program change 1-128
|
||||
#define OCTAVE_FACTORY 3 // 3 is 0 octave change
|
||||
#define CTOUCH_THR_FACTORY 125 // MPR121 touch threshold
|
||||
#define BREATHCURVE_FACTORY 4 // 0 to 12 (-4 to +4, S1 to S4)
|
||||
#define VEL_SMP_DL_FACTORY 20 // 0 to 30
|
||||
#define VEL_BIAS_FACTORY 0 // 0 to 9
|
||||
#define PINKY_KEY_FACTORY 12 // 0 - 11 (QuickTranspose -12 to -1), 12 (pb/2), 13 - 22 (QuickTranspose +1 to +12)
|
||||
#define DIPSW_BITS_FACTORY 0 // virtual dip switch settings for special modes (work in progress)
|
||||
#define PARAL_FACTORY 31 // 7 (+ 24) Rotator parallel
|
||||
#define ROTN1_FACTORY 19 // -5 (+24) Rotation 1
|
||||
#define ROTN2_FACTORY 14 // -10 (+24) Rotation 2
|
||||
#define ROTN3_FACTORY 17 // -7 (+24) Rotation 3
|
||||
#define ROTN4_FACTORY 10 // -14 (+24) Rotation 4
|
||||
#define PRIO_FACTORY 0 // Mono priority 0 - BAS(e note), 1 - ROT(ating note)
|
||||
#define VIB_SENS_FACTORY 6 // 1 least sensitive, higher more sensitive
|
||||
#define VIB_RETN_FACTORY 2 // 0, no return, 1 slow return, higher faster return
|
||||
#define VIB_SQUELCH_FACTORY 12 // 0 to 30, vib signal squelch
|
||||
#define VIB_DIRECTION_FACTORY 0
|
||||
#define BREATH_CC2_FACTORY 0 //OFF,1-127
|
||||
#define BREATH_CC2_RISE_FACTORY 1
|
||||
#define VIB_SENS_BITE_FACTORY 8
|
||||
#define VIB_SQUELCH_BITE_FACTORY 15
|
||||
#define VIB_CONTROL_FACTORY 0
|
||||
#define TRILL3_INTERVAL_FACTORY 4
|
||||
#define DAC_MODE_FACTORY DAC_MODE_PITCH
|
||||
#define EXTRA2_FACTORY 0
|
||||
#define LEVEL_CC_FACTORY 11
|
||||
#define LEVEL_VAL_FACTORY 127
|
||||
#define FINGER_FACTORY 0
|
||||
#define LPINKY3_FACTORY 0
|
||||
#define BATTYPE_FACTORY 0
|
||||
#define HARMSET_FACTORY 0
|
||||
#define HARMSEL_FACTORY 0
|
||||
#define PARAB_FACTORY 31 // 7 (+ 24) Rotator parallel
|
||||
#define ROTB1_FACTORY 19 // -5 (+24) Rotation 1
|
||||
#define ROTB2_FACTORY 14 // -10 (+24) Rotation 2
|
||||
#define ROTB3_FACTORY 17 // -7 (+24) Rotation 3
|
||||
#define ROTB4_FACTORY 10 // -14 (+24) Rotation 4
|
||||
#define PARAC_FACTORY 31 // 7 (+ 24) Rotator parallel
|
||||
#define ROTC1_FACTORY 19 // -5 (+24) Rotation 1
|
||||
#define ROTC2_FACTORY 14 // -10 (+24) Rotation 2
|
||||
#define ROTC3_FACTORY 17 // -7 (+24) Rotation 3
|
||||
#define ROTC4_FACTORY 10 // -14 (+24) Rotation 4
|
||||
#define POLYSEL_FACTORY 0
|
||||
#define FWCTYPE_FACTORY 0
|
||||
#define HMZKEY_FACTORY 0
|
||||
#define FWCLCH_FACTORY 0
|
||||
#define FWCDP2_FACTORY 0
|
||||
#define HMZLIMIT_FACTORY 5
|
||||
#define BRINTERV_FACTORY 6
|
||||
#define OTFKEY_FACTORY 0
|
||||
#define PORTLIMIT_FACTORY 127
|
||||
#define BRHARMSET_FACTORY 0
|
||||
#define BRHARMSEL_FACTORY 0
|
||||
#define BITECTL_FACTORY 2 // GLD
|
||||
#define LEVERCTL_FACTORY 1 // VIB
|
||||
#define BITECC_FACTORY 1 //Mod Wheel
|
||||
#define LEVERCC_FACTORY 11 //Expression
|
||||
#define CVTUNE_FACTORY 100 // 100 is zero tuning
|
||||
#define CVSCALE_FACTORY 100 // 100 is zero scaling
|
||||
#define CVRATE_FACTORY 3 // 3 is 5.5Hz
|
||||
#define ROLLER_FACTORY 1
|
||||
|
||||
#define NO_CHECKSUM 0x7F007F00
|
||||
|
||||
void readEEPROM(const bool factoryReset);
|
||||
void setBit(uint16_t &bitfield, const uint8_t pos, const uint16_t value);
|
||||
uint16_t readSetting(const uint16_t address);
|
||||
void writeSetting(const uint16_t address, const uint16_t value);
|
||||
uint16_t readSettingBounded(const uint16_t address, const uint16_t min, const uint16_t max, const uint16_t defaultValue);
|
||||
|
||||
//Functions for config management mode
|
||||
void sendSysexSettings();
|
||||
void sendSysexMessage(const char* messageCode);
|
||||
void sendSysexVersion();
|
||||
|
||||
void handleSysex(uint8_t *data, unsigned int length);
|
||||
void handleSysexChunk(const uint8_t *data, uint16_t length, bool last);
|
||||
|
||||
uint32_t crc32(const uint8_t *message, const size_t length);
|
||||
|
||||
void configInitScreen();
|
||||
void configShowMessage(const char* message);
|
||||
|
||||
void configModeSetup();
|
||||
void configModeLoop();
|
||||
|
||||
#endif
|
||||
478
NuEVI/FilterOnePole.cpp → NuEVI/src/FilterOnePole.cpp
Executable file → Normal file
478
NuEVI/FilterOnePole.cpp → NuEVI/src/FilterOnePole.cpp
Executable file → Normal file
|
|
@ -1,240 +1,238 @@
|
|||
// Copyright 2014 Jonathan Driscoll
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "FilterOnePole.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
FilterOnePole::FilterOnePole( FILTER_TYPE ft, float fc, float initialValue ) {
|
||||
setFilter( ft, fc, initialValue );
|
||||
}
|
||||
|
||||
void FilterOnePole::setFilter( FILTER_TYPE ft, float fc, float initialValue ) {
|
||||
FT = ft;
|
||||
setFrequency( fc );
|
||||
|
||||
Y = initialValue;
|
||||
Ylast = initialValue;
|
||||
X = initialValue;
|
||||
|
||||
LastUS = micros();
|
||||
}
|
||||
|
||||
float FilterOnePole::input( float inVal ) {
|
||||
long time = micros();
|
||||
ElapsedUS = float(time - LastUS); // cast to float here, for math
|
||||
LastUS = time; // update this now
|
||||
|
||||
// shift the data values
|
||||
Ylast = Y;
|
||||
X = inVal; // this is now the most recent input value
|
||||
|
||||
// filter value is controlled by a parameter called X
|
||||
// tau is set by the user in microseconds, but must be converted to samples here
|
||||
TauSamps = TauUS / ElapsedUS;
|
||||
|
||||
float ampFactor;
|
||||
#ifdef ARM_FLOAT
|
||||
ampFactor = expf( -1.0 / TauSamps ); // this is 1 if called quickly
|
||||
#else
|
||||
ampFactor = exp( -1.0 / TauSamps ); // this is 1 if called quickly
|
||||
#endif
|
||||
|
||||
Y = (1.0-ampFactor)*X + ampFactor*Ylast; // set the new value
|
||||
|
||||
return output();
|
||||
}
|
||||
|
||||
void FilterOnePole::setFrequency( float newFrequency ) {
|
||||
setTau( 1.0/(TWO_PI*newFrequency ) ); // τ=1/ω
|
||||
}
|
||||
|
||||
void FilterOnePole::setTau( float newTau ) {
|
||||
TauUS = newTau * 1e6;
|
||||
}
|
||||
|
||||
float FilterOnePole::output() {
|
||||
// figure out which button to read
|
||||
switch (FT) {
|
||||
case LOWPASS:
|
||||
// return the last value
|
||||
return Y;
|
||||
break;
|
||||
case INTEGRATOR:
|
||||
// using a lowpass, but normaize
|
||||
return Y * (TauUS/1.0e6);
|
||||
break;
|
||||
case HIGHPASS:
|
||||
// highpass is the _difference_
|
||||
return X-Y;
|
||||
break;
|
||||
case DIFFERENTIATOR:
|
||||
// like a highpass, but normalize
|
||||
return (X-Y)/(TauUS/1.0e6);
|
||||
break;
|
||||
default:
|
||||
// should never get to here, return 0 just in case
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FilterOnePole::print() {
|
||||
Serial.println("");
|
||||
Serial.print(" Y: "); Serial.print( Y );
|
||||
Serial.print(" Ylast: "); Serial.print( Ylast );
|
||||
Serial.print(" X "); Serial.print( X );
|
||||
Serial.print(" ElapsedUS "); Serial.print( ElapsedUS );
|
||||
Serial.print(" TauSamps: "); Serial.print( TauSamps );
|
||||
//Serial.print(" ampFactor " ); Serial.print( ampFactor );
|
||||
Serial.print(" TauUS: "); Serial.print( TauUS );
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
void FilterOnePole::test() {
|
||||
float tau = 10;
|
||||
float updateInterval = 1;
|
||||
float nextupdateTime = millis()*1e-3;
|
||||
|
||||
float inputValue = 0;
|
||||
FilterOnePole hp( HIGHPASS, tau, inputValue );
|
||||
FilterOnePole lp( LOWPASS, tau, inputValue );
|
||||
|
||||
while( true ) {
|
||||
float now = millis()*1e-3;
|
||||
|
||||
// switch input values on a 20 second cycle
|
||||
if( round(now/20.0)-(now/20.0) < 0 )
|
||||
inputValue = 0;
|
||||
else
|
||||
inputValue = 100;
|
||||
|
||||
hp.input(inputValue);
|
||||
lp.input(inputValue);
|
||||
|
||||
if( now > nextupdateTime ) {
|
||||
nextupdateTime += updateInterval;
|
||||
|
||||
Serial.print("inputValue: "); Serial.print( inputValue );
|
||||
Serial.print("\t high-passed: "); Serial.print( hp.output() );
|
||||
Serial.print("\t low-passed: "); Serial.print( lp.output() );
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FilterOnePole::setToNewValue( float newVal ) {
|
||||
Y = Ylast = X = newVal;
|
||||
}
|
||||
|
||||
|
||||
// stuff for filter2 (lowpass only)
|
||||
// should be able to set a separate fall time as well
|
||||
FilterOnePoleCascade::FilterOnePoleCascade( float riseTime, float initialValue ) {
|
||||
setRiseTime( riseTime );
|
||||
setToNewValue( initialValue );
|
||||
}
|
||||
|
||||
void FilterOnePoleCascade::setRiseTime( float riseTime ) {
|
||||
float tauScale = 3.36; // found emperically, by running test();
|
||||
|
||||
Pole1.setTau( riseTime / tauScale );
|
||||
Pole2.setTau( riseTime / tauScale );
|
||||
}
|
||||
|
||||
float FilterOnePoleCascade::input( float inVal ) {
|
||||
Pole2.input( Pole1.input( inVal ));
|
||||
return output();
|
||||
}
|
||||
|
||||
// clears out the values in the filter
|
||||
void FilterOnePoleCascade::setToNewValue( float newVal ) {
|
||||
Pole1.setToNewValue( newVal );
|
||||
Pole2.setToNewValue( newVal );
|
||||
}
|
||||
|
||||
float FilterOnePoleCascade::output() {
|
||||
return Pole2.output();
|
||||
}
|
||||
|
||||
void FilterOnePoleCascade::test() {
|
||||
// make a filter, how fast does it run:
|
||||
|
||||
float rise = 1.0;
|
||||
FilterOnePoleCascade myFilter( rise );
|
||||
|
||||
// first, test the filter speed ...
|
||||
long nLoops = 1000;
|
||||
|
||||
Serial.print( "testing filter with a rise time of ");
|
||||
Serial.print( rise ); Serial.print( "s" );
|
||||
|
||||
Serial.print( "\n running filter speed loop ... ");
|
||||
|
||||
float startTime, stopTime;
|
||||
|
||||
startTime = millis()*1e-3;
|
||||
for( long i=0; i<nLoops; ++i ) {
|
||||
myFilter.input( PI ); // use pi, so it will actually do a full calculation
|
||||
}
|
||||
stopTime = millis()*1e-3;
|
||||
|
||||
Serial.print( "done, filter runs at " );
|
||||
Serial.print( float(nLoops) / (stopTime - startTime) );
|
||||
Serial.print( " hz " );
|
||||
Serial.print( "\n filter value: " ); Serial.print( myFilter.output() );
|
||||
|
||||
myFilter.setToNewValue( 0.0 );
|
||||
Serial.print( "\n after reset to 0: "); Serial.print( myFilter.output() );
|
||||
|
||||
Serial.print( "\n testing rise time (10% to 90%) ...");
|
||||
|
||||
bool crossedTenPercent = false;
|
||||
while( myFilter.output() < 0.9 ) {
|
||||
myFilter.input( 1.0 );
|
||||
if( myFilter.output() > 0.1 && !crossedTenPercent ) {
|
||||
// filter first crossed the 10% point
|
||||
startTime = millis()*1e-3;
|
||||
crossedTenPercent = true;
|
||||
}
|
||||
}
|
||||
stopTime = millis()*1e-3;
|
||||
|
||||
Serial.print( "done, rise time: " ); Serial.print( stopTime-startTime );
|
||||
|
||||
Serial.print( "testing attenuation at f = 1/risetime" );
|
||||
|
||||
myFilter.setToNewValue( 0.0 );
|
||||
|
||||
float maxVal = 0;
|
||||
float valWasOutputThisCycle = true;
|
||||
|
||||
__unused float lastFilterVal = 0;
|
||||
|
||||
while( true ) {
|
||||
float now = 1e-3*millis();
|
||||
|
||||
float currentFilterVal = myFilter.input( sin( TWO_PI*now) );
|
||||
|
||||
if( currentFilterVal < 0.0 ) {
|
||||
if( !valWasOutputThisCycle ) {
|
||||
// just crossed below zero, output the max
|
||||
Serial.print( maxVal*100 ); Serial.print( " %\n" );
|
||||
valWasOutputThisCycle = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// Copyright 2014 Jonathan Driscoll
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "FilterOnePole.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
FilterOnePole::FilterOnePole( FILTER_TYPE ft, float fc, float initialValue ) {
|
||||
setFilter( ft, fc, initialValue );
|
||||
}
|
||||
|
||||
void FilterOnePole::setFilter( FILTER_TYPE ft, float fc, float initialValue ) {
|
||||
FT = ft;
|
||||
setFrequency( fc );
|
||||
|
||||
Y = initialValue;
|
||||
Ylast = initialValue;
|
||||
X = initialValue;
|
||||
|
||||
LastUS = micros();
|
||||
}
|
||||
|
||||
float FilterOnePole::input( float inVal ) {
|
||||
long time = micros();
|
||||
ElapsedUS = float(time - LastUS); // cast to float here, for math
|
||||
LastUS = time; // update this now
|
||||
|
||||
// shift the data values
|
||||
Ylast = Y;
|
||||
X = inVal; // this is now the most recent input value
|
||||
|
||||
// filter value is controlled by a parameter called X
|
||||
// tau is set by the user in microseconds, but must be converted to samples here
|
||||
TauSamps = TauUS / ElapsedUS;
|
||||
|
||||
float ampFactor;
|
||||
#ifdef ARM_FLOAT
|
||||
ampFactor = expf( -1.0 / TauSamps ); // this is 1 if called quickly
|
||||
#else
|
||||
ampFactor = exp( -1.0 / TauSamps ); // this is 1 if called quickly
|
||||
#endif
|
||||
|
||||
Y = (1.0-ampFactor)*X + ampFactor*Ylast; // set the new value
|
||||
|
||||
return output();
|
||||
}
|
||||
|
||||
void FilterOnePole::setFrequency( float newFrequency ) {
|
||||
setTau( 1.0/(TWO_PI*newFrequency ) ); // τ=1/ω
|
||||
}
|
||||
|
||||
void FilterOnePole::setTau( float newTau ) {
|
||||
TauUS = newTau * 1e6;
|
||||
}
|
||||
|
||||
float FilterOnePole::output() {
|
||||
// figure out which button to read
|
||||
switch (FT) {
|
||||
case LOWPASS:
|
||||
// return the last value
|
||||
return Y;
|
||||
break;
|
||||
case INTEGRATOR:
|
||||
// using a lowpass, but normaize
|
||||
return Y * (TauUS/1.0e6);
|
||||
break;
|
||||
case HIGHPASS:
|
||||
// highpass is the _difference_
|
||||
return X-Y;
|
||||
break;
|
||||
case DIFFERENTIATOR:
|
||||
// like a highpass, but normalize
|
||||
return (X-Y)/(TauUS/1.0e6);
|
||||
break;
|
||||
default:
|
||||
// should never get to here, return 0 just in case
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FilterOnePole::print() {
|
||||
Serial.println("");
|
||||
Serial.print(" Y: "); Serial.print( Y );
|
||||
Serial.print(" Ylast: "); Serial.print( Ylast );
|
||||
Serial.print(" X "); Serial.print( X );
|
||||
Serial.print(" ElapsedUS "); Serial.print( ElapsedUS );
|
||||
Serial.print(" TauSamps: "); Serial.print( TauSamps );
|
||||
//Serial.print(" ampFactor " ); Serial.print( ampFactor );
|
||||
Serial.print(" TauUS: "); Serial.print( TauUS );
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
void FilterOnePole::test() {
|
||||
float tau = 10;
|
||||
float updateInterval = 1;
|
||||
float nextupdateTime = millis()*1e-3;
|
||||
|
||||
float inputValue = 0;
|
||||
FilterOnePole hp( HIGHPASS, tau, inputValue );
|
||||
FilterOnePole lp( LOWPASS, tau, inputValue );
|
||||
|
||||
while( true ) {
|
||||
float now = millis()*1e-3;
|
||||
|
||||
// switch input values on a 20 second cycle
|
||||
if( round(now/20.0)-(now/20.0) < 0 )
|
||||
inputValue = 0;
|
||||
else
|
||||
inputValue = 100;
|
||||
|
||||
hp.input(inputValue);
|
||||
lp.input(inputValue);
|
||||
|
||||
if( now > nextupdateTime ) {
|
||||
nextupdateTime += updateInterval;
|
||||
|
||||
Serial.print("inputValue: "); Serial.print( inputValue );
|
||||
Serial.print("\t high-passed: "); Serial.print( hp.output() );
|
||||
Serial.print("\t low-passed: "); Serial.print( lp.output() );
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FilterOnePole::setToNewValue( float newVal ) {
|
||||
Y = Ylast = X = newVal;
|
||||
}
|
||||
|
||||
|
||||
// stuff for filter2 (lowpass only)
|
||||
// should be able to set a separate fall time as well
|
||||
FilterOnePoleCascade::FilterOnePoleCascade( float riseTime, float initialValue ) {
|
||||
setRiseTime( riseTime );
|
||||
setToNewValue( initialValue );
|
||||
}
|
||||
|
||||
void FilterOnePoleCascade::setRiseTime( float riseTime ) {
|
||||
float tauScale = 3.36; // found emperically, by running test();
|
||||
|
||||
Pole1.setTau( riseTime / tauScale );
|
||||
Pole2.setTau( riseTime / tauScale );
|
||||
}
|
||||
|
||||
float FilterOnePoleCascade::input( float inVal ) {
|
||||
Pole2.input( Pole1.input( inVal ));
|
||||
return output();
|
||||
}
|
||||
|
||||
// clears out the values in the filter
|
||||
void FilterOnePoleCascade::setToNewValue( float newVal ) {
|
||||
Pole1.setToNewValue( newVal );
|
||||
Pole2.setToNewValue( newVal );
|
||||
}
|
||||
|
||||
float FilterOnePoleCascade::output() {
|
||||
return Pole2.output();
|
||||
}
|
||||
|
||||
void FilterOnePoleCascade::test() {
|
||||
// make a filter, how fast does it run:
|
||||
|
||||
float rise = 1.0;
|
||||
FilterOnePoleCascade myFilter( rise );
|
||||
|
||||
// first, test the filter speed ...
|
||||
long nLoops = 1000;
|
||||
|
||||
Serial.print( "testing filter with a rise time of ");
|
||||
Serial.print( rise ); Serial.print( "s" );
|
||||
|
||||
Serial.print( "\n running filter speed loop ... ");
|
||||
|
||||
float startTime, stopTime;
|
||||
|
||||
startTime = millis()*1e-3;
|
||||
for( long i=0; i<nLoops; ++i ) {
|
||||
myFilter.input( PI ); // use pi, so it will actually do a full calculation
|
||||
}
|
||||
stopTime = millis()*1e-3;
|
||||
|
||||
Serial.print( "done, filter runs at " );
|
||||
Serial.print( float(nLoops) / (stopTime - startTime) );
|
||||
Serial.print( " hz " );
|
||||
Serial.print( "\n filter value: " ); Serial.print( myFilter.output() );
|
||||
|
||||
myFilter.setToNewValue( 0.0 );
|
||||
Serial.print( "\n after reset to 0: "); Serial.print( myFilter.output() );
|
||||
|
||||
Serial.print( "\n testing rise time (10% to 90%) ...");
|
||||
|
||||
bool crossedTenPercent = false;
|
||||
while( myFilter.output() < 0.9 ) {
|
||||
myFilter.input( 1.0 );
|
||||
if( myFilter.output() > 0.1 && !crossedTenPercent ) {
|
||||
// filter first crossed the 10% point
|
||||
startTime = millis()*1e-3;
|
||||
crossedTenPercent = true;
|
||||
}
|
||||
}
|
||||
stopTime = millis()*1e-3;
|
||||
|
||||
Serial.print( "done, rise time: " ); Serial.print( stopTime-startTime );
|
||||
|
||||
Serial.print( "testing attenuation at f = 1/risetime" );
|
||||
|
||||
myFilter.setToNewValue( 0.0 );
|
||||
|
||||
float maxVal = 0;
|
||||
float valWasOutputThisCycle = true;
|
||||
|
||||
while( true ) {
|
||||
float now = 1e-3*millis();
|
||||
|
||||
float currentFilterVal = myFilter.input( sin( TWO_PI*now) );
|
||||
|
||||
if( currentFilterVal < 0.0 ) {
|
||||
if( !valWasOutputThisCycle ) {
|
||||
// just crossed below zero, output the max
|
||||
Serial.print( maxVal*100 ); Serial.print( " %\n" );
|
||||
valWasOutputThisCycle = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
178
NuEVI/FilterOnePole.h → NuEVI/src/FilterOnePole.h
Executable file → Normal file
178
NuEVI/FilterOnePole.h → NuEVI/src/FilterOnePole.h
Executable file → Normal file
|
|
@ -1,89 +1,89 @@
|
|||
// Copyright 2014 Jonathan Driscoll
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// FilterOnePole has been copied from https://github.com/JonHub/Filters
|
||||
|
||||
|
||||
#ifndef FilterOnePole_h
|
||||
#define FilterOnePole_h
|
||||
|
||||
enum FILTER_TYPE {
|
||||
HIGHPASS,
|
||||
LOWPASS,
|
||||
INTEGRATOR,
|
||||
DIFFERENTIATOR
|
||||
};
|
||||
|
||||
// the recursive filter class implements a recursive filter (low / pass / highpass
|
||||
// note that this must be updated in a loop, using the most recent acquired values and the time acquired
|
||||
// Y = a0*X + a1*Xm1
|
||||
// + b1*Ylast
|
||||
struct FilterOnePole {
|
||||
FILTER_TYPE FT;
|
||||
float TauUS; // decay constant of the filter, in US
|
||||
float TauSamps; // tau, measued in samples (this changes, depending on how long between input()s
|
||||
|
||||
// filter values - these are public, but should not be set externally
|
||||
float Y; // most recent output value (gets computed on update)
|
||||
float Ylast; // prevous output value
|
||||
|
||||
float X; // most recent input value
|
||||
|
||||
// elapsed times are kept in long, and will wrap every
|
||||
// 35 mins, 47 seconds ... however, the wrap does not matter,
|
||||
// because the delta will still be correct (always positive and small)
|
||||
float ElapsedUS; // time since last update
|
||||
long LastUS; // last time measured
|
||||
|
||||
FilterOnePole( FILTER_TYPE ft=LOWPASS, float fc=1.0, float initialValue=0 );
|
||||
|
||||
// sets or resets the parameters and state of the filter
|
||||
void setFilter( FILTER_TYPE ft, float tauS, float initialValue );
|
||||
|
||||
void setFrequency( float newFrequency );
|
||||
|
||||
void setTau( float newTau );
|
||||
|
||||
float input( float inVal );
|
||||
|
||||
float output();
|
||||
|
||||
void print();
|
||||
|
||||
void test();
|
||||
|
||||
void setToNewValue( float newVal ); // resets the filter to a new value
|
||||
};
|
||||
|
||||
// two pole filter, these are very useful
|
||||
struct FilterOnePoleCascade {
|
||||
|
||||
FilterOnePole Pole1;
|
||||
FilterOnePole Pole2;
|
||||
|
||||
FilterOnePoleCascade( float riseTime=1.0, float initialValue=0 ); // rise time to step function, 10% to 90%
|
||||
|
||||
// rise time is 10% to 90%, for a step input
|
||||
void setRiseTime( float riseTime );
|
||||
|
||||
void setToNewValue( float newVal );
|
||||
|
||||
float input( float inVal );
|
||||
|
||||
float output();
|
||||
|
||||
void test();
|
||||
};
|
||||
|
||||
#endif
|
||||
// Copyright 2014 Jonathan Driscoll
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// FilterOnePole has been copied from https://github.com/JonHub/Filters
|
||||
|
||||
|
||||
#ifndef FilterOnePole_h
|
||||
#define FilterOnePole_h
|
||||
|
||||
enum FILTER_TYPE {
|
||||
HIGHPASS,
|
||||
LOWPASS,
|
||||
INTEGRATOR,
|
||||
DIFFERENTIATOR
|
||||
};
|
||||
|
||||
// the recursive filter class implements a recursive filter (low / pass / highpass
|
||||
// note that this must be updated in a loop, using the most recent acquired values and the time acquired
|
||||
// Y = a0*X + a1*Xm1
|
||||
// + b1*Ylast
|
||||
struct FilterOnePole {
|
||||
FILTER_TYPE FT;
|
||||
float TauUS; // decay constant of the filter, in US
|
||||
float TauSamps; // tau, measued in samples (this changes, depending on how long between input()s
|
||||
|
||||
// filter values - these are public, but should not be set externally
|
||||
float Y; // most recent output value (gets computed on update)
|
||||
float Ylast; // prevous output value
|
||||
|
||||
float X; // most recent input value
|
||||
|
||||
// elapsed times are kept in long, and will wrap every
|
||||
// 35 mins, 47 seconds ... however, the wrap does not matter,
|
||||
// because the delta will still be correct (always positive and small)
|
||||
float ElapsedUS; // time since last update
|
||||
long LastUS; // last time measured
|
||||
|
||||
FilterOnePole( FILTER_TYPE ft=LOWPASS, float fc=1.0, float initialValue=0 );
|
||||
|
||||
// sets or resets the parameters and state of the filter
|
||||
void setFilter( FILTER_TYPE ft, float tauS, float initialValue );
|
||||
|
||||
void setFrequency( float newFrequency );
|
||||
|
||||
void setTau( float newTau );
|
||||
|
||||
float input( float inVal );
|
||||
|
||||
float output();
|
||||
|
||||
void print();
|
||||
|
||||
void test();
|
||||
|
||||
void setToNewValue( float newVal ); // resets the filter to a new value
|
||||
};
|
||||
|
||||
// two pole filter, these are very useful
|
||||
struct FilterOnePoleCascade {
|
||||
|
||||
FilterOnePole Pole1;
|
||||
FilterOnePole Pole2;
|
||||
|
||||
FilterOnePoleCascade( float riseTime=1.0, float initialValue=0 ); // rise time to step function, 10% to 90%
|
||||
|
||||
// rise time is 10% to 90%, for a step input
|
||||
void setRiseTime( float riseTime );
|
||||
|
||||
void setToNewValue( float newVal );
|
||||
|
||||
float input( float inVal );
|
||||
|
||||
float output();
|
||||
|
||||
void test();
|
||||
};
|
||||
|
||||
#endif
|
||||
8
NuEVI/src/TODO
Normal file
8
NuEVI/src/TODO
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
1. LED abstraction code
|
||||
2. Encoder code
|
||||
3. Menu refactor
|
||||
4. Refactor note play behavior into module
|
||||
5. Refactor CV behavior into module
|
||||
6. 9dof sensor code
|
||||
7. Alternate fingerings
|
||||
8. Encoder midi
|
||||
175
NuEVI/src/adjustmenu.cpp
Normal file
175
NuEVI/src/adjustmenu.cpp
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
#include <array>
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include "menu.h"
|
||||
#include "globals.h"
|
||||
#include "config.h"
|
||||
#include "hardware.h"
|
||||
#include "settings.h"
|
||||
|
||||
//***********************************************************
|
||||
|
||||
extern Adafruit_SSD1306 display;
|
||||
extern Adafruit_MPR121 touchSensorUtil;
|
||||
extern Adafruit_MPR121 touchSensorKeys;
|
||||
extern Adafruit_MPRLS pressureSensorMain;
|
||||
extern Adafruit_MPRLS pressureSensorAlt;
|
||||
extern byte cursorNow;
|
||||
|
||||
int16_t ctouchVal = 0;
|
||||
|
||||
// Track pixels for faster redrawing
|
||||
struct AdjustDrawing {
|
||||
int row;
|
||||
int thrX;
|
||||
int maxX;
|
||||
int valX;
|
||||
};
|
||||
|
||||
struct AdjustValue {
|
||||
const char *title;
|
||||
const int16_t &value;
|
||||
int16_t &thrVal;
|
||||
int16_t &maxVal;
|
||||
const int16_t limitLow;
|
||||
const int16_t limitHigh;
|
||||
|
||||
// If not null, thr and max are relative to zeroPoint
|
||||
const int16_t *zeroPoint;
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
class AdjustMenuScreen : public MenuScreen {
|
||||
public:
|
||||
AdjustMenuScreen(const char* title, std::array<AdjustValue, N> entries) : _title(title), _entries(entries) { }
|
||||
void update(InputState input, bool redraw) {
|
||||
bool redrawIndicators = false;
|
||||
if (input.changed) {
|
||||
if (input.knobMenu) {
|
||||
_selectedEntry = _selectedEntry + input.knobMenu;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
AdjustValue value = _entries[_selectedEntry];
|
||||
if (input.knobVal1) {
|
||||
value.thrVal += input.knobVal1;
|
||||
redrawIndicators = true;
|
||||
}
|
||||
|
||||
if (input.knobVal2) {
|
||||
value.maxVal += input.knobVal2;
|
||||
redrawIndicators = true;
|
||||
}
|
||||
} else {
|
||||
draw(redrawIndicators, redraw);
|
||||
}
|
||||
}
|
||||
const char *title() {
|
||||
return _title;
|
||||
}
|
||||
private:
|
||||
void draw(bool redrawIndicators, bool redraw) {
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
if (redraw) {
|
||||
drawAdjustRow(_entries[i], _rowDrawings[i], i == _selectedEntry);
|
||||
} else if (redrawIndicators && i == _selectedEntry) {
|
||||
drawAdjustIndicators(_entries[i], _rowDrawings[i]);
|
||||
} else {
|
||||
drawAdjustValues(_entries[i], _rowDrawings[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* _title;
|
||||
size_t _selectedEntry = 0;
|
||||
std::array<AdjustValue, N> _entries;
|
||||
std::array<AdjustDrawing, N> _rowDrawings;
|
||||
};
|
||||
|
||||
std::array<AdjustValue, 8> adjustValues = {{
|
||||
{"BREATH", state.breathSignal, calibration.breathThrValOffset, calibration.breathMaxValOffset,
|
||||
BREATH_LO_LIMIT, BREATH_HI_LIMIT, &state.breathZero},
|
||||
{"BR ALT", state.breathAltSignal, calibration.breathAltThrValOffset, calibration.breathAltMaxValOffset,
|
||||
BREATH_LO_LIMIT, BREATH_HI_LIMIT, &state.breathAltZero},
|
||||
{"BITE",state.biteSignal, calibration.biteThrVal, calibration.biteMaxVal, BITE_LO_LIMIT, BITE_HI_LIMIT, NULL},
|
||||
{"PB DOWN",state.pbDnSignal, calibration.pbDnThrVal, calibration.pbDnMaxVal, PITCHB_LO_LIMIT, PITCHB_HI_LIMIT, NULL},
|
||||
{"PB UP", state.pbUpSignal, calibration.pbUpThrVal, calibration.pbUpMaxVal, PITCHB_LO_LIMIT, PITCHB_HI_LIMIT, NULL},
|
||||
{"EXTRA", state.extraSignal, calibration.extraThrVal, calibration.extraMaxVal, EXTRA_LO_LIMIT, EXTRA_HI_LIMIT, NULL},
|
||||
{"LEVER", state.leverSignal, calibration.leverThrVal, calibration.leverMaxVal, LEVER_LO_LIMIT, LEVER_HI_LIMIT, NULL},
|
||||
{"TOUCH", ctouchVal, calibration.ctouchThrVal, calibration.ctouchThrVal, CTOUCH_LO_LIMIT, CTOUCH_HI_LIMIT, NULL},
|
||||
}};
|
||||
|
||||
const MenuScreen adjustMenu = AdjustMenuScreen<8>("ADJUST", adjustValues);
|
||||
|
||||
void autoCalSelected() {
|
||||
}
|
||||
|
||||
//***********************************************************
|
||||
|
||||
|
||||
static void drawIndicator(int x, int row, int color) {
|
||||
display.fillTriangle(x-2, row+1, x+2, row+1, x, row+3, color);
|
||||
display.fillTriangle(x-2, row+10, x+2, row+10, x, row+7, color);
|
||||
}
|
||||
|
||||
static void drawAdjustIndicators(const AdjustValue &value, AdjustDrawing &drawing) {
|
||||
const int thrX = mapConstrain(value.thrVal, value.limitLow, value.limitHigh, 1, 127);
|
||||
const int maxX = mapConstrain(value.maxVal, value.limitLow, value.limitHigh, 1, 127);
|
||||
if (drawing.maxX != maxX) {
|
||||
drawIndicator(drawing.thrX, drawing.row, BLACK);
|
||||
drawIndicator(thrX, drawing.row, WHITE);
|
||||
drawing.maxX = maxX;
|
||||
}
|
||||
|
||||
if (drawing.thrX != thrX) {
|
||||
drawIndicator(drawing.thrX, drawing.row, BLACK);
|
||||
drawIndicator(thrX, drawing.row, WHITE);
|
||||
drawing.thrX = thrX;
|
||||
}
|
||||
}
|
||||
|
||||
static void drawAdjustTitle(const AdjustValue &value, AdjustDrawing &drawing, bool highlight) {
|
||||
display.setTextSize(1);
|
||||
if (highlight) {
|
||||
display.setTextColor(BLACK, WHITE);
|
||||
} else {
|
||||
display.setTextColor(WHITE, BLACK);
|
||||
}
|
||||
display.setCursor(0, drawing.row);
|
||||
display.println(value.title);
|
||||
}
|
||||
|
||||
static void drawAdjustValues(const AdjustValue &value, AdjustDrawing &drawing) {
|
||||
char buffer[13];
|
||||
snprintf(buffer, 13, "%d>%d<%d", value.thrVal, value.value, value.maxVal);
|
||||
display.setTextSize(1);
|
||||
display.setCursor(128 - 6 * strlen(buffer), drawing.row);
|
||||
display.println(buffer);
|
||||
|
||||
const int valX = mapConstrain(value.value, value.limitLow, value.limitHigh, 1, 127);
|
||||
if (drawing.valX != valX) {
|
||||
display.drawFastVLine(drawing.valX, drawing.row+4, 4, BLACK);
|
||||
display.drawFastVLine(valX, drawing.row+4, 4, WHITE);
|
||||
drawing.valX = valX;
|
||||
}
|
||||
}
|
||||
|
||||
static void drawAdjustFrame(int line) {
|
||||
display.drawLine(25,line,120,line,WHITE); // Top line
|
||||
display.drawLine(25,line+12,120,line+12,WHITE); // Bottom line
|
||||
|
||||
display.drawLine(25,line+1,25,line+2,WHITE);
|
||||
display.drawLine(120,line+1,120,line+2,WHITE);
|
||||
|
||||
display.drawLine(120,line+10,120,line+11,WHITE);
|
||||
display.drawLine(25,line+10,25,line+11,WHITE);
|
||||
}
|
||||
|
||||
static void drawAdjustRow(const AdjustValue &value, AdjustDrawing &drawing, bool highlight) {
|
||||
display.fillRect(0, drawing.row, 128, 21, BLACK);
|
||||
drawAdjustFrame(drawing.row);
|
||||
drawAdjustTitle(value, drawing, highlight);
|
||||
drawAdjustValues(value, drawing);
|
||||
drawAdjustIndicators(value, drawing);
|
||||
}
|
||||
57
NuEVI/src/config.h
Normal file
57
NuEVI/src/config.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
|
||||
#ifndef __CONFIG_H
|
||||
#define __CONFIG_H
|
||||
|
||||
|
||||
// Compile options, comment/uncomment to change
|
||||
|
||||
#define FIRMWARE_VERSION "0.0.1" // FIRMWARE VERSION NUMBER HERE <<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
#define ON_Delay 20 // Set Delay after ON threshold before velocity is checked (wait for tounging peak)
|
||||
#define CCN_Port 5 // Controller number for portamento level
|
||||
#define CCN_PortOnOff 65// Controller number for portamento on/off
|
||||
#define START_NOTE 24 // set startNote to C (change this value in steps of 12 to start in other octaves)
|
||||
#define FILTER_FREQ 30.0
|
||||
#define CAP_SENS_ABSOLUTE_MAX 1000 // For inverting capacitive sensors
|
||||
#define PRESSURE_SENS_MULTIPLIER 10 // Multiply pressure sens so it's not a float
|
||||
#define CALIBRATE_SAMPLE_COUNT 4
|
||||
|
||||
|
||||
// Statup buttons
|
||||
#define STARTUP_FACTORY_RESET 0x3
|
||||
#define STARTUP_CONFIG 0xC
|
||||
#define TEST_CONFIG 0xA
|
||||
#define DEBUG_CONFIG 0x1
|
||||
|
||||
// Buttons
|
||||
#define BTN_MENU 0x1
|
||||
#define BTN_VAL1 0x2
|
||||
#define BTN_VAL2 0x4
|
||||
#define BTN_PRESET 0x8
|
||||
|
||||
// Send breath CC data no more than every CC_BREATH_INTERVAL
|
||||
// milliseconds
|
||||
#define CC_BREATH_INTERVAL 5
|
||||
#define SLOW_MIDI_ADD 7
|
||||
#define CC_INTERVAL_PRIMARY 9
|
||||
#define CC_INTERVAL_PORT 13
|
||||
#define CC_INTERVAL_OTHER 37
|
||||
#define LVL_TIMER_INTERVAL 15
|
||||
#define CVPORTATUNE 2
|
||||
|
||||
#define maxSamplesNum 120
|
||||
|
||||
#define BREATH_LO_LIMIT 8000
|
||||
#define BREATH_HI_LIMIT 10000
|
||||
#define BITE_LO_LIMIT 0
|
||||
#define BITE_HI_LIMIT 1000
|
||||
#define PITCHB_LO_LIMIT 0
|
||||
#define PITCHB_HI_LIMIT 1000
|
||||
#define EXTRA_LO_LIMIT 0
|
||||
#define EXTRA_HI_LIMIT 1000
|
||||
#define CTOUCH_LO_LIMIT 0
|
||||
#define CTOUCH_HI_LIMIT 1000
|
||||
#define LEVER_LO_LIMIT 0
|
||||
#define LEVER_HI_LIMIT 1000
|
||||
|
||||
#endif
|
||||
139
NuEVI/src/globals.h
Normal file
139
NuEVI/src/globals.h
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
#ifndef __GLOBALS_H
|
||||
#define __GLOBALS_H
|
||||
|
||||
#include "wiring.h"
|
||||
#include <array>
|
||||
|
||||
|
||||
// The three states of our main state machine
|
||||
|
||||
// No note is sounding
|
||||
#define NOTE_OFF 1
|
||||
|
||||
// We've observed a transition from below to above the
|
||||
// threshold value. We wait a while to see how fast the
|
||||
// breath velocity is increasing
|
||||
#define RISE_WAIT 2
|
||||
|
||||
// A note is sounding
|
||||
#define NOTE_ON 3
|
||||
|
||||
enum PinkyMode : uint8_t {
|
||||
PBD = 12,
|
||||
GLD = 25,
|
||||
MOD = 26,
|
||||
QTN = 27,
|
||||
};
|
||||
|
||||
enum FingeringMode : uint8_t {
|
||||
EVI = 0,
|
||||
EVR = 1,
|
||||
TPT = 2,
|
||||
HRN = 3,
|
||||
};
|
||||
|
||||
enum RollerMode : uint8_t {
|
||||
HIGHEST = 1,
|
||||
HIGHEST_EXTEND = 2,
|
||||
HIGHEST_PAIR = 3,
|
||||
HIGHEST_PAIR_EXTEND = 4, // Releasing the roller from the highest/lowest moves
|
||||
PARTIAL = 5,
|
||||
PARTIAL_EXTEND = 6,
|
||||
};
|
||||
|
||||
enum VibratoMode : uint8_t {
|
||||
VSTART_DOWN = 0,
|
||||
VSTART_UP = 1,
|
||||
};
|
||||
|
||||
enum BreathMode : uint8_t {
|
||||
BREATH_STD = 0,
|
||||
BREATH_LSB = 1,
|
||||
BREATH_AT = 2,
|
||||
BREATH_LSB_AT = 3,
|
||||
};
|
||||
|
||||
enum ExtraControl : uint8_t {
|
||||
OFF = 0,
|
||||
VIBRATO = 1,
|
||||
GLIDE = 2,
|
||||
CC = 3,
|
||||
};
|
||||
|
||||
enum PolySelect : uint8_t {
|
||||
EHarmonizerOff = 0,
|
||||
EDuo = 1,
|
||||
EChord = 2,
|
||||
};
|
||||
|
||||
enum PortamentoMode : uint8_t {
|
||||
POFF = 0,
|
||||
PON = 1,
|
||||
PSWITCH_ONLY = 2,
|
||||
PGLIDE_ONLY = 3,
|
||||
};
|
||||
|
||||
struct instrument_state_t {
|
||||
int mainState; // The state of the main state machine
|
||||
uint8_t patch; // 1-128
|
||||
byte activeMIDIchannel = 1; // MIDI channel
|
||||
byte activeNote = 0; // note playing
|
||||
byte activePatch = 0;
|
||||
byte doPatchUpdate = 0;
|
||||
int8_t transpose = 0;
|
||||
uint8_t octave = 0;
|
||||
PolySelect polyMode = PolySelect::EHarmonizerOff;
|
||||
|
||||
// Raw sensor signals
|
||||
int16_t breathSignal = 0; // breath level (smoothed) not mapped to CC value
|
||||
int16_t breathAltSignal = 0;
|
||||
int16_t biteSignal = 0; // capacitance data from bite sensor, for midi cc and threshold checks
|
||||
int16_t leverSignal = 0;
|
||||
int16_t pbUpSignal = 0;
|
||||
int16_t pbDnSignal = 0;
|
||||
int16_t extraSignal = 0;
|
||||
int16_t vibSignal = 0;
|
||||
|
||||
// MIDI values
|
||||
int breathCCVal = 0;
|
||||
byte biteVal = 0; // keep track and make sure we send CC with 0 value when off threshold
|
||||
byte portamentoVal = 0; // keep track and make sure we send CC with 0 value when off threshold
|
||||
byte extraVal = 0; // keep track and make sure we send CC with 0 value when off threshold
|
||||
byte leverVal = 0; // keep track and make sure we send CC with 0 value when off threshold
|
||||
int pitchBend = 8192;
|
||||
int pbSend = 8192; // Pitch bend actually sent, modified by vibrato, etc
|
||||
|
||||
// Key states
|
||||
byte quarterToneTrigger;
|
||||
byte pinkyKey = 0;
|
||||
|
||||
// CV values
|
||||
int cvPitch;
|
||||
int targetPitch;
|
||||
|
||||
// Calibration
|
||||
int16_t breathZero; // this gets auto calibrated in setup
|
||||
int16_t breathThrVal; // this gets auto calibrated in setup
|
||||
int16_t breathMaxVal; // this gets auto calibrated in setup
|
||||
int16_t breathAltZero; // this gets auto calibrated in setup
|
||||
int16_t breathAltThrVal; // this gets auto calibrated in setup
|
||||
int16_t breathAltMaxVal; // this gets auto calibrated in setup
|
||||
|
||||
int16_t vibThr; // this gets auto calibrated in setup
|
||||
int16_t vibThrLo;
|
||||
int16_t vibZero;
|
||||
int16_t vibZeroBite;
|
||||
int16_t vibThrBite;
|
||||
int16_t vibThrBiteLo;
|
||||
};
|
||||
|
||||
extern instrument_state_t state;
|
||||
|
||||
extern const std::array<const unsigned short*, 13> curves;
|
||||
extern const unsigned short curveIn[];
|
||||
|
||||
extern unsigned int multiMap(unsigned short val, const unsigned short * _in, const unsigned short * _out, uint8_t size);
|
||||
|
||||
#define mapConstrain(val, in_lo, in_hi, out_lo, out_hi) map(constrain(val, in_lo, in_hi), in_lo, in_hi, out_lo, out_hi)
|
||||
|
||||
#endif
|
||||
131
NuEVI/src/hardware.cpp
Normal file
131
NuEVI/src/hardware.cpp
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
#include <Wire.h>
|
||||
#include "hardware.h"
|
||||
|
||||
#define ENCODER_OPTIMIZE_INTERRUPTS
|
||||
#include <Encoder.h>
|
||||
#include "menu.h"
|
||||
#include "config.h"
|
||||
#include "FilterOnePole.h" // for the breath signal low-pass filtering, from https://github.com/JonHub/Filters
|
||||
FilterOnePole breathFilter;
|
||||
FilterOnePole breathAltFilter;
|
||||
|
||||
Adafruit_MPR121 touchSensorKeys = Adafruit_MPR121();
|
||||
Adafruit_MPR121 touchSensorUtil = Adafruit_MPR121();
|
||||
Adafruit_MPRLS pressureSensorMain = Adafruit_MPRLS();
|
||||
Adafruit_MPRLS pressureSensorAlt = Adafruit_MPRLS();
|
||||
|
||||
byte drawingMemory[numLeds*3]; // 3 bytes per LED
|
||||
DMAMEM byte displayMemory[numLeds*12]; // 12 bytes per LED
|
||||
WS2812Serial ledStrip(numLeds, displayMemory, drawingMemory, ledStripPin, WS2812_GRB);
|
||||
Adafruit_ICM20948 icmSensor;
|
||||
Adafruit_Sensor *accelSensor;
|
||||
Encoder knobs[] = {
|
||||
Encoder(e1aPin, e1bPin),
|
||||
Encoder(e2aPin, e2bPin),
|
||||
Encoder(e3aPin, e3bPin),
|
||||
Encoder(e4aPin, e4bPin),
|
||||
};
|
||||
|
||||
void errorWait();
|
||||
|
||||
|
||||
void initHardware() {
|
||||
MainI2CBus.setClock(1000000);
|
||||
AuxI2CBus.setClock(1000000);
|
||||
pinMode(statusLedPin,OUTPUT); // Teensy onboard LED
|
||||
|
||||
// Buttons
|
||||
pinMode(b1Pin,INPUT_PULLUP);
|
||||
pinMode(b2Pin,INPUT_PULLUP);
|
||||
pinMode(b3Pin,INPUT_PULLUP);
|
||||
pinMode(b4Pin,INPUT_PULLUP);
|
||||
|
||||
breathFilter.setFilter(LOWPASS, FILTER_FREQ, 0.0); // create a one pole (RC) lowpass filter
|
||||
breathAltFilter.setFilter(LOWPASS, FILTER_FREQ, 0.0); // create a one pole (RC) lowpass filter
|
||||
|
||||
ledStrip.begin();
|
||||
|
||||
if (!touchSensorKeys.begin(KeysI2CAddr, &MainI2CBus)) {
|
||||
displayError("Keys touch error");
|
||||
errorWait();
|
||||
}
|
||||
|
||||
if (!touchSensorUtil.begin(UtilI2CAddr, &MainI2CBus)) {
|
||||
displayError("Roller/Util touch error");
|
||||
errorWait();
|
||||
}
|
||||
|
||||
if (!pressureSensorMain.begin(MPRLS_DEFAULT_ADDR, &MainI2CBus)) {
|
||||
displayError("Main pressure sensor error");
|
||||
errorWait();
|
||||
}
|
||||
|
||||
if (!pressureSensorAlt.begin(MPRLS_DEFAULT_ADDR, &AuxI2CBus)) {
|
||||
displayError("Alt pressure sensor error");
|
||||
errorWait();
|
||||
}
|
||||
|
||||
if (!icmSensor.begin_I2C(ICM20948_I2CADDR_DEFAULT, &MainI2CBus)) {
|
||||
displayError("ICM sensor error");
|
||||
errorWait();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Return true if the given button bitmask is pressed
|
||||
*/
|
||||
bool checkButtonState(uint8_t mask) {
|
||||
return buttonState() & mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the state of the switches (note that they are active low, so we invert the values)
|
||||
*/
|
||||
uint8_t buttonState() {
|
||||
return 0x0f ^(digitalRead(b1Pin)
|
||||
| (digitalRead(b2Pin) << 1)
|
||||
| (digitalRead(b3Pin) << 2)
|
||||
| (digitalRead(b4Pin) << 3));
|
||||
}
|
||||
|
||||
|
||||
void errorWait() {
|
||||
while (1) {
|
||||
if (!digitalRead(b1Pin)) {
|
||||
_reboot_Teensyduino_(); // reboot to program mode if b1 pressed
|
||||
}
|
||||
|
||||
if (!digitalRead(b4Pin)) {
|
||||
break; // Continue if b4 pressed
|
||||
}
|
||||
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
|
||||
int readKnob(uint8_t n) {
|
||||
return knobs[n].readAndReset();
|
||||
}
|
||||
|
||||
int readTouchKey(uint8_t n) {
|
||||
return CAP_SENS_ABSOLUTE_MAX - touchSensorKeys.filteredData(n);
|
||||
}
|
||||
int readTouchUtil(uint8_t n) {
|
||||
return CAP_SENS_ABSOLUTE_MAX - touchSensorUtil.filteredData(n);
|
||||
}
|
||||
|
||||
uint16_t keysTouched() {
|
||||
return touchSensorKeys.touched();
|
||||
}
|
||||
|
||||
uint16_t utilTouched() {
|
||||
return touchSensorKeys.touched();
|
||||
}
|
||||
|
||||
int readPressure() {
|
||||
return breathFilter.input(pressureSensorMain.readPressure()) * PRESSURE_SENS_MULTIPLIER;
|
||||
}
|
||||
|
||||
int readAltPressure() {
|
||||
return breathAltFilter.input(pressureSensorAlt.readPressure()) * PRESSURE_SENS_MULTIPLIER;
|
||||
}
|
||||
96
NuEVI/src/hardware.h
Normal file
96
NuEVI/src/hardware.h
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#ifndef __HARDWARE_H
|
||||
#define __HARDWARE_H
|
||||
|
||||
#include <Adafruit_MPR121.h>
|
||||
#include <Adafruit_MPRLS.h>
|
||||
#include <Adafruit_ICM20X.h>
|
||||
#include <WS2812Serial.h>
|
||||
#include <Adafruit_ICM20948.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Hardware sensor definitions
|
||||
// TODO: remove these
|
||||
|
||||
extern WS2812Serial ledStrip;
|
||||
extern Adafruit_Sensor *accelSensor;
|
||||
extern Adafruit_ICM20948 icmSensor;
|
||||
|
||||
void initHardware();
|
||||
bool checkButtonState(uint8_t mask); // return true if the given buttons are pressed
|
||||
uint8_t buttonState(); // return true if the given buttons are pressed
|
||||
int readKnob(uint8_t n);
|
||||
int readTouchKey(uint8_t n);
|
||||
int readTouchUtil(uint8_t n);
|
||||
uint16_t keysTouched();
|
||||
uint16_t utilTouched();
|
||||
int readPressure();
|
||||
int readAltPressure();
|
||||
|
||||
// xEVI hardware setup
|
||||
|
||||
// I2C
|
||||
#define MainI2CBus Wire1
|
||||
#define AuxI2CBus Wire
|
||||
#define KeysI2CAddr 0x5B
|
||||
#define UtilI2CAddr 0x5A
|
||||
|
||||
// Digital pins for encoder buttons
|
||||
#define b1Pin 0
|
||||
#define b2Pin 2
|
||||
#define b3Pin 3
|
||||
#define b4Pin 4
|
||||
|
||||
// Digital pins for encoder quadrature
|
||||
#define e1aPin 5
|
||||
#define e2aPin 6
|
||||
#define e3aPin 7
|
||||
#define e4aPin 8
|
||||
|
||||
#define e1bPin 20
|
||||
#define e2bPin 21
|
||||
#define e3bPin 22
|
||||
#define e4bPin 23
|
||||
|
||||
// CV pins
|
||||
#define cvGatePin 9
|
||||
#define cvPitchPin 10
|
||||
#define cvBreathPin 11
|
||||
#define cvBitePin 12
|
||||
|
||||
//Output pins for LEDs
|
||||
#define statusLedPin 13
|
||||
#define ledStripPin 1
|
||||
#define numLeds 8
|
||||
|
||||
// Key pins
|
||||
// RH keys
|
||||
#define K1Pin 0
|
||||
#define K2Pin 1
|
||||
#define K3Pin 2
|
||||
#define K4Pin 3
|
||||
#define K5Pin 4
|
||||
#define K6Pin 5
|
||||
#define K7Pin 6
|
||||
#define K8Pin 7
|
||||
|
||||
// LH keys
|
||||
#define K9Pin 8
|
||||
#define K10Pin 9
|
||||
#define K11Pin 10
|
||||
#define K12Pin 11
|
||||
|
||||
// Octave roller pins
|
||||
#define R1Pin 0
|
||||
#define R2Pin 1
|
||||
#define R3Pin 2
|
||||
#define R4Pin 3
|
||||
#define R5Pin 4
|
||||
#define R6Pin 5
|
||||
|
||||
// Additional pins
|
||||
#define bitePin 6
|
||||
#define pbUpPin 7
|
||||
#define pbDnPin 8
|
||||
#define vibratoPin 9
|
||||
|
||||
#endif
|
||||
49
NuEVI/src/led.cpp
Normal file
49
NuEVI/src/led.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#include <Arduino.h>
|
||||
#include "hardware.h"
|
||||
#include "globals.h"
|
||||
#include "config.h"
|
||||
|
||||
void singleLED(int n, int color) {
|
||||
}
|
||||
|
||||
void ledFullMeter(byte indicatedValue, int color){
|
||||
}
|
||||
|
||||
void ledHalfMeter(int n, byte indicatedValue, int color){
|
||||
}
|
||||
|
||||
void ledQuarterMeter(int n, byte indicatedValue, int color){
|
||||
}
|
||||
|
||||
void statusLedOn() {
|
||||
digitalWrite(statusLedPin, HIGH);
|
||||
}
|
||||
|
||||
void statusLedOff() {
|
||||
digitalWrite(statusLedPin, LOW);
|
||||
}
|
||||
|
||||
void statusLed(bool state) {
|
||||
digitalWrite(statusLedPin, state);
|
||||
}
|
||||
|
||||
void statusLedFlip() {
|
||||
digitalWrite(statusLedPin, !digitalRead(statusLedPin));
|
||||
}
|
||||
|
||||
void statusLedFlash(uint16_t delayTime) {
|
||||
statusLedOff();
|
||||
delay(delayTime/2);
|
||||
statusLedOn();
|
||||
delay(delayTime/2);
|
||||
}
|
||||
|
||||
void statusLedBlink() {
|
||||
statusLedFlash(300);
|
||||
statusLedFlash(300);
|
||||
}
|
||||
|
||||
void updateSensorLEDs() {
|
||||
ledHalfMeter(1, state.breathCCVal, 0x00FF00);
|
||||
ledQuarterMeter(3, state.biteVal, 0x0000FF);
|
||||
}
|
||||
26
NuEVI/led.h → NuEVI/src/led.h
Executable file → Normal file
26
NuEVI/led.h → NuEVI/src/led.h
Executable file → Normal file
|
|
@ -1,13 +1,13 @@
|
|||
#ifndef __LED_H
|
||||
#define __LED_H
|
||||
|
||||
void statusLedOn();
|
||||
void statusLedOff();
|
||||
void statusLedFlip();
|
||||
void statusLed(bool state);
|
||||
void statusLedFlash(uint16_t delayTime);
|
||||
void statusLedBlink();
|
||||
void updateSensorLEDs();
|
||||
void ledMeter(byte indicatedValue);
|
||||
|
||||
#endif
|
||||
#ifndef __LED_H
|
||||
#define __LED_H
|
||||
|
||||
void statusLedOn();
|
||||
void statusLedOff();
|
||||
void statusLedFlip();
|
||||
void statusLed(bool state);
|
||||
void statusLedFlash(uint16_t delayTime);
|
||||
void statusLedBlink();
|
||||
void updateSensorLEDs();
|
||||
void ledMeter(byte indicatedValue);
|
||||
|
||||
#endif
|
||||
755
NuEVI/src/menu.cpp
Normal file
755
NuEVI/src/menu.cpp
Normal file
|
|
@ -0,0 +1,755 @@
|
|||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include <Adafruit_MPR121.h>
|
||||
#include <Arduino.h>
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
|
||||
#include "menu.h"
|
||||
#include "hardware.h"
|
||||
#include "config.h"
|
||||
#include "settings.h"
|
||||
#include "globals.h"
|
||||
#include "midi.h"
|
||||
#include "led.h"
|
||||
|
||||
// constants
|
||||
const unsigned long debounceDelay = 30; // the debounce time; increase if the output flickers
|
||||
const unsigned long buttonRepeatInterval = 50;
|
||||
const unsigned long buttonRepeatDelay = 400;
|
||||
const unsigned long cursorBlinkInterval = 300; // the cursor blink toggle interval time
|
||||
const unsigned long patchViewTimeUp = 2000; // ms until patch view shuts off
|
||||
const unsigned long menuTimeUp = 60000; // menu shuts off after one minute of button inactivity
|
||||
|
||||
static unsigned long menuTime = 0;
|
||||
static unsigned long patchViewTime = 0;
|
||||
unsigned long cursorBlinkTime = 0; // the last time the cursor was toggled
|
||||
|
||||
std::array<const char *, 128> CC_NAMES = {
|
||||
"Bank Select", // 0
|
||||
"Mod Wheel", // 1
|
||||
"Breath", // 2
|
||||
"Undefined", // 3
|
||||
"Foot Pedal", // 4
|
||||
"Port. Time", // 5
|
||||
"Data Entry", // 6
|
||||
"Volume", // 7
|
||||
"Balance", // 8
|
||||
"Undefined", // 9
|
||||
"Pan", // 10
|
||||
"Expression", // 11
|
||||
"Effect 1", // 12
|
||||
"Effect 2", // 13
|
||||
"Undefined", // 14
|
||||
"Undefined", // 15
|
||||
"GP 1", // 16
|
||||
"GP 2", // 17
|
||||
"GP 3", // 18
|
||||
"GP 3", // 19
|
||||
"Undefined", // 20
|
||||
"Undefined", // 21
|
||||
"Undefined", // 22
|
||||
"Undefined", // 23
|
||||
"Undefined", // 24
|
||||
"Undefined", // 25
|
||||
"Undefined", // 26
|
||||
"Undefined", // 27
|
||||
"Undefined", // 28
|
||||
"Undefined", // 29
|
||||
"Undefined", // 30
|
||||
"Undefined", // 31
|
||||
"LSB 0", // 32
|
||||
"LSB 1", // 33
|
||||
"LSB 2", // 34
|
||||
"LSB 3", // 35
|
||||
"LSB 4", // 36
|
||||
"LSB 5", // 37
|
||||
"LSB 6", // 38
|
||||
"LSB 7", // 39
|
||||
"LSB 8", // 40
|
||||
"LSB 9", // 41
|
||||
"LSB 10", // 42
|
||||
"LSB 11", // 43
|
||||
"LSB 12", // 44
|
||||
"LSB 13", // 45
|
||||
"LSB 14", // 46
|
||||
"LSB 15", // 47
|
||||
"LSB 16", // 48
|
||||
"LSB 17", // 49
|
||||
"LSB 18", // 50
|
||||
"LSB 19", // 51
|
||||
"LSB 20", // 52
|
||||
"LSB 21", // 53
|
||||
"LSB 22", // 54
|
||||
"LSB 23", // 55
|
||||
"LSB 24", // 56
|
||||
"LSB 25", // 57
|
||||
"LSB 26", // 58
|
||||
"LSB 27", // 59
|
||||
"LSB 28", // 60
|
||||
"LSB 29", // 61
|
||||
"LSB 30", // 62
|
||||
"LSB 31", // 63
|
||||
"Sustain", // 64
|
||||
"Portamento", // 65
|
||||
"Sostenuto", // 66
|
||||
"Soft Pedal", // 67
|
||||
"Legato", // 68
|
||||
"Hold 2", // 69
|
||||
"Variation", // 70
|
||||
"Resonance", // 71
|
||||
"Release", // 72
|
||||
"Attack", // 73
|
||||
"Cutoff", // 74
|
||||
"Sound 6", // 75
|
||||
"Sound 7", // 76
|
||||
"Sound 8", // 77
|
||||
"Sound 9", // 78
|
||||
"Sound 10", // 79
|
||||
"Decay", // 80
|
||||
"Hi Pass", // 81
|
||||
"GP Button 3", // 82
|
||||
"GP Button 4", // 83
|
||||
"Port. Amount", // 84
|
||||
"Undefined", // 85
|
||||
"Undefined", // 86
|
||||
"Undefined", // 87
|
||||
"Undefined", // 88
|
||||
"Undefined", // 89
|
||||
"Undefined", // 90
|
||||
"Reverb", // 91
|
||||
"Tremolo", // 92
|
||||
"Chorus", // 93
|
||||
"Detune", // 94
|
||||
"Phaser", // 95
|
||||
"Data Inc", // 96
|
||||
"Data Dec", // 97
|
||||
"NRPN LSB", // 98
|
||||
"NRPN MSB", // 99
|
||||
"RP LSB", // 100
|
||||
"RP MSB", // 101
|
||||
"Undefined", // 102
|
||||
"Undefined", // 103
|
||||
"Undefined", // 104
|
||||
"Undefined", // 105
|
||||
"Undefined", // 106
|
||||
"Undefined", // 107
|
||||
"Undefined", // 108
|
||||
"Undefined", // 109
|
||||
"Undefined", // 110
|
||||
"Undefined", // 111
|
||||
"Undefined", // 112
|
||||
"Undefined", // 113
|
||||
"Undefined", // 114
|
||||
"Undefined", // 115
|
||||
"Undefined", // 116
|
||||
"Undefined", // 117
|
||||
"Undefined", // 118
|
||||
"Undefined", // 119
|
||||
"All Sound Off", // 120
|
||||
"All CCC Off", // 121
|
||||
"Keyboard On", // 122
|
||||
"All Notes Off", // 123
|
||||
"Omni Mode Off", // 124
|
||||
"Omni Mode On", // 125
|
||||
"Mono", // 126
|
||||
"Poly Mode", // 127
|
||||
};
|
||||
|
||||
// 'NuEVI' or 'NuRAD' logo
|
||||
#define LOGO16_GLCD_WIDTH 128
|
||||
#define LOGO16_GLCD_HEIGHT 64
|
||||
static const unsigned char PROGMEM nuevi_logo_bmp[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xe3, 0x60, 0x00, 0x07, 0x73, 0x60, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xe3, 0x60, 0x00, 0x0e, 0xe3, 0x60, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x03, 0x60, 0x00, 0x1d, 0xc3, 0x60, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xbf, 0xff, 0xff, 0xe3, 0x60, 0x00, 0x3b, 0x83, 0x60, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xbf, 0xff, 0xff, 0xe3, 0x60, 0x00, 0x77, 0x03, 0x60, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x03, 0x60, 0x00, 0xee, 0x03, 0x60, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x03, 0x60, 0x01, 0xdc, 0x03, 0x60, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x03, 0x60, 0x03, 0xb8, 0x03, 0x60, 0x00,
|
||||
0x00, 0x00, 0x00, 0x20, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x03, 0x60, 0x07, 0x70, 0x03, 0x60, 0x00,
|
||||
0x00, 0x00, 0x00, 0x60, 0x00, 0x01, 0xbf, 0xff, 0xff, 0xe3, 0x60, 0x0e, 0xe0, 0x03, 0x60, 0x00,
|
||||
0x00, 0x00, 0x00, 0x60, 0x00, 0x01, 0xbf, 0xff, 0xff, 0xe3, 0x60, 0x1d, 0xc0, 0x03, 0x60, 0x00,
|
||||
0x00, 0x03, 0x00, 0x60, 0x00, 0x01, 0x80, 0x00, 0x00, 0x03, 0x60, 0x3b, 0x80, 0x03, 0x60, 0x00,
|
||||
0x00, 0x03, 0x00, 0xe0, 0x00, 0x01, 0xbf, 0xff, 0xff, 0xe3, 0x60, 0x77, 0x00, 0x03, 0x60, 0x00,
|
||||
0x00, 0x03, 0x00, 0xc0, 0x00, 0x01, 0xbf, 0xff, 0xff, 0xe3, 0x60, 0xee, 0x00, 0x03, 0x60, 0x00,
|
||||
0x00, 0x03, 0x80, 0xc0, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x03, 0x61, 0xdc, 0x00, 0x03, 0x60, 0x00,
|
||||
0x00, 0x07, 0x80, 0xc0, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x03, 0x63, 0xb8, 0x00, 0x03, 0x60, 0x00,
|
||||
0x00, 0x07, 0xc0, 0xc0, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x03, 0x67, 0x70, 0x00, 0x03, 0x60, 0x00,
|
||||
0x00, 0x06, 0xc0, 0xc0, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x03, 0x6e, 0xe0, 0x00, 0x03, 0x60, 0x00,
|
||||
0x00, 0x06, 0x60, 0xc1, 0x01, 0x01, 0xb0, 0x00, 0x00, 0x03, 0x7d, 0xc0, 0x00, 0x03, 0x60, 0x00,
|
||||
0x00, 0x06, 0x30, 0xc3, 0x03, 0x01, 0xbf, 0xff, 0xff, 0xe3, 0x7b, 0x80, 0x00, 0x03, 0x60, 0x00,
|
||||
0x00, 0x0c, 0x30, 0xc3, 0x07, 0x01, 0xbf, 0xff, 0xff, 0xe3, 0x77, 0x00, 0x00, 0x03, 0x60, 0x00,
|
||||
0x00, 0x0c, 0x1c, 0xc3, 0x06, 0x01, 0x80, 0x00, 0x00, 0x03, 0x0e, 0x00, 0x00, 0x03, 0x60, 0x00,
|
||||
0x00, 0x0c, 0x0c, 0xc2, 0x0e, 0x01, 0xff, 0xff, 0xff, 0xe3, 0xfc, 0x00, 0x00, 0x03, 0x60, 0x00,
|
||||
0x00, 0x0c, 0x0e, 0xc6, 0x1e, 0x01, 0xff, 0xff, 0xff, 0xe3, 0xf8, 0x00, 0x00, 0x03, 0x60, 0x00,
|
||||
0x00, 0x0c, 0x07, 0xc6, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x0c, 0x03, 0xc6, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x0c, 0x01, 0xc7, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x0c, 0x00, 0xc7, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x0c, 0x00, 0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
|
||||
extern void readSwitches(void);
|
||||
#define OLED_RESET 4
|
||||
Adafruit_SSD1306 display(128, 64, &Wire1, OLED_RESET,1000000,1000000);
|
||||
|
||||
MenuScreen *currentMenu = NULL;
|
||||
|
||||
void plotSubOption(const char* label, const char* unit = nullptr) {
|
||||
int text_x, unit_x;
|
||||
int label_pixel_width = strlen(label)*12;
|
||||
|
||||
if(unit == nullptr) {
|
||||
text_x = 96 - (label_pixel_width/2);
|
||||
} else {
|
||||
int unit_pixel_width = strlen(unit)*6;
|
||||
int halfSum = (label_pixel_width + unit_pixel_width)/2;
|
||||
text_x = 96 - halfSum;
|
||||
unit_x = 96 + halfSum - unit_pixel_width;
|
||||
display.setCursor(unit_x,40);
|
||||
display.setTextSize(1);
|
||||
display.println(unit);
|
||||
}
|
||||
|
||||
display.setTextSize(2);
|
||||
display.setCursor(text_x,33);
|
||||
display.println(label);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
static void plotMenuEntries(std::array<MenuScreen, N> entries, size_t cursorPos) {
|
||||
display.fillRect(0, MENU_HEADER_OFFSET, 63, 64-MENU_HEADER_OFFSET, BLACK);
|
||||
display.setTextSize(1);
|
||||
|
||||
size_t scrollPos = 0;
|
||||
if (entries.size() >= MENU_NUM_ROWS) {
|
||||
if ((cursorPos - scrollPos) > (MENU_NUM_ROWS-2) ) {
|
||||
scrollPos = cursorPos - (MENU_NUM_ROWS-2);
|
||||
} else if( (cursorPos - scrollPos) < 1) {
|
||||
scrollPos = cursorPos - 1;
|
||||
}
|
||||
|
||||
scrollPos = constrain(scrollPos, 0, entries.size() - MENU_NUM_ROWS);
|
||||
}
|
||||
|
||||
int row = 0;
|
||||
int end = constrain(scrollPos + MENU_NUM_ROWS, 0, entries.size());
|
||||
for (size_t i = scrollPos; i < end; i++, row++) {
|
||||
int rowPixel = (row)*MENU_ROW_HEIGHT + MENU_HEADER_OFFSET;
|
||||
display.setCursor(0,rowPixel);
|
||||
if (cursorPos == i) {
|
||||
display.setTextColor(BLACK, WHITE);
|
||||
} else {
|
||||
display.setTextColor(WHITE);
|
||||
}
|
||||
|
||||
display.println(entries[i].title());
|
||||
}
|
||||
}
|
||||
|
||||
class AboutMenu : public MenuScreen {
|
||||
const char *title() {
|
||||
return "ABOUT";
|
||||
}
|
||||
|
||||
void update(InputState input, bool redraw) {
|
||||
if (redraw) {
|
||||
display.clearDisplay();
|
||||
display.setCursor(49,0);
|
||||
display.setTextColor(WHITE);
|
||||
display.setTextSize(0);
|
||||
display.println("xEVI");
|
||||
display.setCursor(16,12);
|
||||
display.print("firmware v.");
|
||||
display.println(FIRMWARE_VERSION);
|
||||
display.print("eeprom v.");
|
||||
display.println(EEPROM_VERSION);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
class MainMenu : public MenuScreen {
|
||||
public:
|
||||
MainMenu(std::array<MenuScreen, N> entries) : _entries(entries) { }
|
||||
void update(InputState input, bool redraw) {
|
||||
if (input.changed && input.btnMenu) {
|
||||
_inSubMenu = !_inSubMenu;
|
||||
input.changed = false;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if (_inSubMenu) {
|
||||
_entries[_cursorPos].update(input, redraw);
|
||||
return;
|
||||
}
|
||||
|
||||
if (input.changed) {
|
||||
_cursorPos = (_cursorPos + input.knobMenu) % _entries.size();
|
||||
}
|
||||
|
||||
draw(redraw);
|
||||
};
|
||||
|
||||
const char *title() {
|
||||
return "MENU";
|
||||
}
|
||||
|
||||
private:
|
||||
void draw(bool redraw) {
|
||||
if (redraw) {
|
||||
display.clearDisplay();
|
||||
display.setTextSize(1);
|
||||
display.setCursor(0,0);
|
||||
display.drawLine(0, MENU_ROW_HEIGHT, 127, MENU_ROW_HEIGHT, WHITE);
|
||||
display.println("MENU");
|
||||
}
|
||||
|
||||
plotMenuEntries(_entries, _cursorPos);
|
||||
|
||||
}
|
||||
|
||||
bool _inSubMenu = false;
|
||||
size_t _cursorPos;
|
||||
std::array<MenuScreen, N> _entries;
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
class SubMenu : public MenuScreen {
|
||||
public:
|
||||
SubMenu(const char *title, std::array<MenuScreen, N> entries) : _title(title), _entries(entries) {}
|
||||
void update(InputState input, bool redraw) {
|
||||
bool redrawValue = false;
|
||||
if (input.changed && input.knobMenu != 0) {
|
||||
_cursorPos = (_cursorPos + input.knobMenu) % _entries.size();
|
||||
draw(false);
|
||||
input.changed = false;
|
||||
redrawValue = true;
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
draw(redraw);
|
||||
}
|
||||
|
||||
_entries[_cursorPos].update(input, redrawValue);
|
||||
};
|
||||
|
||||
const char *title() {
|
||||
return _title;
|
||||
}
|
||||
|
||||
private:
|
||||
void draw(bool redraw) {
|
||||
if (redraw) {
|
||||
display.clearDisplay();
|
||||
display.setTextSize(1);
|
||||
display.setCursor(0,0);
|
||||
display.drawLine(0, MENU_ROW_HEIGHT, 127, MENU_ROW_HEIGHT, WHITE);
|
||||
display.println(_title);
|
||||
}
|
||||
|
||||
plotMenuEntries(_entries, _cursorPos);
|
||||
}
|
||||
const char *_title;
|
||||
size_t _cursorPos;
|
||||
std::array<MenuScreen, N> _entries;
|
||||
};
|
||||
|
||||
template<
|
||||
size_t L,
|
||||
typename T
|
||||
>
|
||||
class ValueMenu : public MenuScreen {
|
||||
public:
|
||||
ValueMenu(
|
||||
const char * title, T &value,
|
||||
const T min, const T max, const bool wrap = false,
|
||||
const std::array<const char *, L> labels = {}
|
||||
) : _title(title), _value(value), _min(min), _max(max), _wrap(wrap), _labels(labels) {}
|
||||
void update(InputState input, bool redraw) {
|
||||
if (input.knobMenu) {
|
||||
_value = (_value + input.knobMenu);
|
||||
if (_value > _max) {
|
||||
_value = _min;
|
||||
} else if (_value < _min) {
|
||||
_value = _max;
|
||||
}
|
||||
|
||||
draw(redraw);
|
||||
} else if (redraw) {
|
||||
draw(redraw);
|
||||
}
|
||||
}
|
||||
private:
|
||||
T &_value;
|
||||
const T _min;
|
||||
const T _max;
|
||||
const bool _wrap;
|
||||
const std::array<const char *, L> _labels;
|
||||
const char *_title;
|
||||
|
||||
void draw(bool redraw) {
|
||||
if (redraw) {
|
||||
display.fillRect(63,11,64,52,BLACK);
|
||||
display.drawRect(63,11,64,52,WHITE);
|
||||
display.setTextSize(1);
|
||||
int len = strlen(this->_title);
|
||||
|
||||
display.setCursor(95-len*3,15);
|
||||
display.println(this->_title);
|
||||
}
|
||||
|
||||
char buffer[12];
|
||||
snprintf(buffer, 12, "%+d", _value);
|
||||
size_t label_idx = _value - _min;
|
||||
if (_labels.size() > 0 && label_idx >= 0 && label_idx <= _labels.size()) {
|
||||
plotSubOption(_labels[label_idx], buffer);
|
||||
} else {
|
||||
plotSubOption(buffer);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void drawFlash(int x, int y){
|
||||
display.drawLine(x+5,y,x,y+6,WHITE);
|
||||
display.drawLine(x,y+6,x+5,y+6,WHITE);
|
||||
display.drawLine(x,y+12,x+5,y+6,WHITE);
|
||||
}
|
||||
|
||||
void initDisplay() {
|
||||
|
||||
// by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
|
||||
display.begin(SSD1306_SWITCHCAPVCC, 0x3D); // initialize with the I2C addr 0x3D (for the 128x64)
|
||||
|
||||
// Show image buffer on the display hardware.
|
||||
// Since the buffer is intialized with an Adafruit splashscreen
|
||||
// internally, this will display the splashscreen.
|
||||
|
||||
display.clearDisplay();
|
||||
#if defined(NURAD)
|
||||
display.drawBitmap(0,0,nurad_logo_bmp,LOGO16_GLCD_WIDTH,LOGO16_GLCD_HEIGHT,1);
|
||||
#else
|
||||
display.drawBitmap(0,0,nuevi_logo_bmp,LOGO16_GLCD_WIDTH,LOGO16_GLCD_HEIGHT,1);
|
||||
#endif
|
||||
display.display();
|
||||
}
|
||||
|
||||
void displayError(const char *error) {
|
||||
display.clearDisplay();
|
||||
display.setTextColor(WHITE);
|
||||
display.setTextSize(1);
|
||||
display.setCursor(0,0);
|
||||
display.println(error);
|
||||
display.display();
|
||||
Serial.print("ERROR: ");
|
||||
Serial.println(error);
|
||||
}
|
||||
|
||||
void showVersion() {
|
||||
display.setTextColor(WHITE);
|
||||
display.setTextSize(1);
|
||||
display.setCursor(85,52);
|
||||
display.print("v.");
|
||||
display.println(FIRMWARE_VERSION);
|
||||
display.display();
|
||||
}
|
||||
|
||||
static void clearSub(){
|
||||
display.fillRect(63,11,64,52,BLACK);
|
||||
}
|
||||
|
||||
static void clearSubValue() {
|
||||
display.fillRect(65, 24, 60, 37, BLACK);
|
||||
}
|
||||
|
||||
//***********************************************************
|
||||
const MenuScreen breathModeMenu = ValueMenu<4, BreathMode>("BREATH MODE", currentPreset->breathMode, 0, 1, true, {{ "STANDARD", "LSB", "AT", "LSB_AT" }});
|
||||
const MenuScreen breathCCMenu = ValueMenu<128, uint8_t>("BREATH CC", currentPreset->breathCC, 0, 127, true, CC_NAMES);
|
||||
const MenuScreen velocityMenu = ValueMenu<1, uint8_t>("VELOCITY", currentPreset->fixedVelocity, 0, 127, true, {{ "DYN" }});
|
||||
const MenuScreen curveMenu = ValueMenu<0, uint8_t>("CURVE", currentPreset->breathCurve, 0, 12); // TODO: curve display
|
||||
const MenuScreen velSmpDlMenu = ValueMenu<1, uint8_t>("VEL DELAY", currentPreset->velSmpDl, 0, 30, true, { "OFF" }); // TODO: unit ms
|
||||
const MenuScreen velBiasMenu = ValueMenu<1, uint8_t>("VEL BOOST", currentPreset->velBias, 0, 30, true, { "OFF" });
|
||||
const MenuScreen breathIntervalMenu = ValueMenu<0, uint8_t>("BR INTERV", currentPreset->breathInterval, 0, 30, true);
|
||||
const MenuScreen trill3Menu = ValueMenu<0, int8_t>("TRILL3", currentPreset->trill3_interval, 3, 4, true, {});
|
||||
const MenuScreen cvTuneMenu = ValueMenu<0, int8_t>("CV Tune", currentPreset->cvTune, -100, 100, false, {});
|
||||
const MenuScreen cvVibMenu = ValueMenu<0, uint8_t>("CV Vib LFO", currentPreset->cvVibRate, 0, 8, false, {});
|
||||
const MenuScreen cvScaleMenu = ValueMenu<0, int8_t>("CV SCALING", currentPreset->cvScale, -100, 100, false, {});
|
||||
const std::array<const char *, 25> transposeLabels = {
|
||||
"C>", "C#>", "D>", "D#>", "E>", "F>", "F#>", "G>", "G#>", "A>", "Bb>", "B>",
|
||||
">C<", "<C#", "<D", "<D#", "<E", "<F", "<F#", "<G", "<G#", "<A", "<Bb", "<B", "<C"
|
||||
};
|
||||
|
||||
const MenuScreen transposeMenu = ValueMenu<25, int8_t>("TRANSPOSE", state.transpose, -12, 12, true, transposeLabels);
|
||||
const MenuScreen octaveMenu = ValueMenu<0, uint8_t>("OCTAVE", state.octave, -3, 3, true, {});
|
||||
const MenuScreen midiMenu = ValueMenu<0, byte>("MIDI CH", currentPreset->MIDIchannel, 1, 16, false, {});
|
||||
const MenuScreen vibDepthMenu = ValueMenu<1, uint8_t>("DEPTH", currentPreset->vibratoDepth, 0, 9, true, {"OFF"});
|
||||
const MenuScreen vibRetnMenu = ValueMenu<1, uint8_t>("RETURN", currentPreset->vibRetn, 0, 4, true, {"OFF"});
|
||||
const MenuScreen vibSenseMenu = ValueMenu<0, uint8_t>("SENSE LVR", currentPreset->vibSens, 0, 12);
|
||||
const MenuScreen vibSquelchMenu = ValueMenu<0, uint8_t>("SQUELCH LVR", currentPreset->vibSquelch, 0, 12);
|
||||
const MenuScreen vibDirMenu = ValueMenu<2, VibratoMode>("DIRECTION", currentPreset->vibratoMode, VSTART_DOWN, VSTART_UP, true, { "START DOWN", "START UP"});
|
||||
const MenuScreen biteCtlMenu = ValueMenu<4, ExtraControl>("BITE CTL", currentPreset->biteControl, 0, 3, true, {{
|
||||
"OFF",
|
||||
"VIBRATO",
|
||||
"GLIDE",
|
||||
"CC"
|
||||
}});
|
||||
const MenuScreen biteCCMenu = ValueMenu<128, uint8_t>("BITE CC", currentPreset->biteCC, 0, 127, true, CC_NAMES);
|
||||
const MenuScreen leverCtlMenu = ValueMenu<4, ExtraControl>("LEVER CTL", currentPreset->leverControl, 0, 3, true, {
|
||||
"OFF",
|
||||
"VIBRATO",
|
||||
"GLIDE",
|
||||
"CC"
|
||||
});
|
||||
const MenuScreen leverCCMenu = ValueMenu<128, uint8_t>("LEVER CC", currentPreset->leverCC, 0, 127, true, CC_NAMES);
|
||||
const MenuScreen portMenu = ValueMenu<4, PortamentoMode>("GLIDE MOD", currentPreset->portamentoMode, 0, 3, true, {
|
||||
"OFF",
|
||||
"ON",
|
||||
"SWITCH_ONLY",
|
||||
"GLIDE_ONLY",
|
||||
});
|
||||
const MenuScreen portLimitMenu = ValueMenu<0, uint8_t>("GLIDE LMT", currentPreset->portamentoLimit, 1, 127, true);
|
||||
const MenuScreen pitchBendMenu = ValueMenu<0, uint8_t>("PITCHBEND", currentPreset->PBdepth, 0, 12, true);
|
||||
const MenuScreen extraCtlMenu = ValueMenu<4, ExtraControl>("EXCT CC A", currentPreset->extraControl, 0,4, true, {
|
||||
"OFF",
|
||||
"ON",
|
||||
"SWITCH_ONLY",
|
||||
"GLIDE_ONLY",
|
||||
});
|
||||
const MenuScreen extraCCMenu = ValueMenu<128, uint8_t>("EXCT CC", currentPreset->extraCC, 0,4, true, CC_NAMES);
|
||||
const MenuScreen deglitchMenu = ValueMenu<1, uint8_t>("DEGLITCH", currentPreset->deglitch, 0, 70, true, {"OFF"});
|
||||
const MenuScreen pinkyMenu = ValueMenu<29, uint8_t>("PINKY KEY", currentPreset->pinkySetting, 0, 29, true, {
|
||||
"-12", "-11", "-10", "-9", "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1",
|
||||
"PB/2",
|
||||
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
|
||||
"PBD", "GLD", "MOD", "QTN"
|
||||
});
|
||||
const MenuScreen fingeringMenu = ValueMenu<4, FingeringMode>("FINGERING", currentPreset->fingering, 0, 3, true, {
|
||||
"EVI",
|
||||
"EVR",
|
||||
"TPT",
|
||||
"HRN",
|
||||
});
|
||||
const MenuScreen rollerMenu = ValueMenu<6, RollerMode>("ROLLRMODE", currentPreset->rollerMode, 1, 6, true, {
|
||||
"HIGHEST",
|
||||
"HIGHEST_EXTEND",
|
||||
"HIGHEST_PAIR",
|
||||
"HIGHEST_PAIR_EXTEND",
|
||||
"PARTIAL",
|
||||
"PARTIAL_EXTEND",
|
||||
});
|
||||
|
||||
std::array<MenuScreen, 7> breathMenuEntries = {
|
||||
breathModeMenu,
|
||||
breathCCMenu,
|
||||
velocityMenu,
|
||||
curveMenu,
|
||||
velSmpDlMenu,
|
||||
velBiasMenu,
|
||||
breathIntervalMenu,
|
||||
};
|
||||
const MenuScreen breathMenu = SubMenu<7>("BREATH SETUP", breathMenuEntries);
|
||||
|
||||
const std::array<MenuScreen, 13> controlMenuEntries = {
|
||||
fingeringMenu,
|
||||
rollerMenu,
|
||||
biteCtlMenu,
|
||||
biteCCMenu,
|
||||
leverCtlMenu,
|
||||
leverCCMenu,
|
||||
extraCtlMenu,
|
||||
extraCCMenu,
|
||||
portMenu,
|
||||
portLimitMenu,
|
||||
deglitchMenu,
|
||||
pinkyMenu,
|
||||
pitchBendMenu
|
||||
};
|
||||
const MenuScreen controlMenu = SubMenu<13>("CONTROL SETUP", controlMenuEntries);
|
||||
|
||||
const std::array<MenuScreen, 5> vibratoMenuEntries = {
|
||||
vibDepthMenu,
|
||||
vibRetnMenu,
|
||||
vibDirMenu,
|
||||
vibSenseMenu,
|
||||
vibSquelchMenu,
|
||||
};
|
||||
const MenuScreen vibratoMenu = SubMenu<5>("VIBRATO", vibratoMenuEntries);
|
||||
|
||||
|
||||
const MenuScreen aboutMenu = AboutMenu();
|
||||
|
||||
std::array <MenuScreen, 4> extrasMenuEntries = {
|
||||
trill3Menu,
|
||||
cvTuneMenu,
|
||||
cvScaleMenu,
|
||||
cvVibMenu,
|
||||
};
|
||||
const MenuScreen extrasMenu = SubMenu<4>("EXTRAS", extrasMenuEntries);
|
||||
|
||||
|
||||
// Top-level screens
|
||||
const std::array<MenuScreen, 9> mainMenuEntries = {
|
||||
transposeMenu,
|
||||
octaveMenu,
|
||||
midiMenu,
|
||||
breathMenu,
|
||||
controlMenu,
|
||||
vibratoMenu,
|
||||
adjustMenu,
|
||||
extrasMenu,
|
||||
aboutMenu,
|
||||
};
|
||||
const MenuScreen mainMenuPage = MainMenu<9>(mainMenuEntries);
|
||||
// const MenuScreen patchPage
|
||||
// const MenuScreen presetPage
|
||||
// const MenuScreen ccPage
|
||||
|
||||
static void curveCustomDraw() {
|
||||
const char* curveMenuLabels[] = {"-4", "-3", "-2", "-1", "LIN", "+1", "+2",
|
||||
"+3", "+4", "S1", "S2", "Z1", "Z2" };
|
||||
int y0 = 0, x0 = 0;
|
||||
int scale = ((1<<14)-1)/60;
|
||||
for(int x = x0; x < 60; x+=1) {
|
||||
int y = multiMap(x*scale, curveIn, curves[currentPreset->breathCurve], 17);
|
||||
y = (y*37) / ((1<<14)-1);
|
||||
display.drawLine(x0 + 65, 60 - y0, x + 65, 60 - y, WHITE);
|
||||
x0 = x; y0 = y;
|
||||
}
|
||||
display.setCursor(125 - 3*6, 60-8 );
|
||||
display.setTextSize(0);
|
||||
display.print(curveMenuLabels[currentPreset->breathCurve]);
|
||||
}
|
||||
|
||||
|
||||
static bool updateSensorPixelsFlag = false;
|
||||
void drawSensorPixels() {
|
||||
updateSensorPixelsFlag = true;
|
||||
}
|
||||
|
||||
//***********************************************************
|
||||
|
||||
static InputState readInput(uint32_t timeNow) {
|
||||
|
||||
static uint32_t lastDebounceTime = 0; // the last time the output pin was toggled
|
||||
static uint32_t buttonRepeatTime = 0;
|
||||
static uint32_t buttonPressedTime = 0;
|
||||
static uint8_t lastDeumButtons = 0;
|
||||
static uint8_t deumButtonState = 0;
|
||||
static int lastKnobs[] = {0, 0, 0, 0};
|
||||
|
||||
InputState input;
|
||||
|
||||
uint8_t deumButtons = buttonState();
|
||||
// check to see if you just pressed the button
|
||||
// (i.e. the input went from LOW to HIGH), and you've waited long enough
|
||||
// since the last press to ignore any noise:
|
||||
|
||||
// If the switch changed, due to noise or pressing:
|
||||
if (deumButtons != lastDeumButtons) {
|
||||
// reset the debouncing timer
|
||||
lastDebounceTime = timeNow;
|
||||
}
|
||||
|
||||
if ((timeNow - lastDebounceTime) > debounceDelay) {
|
||||
// whatever the reading is at, it's been there for longer than the debounce
|
||||
// delay, so take it as the actual current state:
|
||||
|
||||
// if the button state has changed:
|
||||
if (deumButtons != deumButtonState) {
|
||||
// keys.current = deumButtons;
|
||||
input.btnMenu = deumButtons & BTN_MENU;
|
||||
input.btnVal1 = deumButtons & BTN_VAL1;
|
||||
input.btnVal2 = deumButtons & BTN_VAL2;
|
||||
input.btnPreset = deumButtons & BTN_PRESET;
|
||||
input.changed = true;
|
||||
|
||||
deumButtonState = deumButtons;
|
||||
menuTime = timeNow;
|
||||
buttonPressedTime = timeNow;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int val = readKnob(i);
|
||||
if (val != lastKnobs[i]) {
|
||||
input.changed = 1;
|
||||
switch (i) {
|
||||
case 0:
|
||||
input.knobMenu = val;
|
||||
break;
|
||||
case 1:
|
||||
input.knobVal1 = val;
|
||||
break;
|
||||
case 2:
|
||||
input.knobVal2 = val;
|
||||
break;
|
||||
case 3:
|
||||
input.knobPreset = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save the reading. Next time through the loop, it'll be the lastButtonState:
|
||||
lastDeumButtons = deumButtons;
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void handleMenu(bool draw) {
|
||||
unsigned long timeNow = millis();
|
||||
|
||||
InputState input = readInput(timeNow);
|
||||
|
||||
// shut off menu system if not used for a while (changes not stored by exiting a setting manually will not be stored in EEPROM)
|
||||
if (currentMenu && ((timeNow - menuTime) > menuTimeUp)) {
|
||||
display.ssd1306_command(SSD1306_DISPLAYOFF);
|
||||
display.clearDisplay();
|
||||
currentMenu = NULL;
|
||||
}
|
||||
|
||||
if (currentMenu && (draw || input.changed)) {
|
||||
currentMenu->update(input, false);
|
||||
}
|
||||
}
|
||||
44
NuEVI/src/menu.h
Normal file
44
NuEVI/src/menu.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef __MENU_H
|
||||
#define __MENU_H
|
||||
|
||||
#include "wiring.h"
|
||||
|
||||
#define MENU_ROW_HEIGHT 9
|
||||
#define MENU_HEADER_OFFSET 12
|
||||
#define MENU_NUM_ROWS 6
|
||||
#define ADJUST_NUM_ROWS 3
|
||||
#define ADJUST_ROW_HEIGHT 21
|
||||
|
||||
extern const unsigned long debounceDelay; // the debounce time; increase if the output flickers
|
||||
extern const unsigned long buttonRepeatInterval;
|
||||
extern const unsigned long buttonRepeatDelay;
|
||||
extern const unsigned long cursorBlinkInterval; // the cursor blink toggle interval time
|
||||
extern const unsigned long patchViewTimeUp; // ms until patch view shuts off
|
||||
extern const unsigned long menuTimeUp; // menu shuts off after one minute of button inactivity
|
||||
|
||||
struct InputState {
|
||||
bool changed = false;
|
||||
bool btnMenu = false;
|
||||
bool btnVal1 = false;
|
||||
bool btnVal2 = false;
|
||||
bool btnPreset = false;
|
||||
int knobMenu = 0;
|
||||
int knobVal1 = 0;
|
||||
int knobVal2 = 0;
|
||||
int knobPreset = 0;
|
||||
};
|
||||
|
||||
struct MenuScreen {
|
||||
MenuScreen() {};
|
||||
virtual const char *title() { return ""; };
|
||||
virtual void update(InputState input, bool redraw) {};
|
||||
virtual ~MenuScreen() {};
|
||||
};
|
||||
extern const MenuScreen adjustMenu;
|
||||
|
||||
void initDisplay();
|
||||
void showVersion();
|
||||
void displayError(const char *error);
|
||||
void handleMenu(bool draw);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,226 +1,232 @@
|
|||
#include <Arduino.h>
|
||||
|
||||
#include "midi.h"
|
||||
#include "hardware.h"
|
||||
#include "globals.h"
|
||||
|
||||
int midiChannel;
|
||||
|
||||
|
||||
void midiSetChannel(uint8_t channel) {
|
||||
midiChannel = constrain(channel, 1, 16);
|
||||
}
|
||||
|
||||
byte midiGetChannel() {
|
||||
return midiChannel;
|
||||
}
|
||||
|
||||
|
||||
void midiSendProgramChange(uint8_t patch) {
|
||||
usbMIDI.sendProgramChange(patch-1, midiChannel);
|
||||
dinMIDIsendProgramChange(patch-1, midiChannel-1);
|
||||
}
|
||||
|
||||
void midiSendControlChange(uint8_t ccParam, uint8_t ccValue) {
|
||||
usbMIDI.sendControlChange(ccParam, ccValue, midiChannel);
|
||||
dinMIDIsendControlChange(ccParam, ccValue, midiChannel - 1);
|
||||
}
|
||||
|
||||
void midiSendNoteOn(uint8_t note, uint8_t velocity) {
|
||||
usbMIDI.sendNoteOn(note, velocity, midiChannel);
|
||||
dinMIDIsendNoteOn(note, velocity, midiChannel - 1);
|
||||
}
|
||||
|
||||
void midiSendNoteOff(uint8_t note) {
|
||||
//Always send velocity 0 on note off to avoid confusing some synthesizers
|
||||
usbMIDI.sendNoteOn(note, 0, midiChannel);
|
||||
dinMIDIsendNoteOn(note, 0, midiChannel - 1);
|
||||
}
|
||||
|
||||
|
||||
void midiSendAfterTouch(uint8_t value) {
|
||||
usbMIDI.sendAfterTouch(value, midiChannel);
|
||||
dinMIDIsendAfterTouch(value, midiChannel - 1);
|
||||
}
|
||||
|
||||
|
||||
void midiSendPitchBend(uint16_t value) {
|
||||
#if (TEENSYDUINO >= 141)
|
||||
usbMIDI.sendPitchBend(value-8192, midiChannel); // newer teensyduino "pitchBend-8192" older just "pitchBend"... strange thing to change
|
||||
#else
|
||||
usbMIDI.sendPitchBend(value, midiChannel);
|
||||
#endif
|
||||
dinMIDIsendPitchBend(value, midiChannel - 1);
|
||||
}
|
||||
|
||||
void midiDiscardInput()
|
||||
{
|
||||
while (usbMIDI.read()) {
|
||||
// read & ignore incoming messages
|
||||
}
|
||||
}
|
||||
|
||||
void midiReset() { // reset controllers
|
||||
midiSendControlChange(7, 100);
|
||||
midiSendControlChange(11, 127);
|
||||
}
|
||||
|
||||
void midiPanic() { // all notes off
|
||||
midiSendControlChange(123, 0);
|
||||
for (int i = 0; i < 128; i++){
|
||||
midiSendNoteOff(i);
|
||||
delay(2);
|
||||
}
|
||||
}
|
||||
|
||||
void midiInitialize(uint8_t channel) {
|
||||
MIDI_SERIAL.begin(31250); // start serial with midi baudrate 31250
|
||||
MIDI_SERIAL.flush();
|
||||
if(widiJumper){
|
||||
WIDI_SERIAL.begin(31250); // start serial with midi baudrate 31250
|
||||
WIDI_SERIAL.flush();
|
||||
}
|
||||
midiSetChannel(channel);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Serial midi functions
|
||||
|
||||
// Send a three byte din midi message
|
||||
void midiSend3B(uint8_t midistatus, uint8_t data1, uint8_t data2) {
|
||||
MIDI_SERIAL.write(midistatus);
|
||||
MIDI_SERIAL.write(data1);
|
||||
MIDI_SERIAL.write(data2);
|
||||
if (widiJumper && widiOn){
|
||||
WIDI_SERIAL.write(midistatus);
|
||||
WIDI_SERIAL.write(data1);
|
||||
WIDI_SERIAL.write(data2);
|
||||
}
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
// Send a two byte din midi message
|
||||
void midiSend2B(uint8_t midistatus, uint8_t data) {
|
||||
MIDI_SERIAL.write(midistatus);
|
||||
MIDI_SERIAL.write(data);
|
||||
if (widiJumper && widiOn){
|
||||
WIDI_SERIAL.write(midistatus);
|
||||
WIDI_SERIAL.write(data);
|
||||
}
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
// Send din pitchbend
|
||||
void dinMIDIsendPitchBend(uint16_t pb, uint8_t ch) {
|
||||
int pitchLSB = pb & 0x007F;
|
||||
int pitchMSB = (pb >>7) & 0x007F;
|
||||
midiSend3B((0xE0 | ch), pitchLSB, pitchMSB);
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
// Send din control change
|
||||
void dinMIDIsendControlChange(uint8_t ccNumber, uint8_t cc, uint8_t ch) {
|
||||
midiSend3B((0xB0 | ch), ccNumber, cc);
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
// Send din note on
|
||||
void dinMIDIsendNoteOn(uint8_t note, uint8_t vel, uint8_t ch) {
|
||||
midiSend3B((0x90 | ch), note, vel);
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
// Send din note off
|
||||
void dinMIDIsendNoteOff(uint8_t note, uint8_t vel, uint8_t ch) {
|
||||
midiSend3B((0x80 | ch), note, vel);
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
// Send din aftertouch
|
||||
void dinMIDIsendAfterTouch(uint8_t value, uint8_t ch) {
|
||||
midiSend2B((0xD0 | ch), value);
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
// Send din program change
|
||||
void dinMIDIsendProgramChange(uint8_t value, uint8_t ch) {
|
||||
midiSend2B((0xC0 | ch), value);
|
||||
}
|
||||
|
||||
// Send sysex commands to wireless module
|
||||
void dinMIDIsendSysex(const uint8_t data[], const uint8_t length) {
|
||||
MIDI_SERIAL.write(0xF0); //Sysex command
|
||||
for(int i=0; i<length; ++i) {
|
||||
MIDI_SERIAL.write(data[i]);
|
||||
}
|
||||
MIDI_SERIAL.write(0xF7); //Sysex end
|
||||
}
|
||||
|
||||
void sendWLPower(const uint8_t level) {
|
||||
uint8_t buf[6] = {
|
||||
0x00, 0x21, 0x11, //Manufacturer id
|
||||
0x02, //TX02
|
||||
0x02, //Set power level
|
||||
0x00 //Power level value (0-3)
|
||||
};
|
||||
|
||||
if(level>3) return; //Don't send invalid values
|
||||
|
||||
buf[5] = level;
|
||||
dinMIDIsendSysex(buf, 6);
|
||||
|
||||
}
|
||||
|
||||
void sendWLChannel(const uint8_t channel) {
|
||||
uint8_t buf[6] = {
|
||||
0x00, 0x21, 0x11, //Manufacturer id
|
||||
0x02, //TX02
|
||||
0x05, //Set channel
|
||||
0x04 //Channel value (4-80)
|
||||
};
|
||||
|
||||
if(channel<4 || channel>80) return; //Don't send invalid values
|
||||
|
||||
buf[5] = channel;
|
||||
dinMIDIsendSysex(buf, 6);
|
||||
|
||||
}
|
||||
|
||||
//Translate between "midi data" (only use 7 LSB per byte, big endian) and "teensy data" (little endian)
|
||||
//Only 14 LSB of int value are used (2MSB are discarded), so only works for unsigned data 0-16383
|
||||
|
||||
//NOTE: This assumes code is running on a little-endian CPU, both for real device (Teensy) and simulator.
|
||||
uint16_t convertToMidiValue(const uint16_t realdata) {
|
||||
return (realdata & 0x3F80) >>7 | (realdata & 0x007F) <<8;
|
||||
}
|
||||
|
||||
uint16_t convertFromMidiValue(const uint16_t mididata) {
|
||||
return (mididata & 0x7F00) >> 8 | (mididata & 0x007F) <<7 ;
|
||||
}
|
||||
|
||||
//Read from a memory location, such as MIDI receive buffer
|
||||
uint16_t convertFromMidiValue(const uint8_t* mididata) {
|
||||
uint8_t msb = *mididata;
|
||||
uint8_t lsb = *(mididata+1);
|
||||
|
||||
return (msb & 0x007F) <<7 | (lsb & 0x007F);
|
||||
}
|
||||
|
||||
//This is a bit different. MSB of each byte is just discarded (instead of discarding MSB for whole value). Just used for CRC (easier to compare)
|
||||
uint32_t convertToMidiCRC(const uint32_t realdata) {
|
||||
uint8_t* p = (uint8_t*)&realdata;
|
||||
|
||||
uint32_t r=0;
|
||||
for(int i=0; i<4; ++i) {
|
||||
r = r<<8 | (p[i] & 0x7F);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "midi.h"
|
||||
#include "hardware.h"
|
||||
#include "globals.h"
|
||||
|
||||
int midiChannel;
|
||||
|
||||
|
||||
void midiSetChannel(uint8_t channel) {
|
||||
midiChannel = constrain(channel, 1, 16);
|
||||
}
|
||||
|
||||
byte midiGetChannel() {
|
||||
return midiChannel;
|
||||
}
|
||||
|
||||
|
||||
void midiSendProgramChange(uint8_t patch) {
|
||||
usbMIDI.sendProgramChange(patch-1, midiChannel);
|
||||
dinMIDIsendProgramChange(patch-1, midiChannel-1);
|
||||
}
|
||||
|
||||
void midiSendControlChange(uint8_t ccParam, uint8_t ccValue) {
|
||||
usbMIDI.sendControlChange(ccParam, ccValue, midiChannel);
|
||||
dinMIDIsendControlChange(ccParam, ccValue, midiChannel - 1);
|
||||
}
|
||||
|
||||
void midiSendNoteOn(uint8_t note, uint8_t velocity) {
|
||||
usbMIDI.sendNoteOn(note, velocity, midiChannel);
|
||||
dinMIDIsendNoteOn(note, velocity, midiChannel - 1);
|
||||
}
|
||||
|
||||
void midiSendNoteOff(uint8_t note) {
|
||||
//Always send velocity 0 on note off to avoid confusing some synthesizers
|
||||
usbMIDI.sendNoteOn(note, 0, midiChannel);
|
||||
dinMIDIsendNoteOn(note, 0, midiChannel - 1);
|
||||
}
|
||||
|
||||
|
||||
void midiSendAfterTouch(uint8_t value) {
|
||||
usbMIDI.sendAfterTouch(value, midiChannel);
|
||||
dinMIDIsendAfterTouch(value, midiChannel - 1);
|
||||
}
|
||||
|
||||
|
||||
void midiSendPitchBend(uint16_t value) {
|
||||
#if (TEENSYDUINO >= 141)
|
||||
usbMIDI.sendPitchBend(value-8192, midiChannel); // newer teensyduino "pitchBend-8192" older just "pitchBend"... strange thing to change
|
||||
#else
|
||||
usbMIDI.sendPitchBend(value, midiChannel);
|
||||
#endif
|
||||
dinMIDIsendPitchBend(value, midiChannel - 1);
|
||||
}
|
||||
|
||||
void midiDiscardInput()
|
||||
{
|
||||
while (usbMIDI.read()) {
|
||||
// read & ignore incoming messages
|
||||
}
|
||||
}
|
||||
|
||||
void midiReset() { // reset controllers
|
||||
midiSendControlChange(7, 100);
|
||||
midiSendControlChange(11, 127);
|
||||
}
|
||||
|
||||
void midiPanic() { // all notes off
|
||||
midiSendControlChange(123, 0);
|
||||
for (int i = 0; i < 128; i++){
|
||||
midiSendNoteOff(i);
|
||||
delay(2);
|
||||
}
|
||||
}
|
||||
|
||||
void midiInitialize(uint8_t channel) {
|
||||
/*
|
||||
MIDI_SERIAL.begin(31250); // start serial with midi baudrate 31250
|
||||
MIDI_SERIAL.flush();
|
||||
if(widiJumper){
|
||||
WIDI_SERIAL.begin(31250); // start serial with midi baudrate 31250
|
||||
WIDI_SERIAL.flush();
|
||||
}
|
||||
*/
|
||||
midiSetChannel(channel);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Serial midi functions
|
||||
|
||||
// Send a three byte din midi message
|
||||
void midiSend3B(uint8_t midistatus, uint8_t data1, uint8_t data2) {
|
||||
/*
|
||||
MIDI_SERIAL.write(midistatus);
|
||||
MIDI_SERIAL.write(data1);
|
||||
MIDI_SERIAL.write(data2);
|
||||
if (widiJumper && widiOn){
|
||||
WIDI_SERIAL.write(midistatus);
|
||||
WIDI_SERIAL.write(data1);
|
||||
WIDI_SERIAL.write(data2);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
// Send a two byte din midi message
|
||||
void midiSend2B(uint8_t midistatus, uint8_t data) {
|
||||
/*
|
||||
MIDI_SERIAL.write(midistatus);
|
||||
MIDI_SERIAL.write(data);
|
||||
if (widiJumper && widiOn){
|
||||
WIDI_SERIAL.write(midistatus);
|
||||
WIDI_SERIAL.write(data);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
// Send din pitchbend
|
||||
void dinMIDIsendPitchBend(uint16_t pb, uint8_t ch) {
|
||||
int pitchLSB = pb & 0x007F;
|
||||
int pitchMSB = (pb >>7) & 0x007F;
|
||||
midiSend3B((0xE0 | ch), pitchLSB, pitchMSB);
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
// Send din control change
|
||||
void dinMIDIsendControlChange(uint8_t ccNumber, uint8_t cc, uint8_t ch) {
|
||||
midiSend3B((0xB0 | ch), ccNumber, cc);
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
// Send din note on
|
||||
void dinMIDIsendNoteOn(uint8_t note, uint8_t vel, uint8_t ch) {
|
||||
midiSend3B((0x90 | ch), note, vel);
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
// Send din note off
|
||||
void dinMIDIsendNoteOff(uint8_t note, uint8_t vel, uint8_t ch) {
|
||||
midiSend3B((0x80 | ch), note, vel);
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
// Send din aftertouch
|
||||
void dinMIDIsendAfterTouch(uint8_t value, uint8_t ch) {
|
||||
midiSend2B((0xD0 | ch), value);
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
// Send din program change
|
||||
void dinMIDIsendProgramChange(uint8_t value, uint8_t ch) {
|
||||
midiSend2B((0xC0 | ch), value);
|
||||
}
|
||||
|
||||
// Send sysex commands to wireless module
|
||||
void dinMIDIsendSysex(const uint8_t data[], const uint8_t length) {
|
||||
//MIDI_SERIAL.write(0xF0); //Sysex command
|
||||
for(int i=0; i<length; ++i) {
|
||||
//MIDI_SERIAL.write(data[i]);
|
||||
}
|
||||
//MIDI_SERIAL.write(0xF7); //Sysex end
|
||||
}
|
||||
|
||||
void sendWLPower(const uint8_t level) {
|
||||
uint8_t buf[6] = {
|
||||
0x00, 0x21, 0x11, //Manufacturer id
|
||||
0x02, //TX02
|
||||
0x02, //Set power level
|
||||
0x00 //Power level value (0-3)
|
||||
};
|
||||
|
||||
if(level>3) return; //Don't send invalid values
|
||||
|
||||
buf[5] = level;
|
||||
dinMIDIsendSysex(buf, 6);
|
||||
|
||||
}
|
||||
|
||||
void sendWLChannel(const uint8_t channel) {
|
||||
uint8_t buf[6] = {
|
||||
0x00, 0x21, 0x11, //Manufacturer id
|
||||
0x02, //TX02
|
||||
0x05, //Set channel
|
||||
0x04 //Channel value (4-80)
|
||||
};
|
||||
|
||||
if(channel<4 || channel>80) return; //Don't send invalid values
|
||||
|
||||
buf[5] = channel;
|
||||
dinMIDIsendSysex(buf, 6);
|
||||
|
||||
}
|
||||
|
||||
//Translate between "midi data" (only use 7 LSB per byte, big endian) and "teensy data" (little endian)
|
||||
//Only 14 LSB of int value are used (2MSB are discarded), so only works for unsigned data 0-16383
|
||||
|
||||
//NOTE: This assumes code is running on a little-endian CPU, both for real device (Teensy) and simulator.
|
||||
uint16_t convertToMidiValue(const uint16_t realdata) {
|
||||
return (realdata & 0x3F80) >>7 | (realdata & 0x007F) <<8;
|
||||
}
|
||||
|
||||
uint16_t convertFromMidiValue(const uint16_t mididata) {
|
||||
return (mididata & 0x7F00) >> 8 | (mididata & 0x007F) <<7 ;
|
||||
}
|
||||
|
||||
//Read from a memory location, such as MIDI receive buffer
|
||||
uint16_t convertFromMidiValue(const uint8_t* mididata) {
|
||||
uint8_t msb = *mididata;
|
||||
uint8_t lsb = *(mididata+1);
|
||||
|
||||
return (msb & 0x007F) <<7 | (lsb & 0x007F);
|
||||
}
|
||||
|
||||
//This is a bit different. MSB of each byte is just discarded (instead of discarding MSB for whole value). Just used for CRC (easier to compare)
|
||||
uint32_t convertToMidiCRC(const uint32_t realdata) {
|
||||
uint8_t* p = (uint8_t*)&realdata;
|
||||
|
||||
uint32_t r=0;
|
||||
for(int i=0; i<4; ++i) {
|
||||
r = r<<8 | (p[i] & 0x7F);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
92
NuEVI/midi.h → NuEVI/src/midi.h
Executable file → Normal file
92
NuEVI/midi.h → NuEVI/src/midi.h
Executable file → Normal file
|
|
@ -1,46 +1,46 @@
|
|||
#ifndef __MIDI_H
|
||||
#define __MIDI_H
|
||||
|
||||
//This is a completely made up "European" SysEx manufacturer ID.
|
||||
static const char sysex_id[] = { 0x00, 0x3e, 0x7f };
|
||||
|
||||
//Enable use of USB and serial MIDI
|
||||
#define USE_MIDI_USB
|
||||
#define USE_MIDI_SERIAL
|
||||
|
||||
//Set / get current midi channel
|
||||
void midiSetChannel(uint8_t channel);
|
||||
uint8_t midiGetChannel();
|
||||
|
||||
void midiSendProgramChange(uint8_t patch);
|
||||
void midiSendControlChange(uint8_t ccParam, uint8_t ccValue);
|
||||
void midiSendNoteOn(uint8_t note, uint8_t velocity);
|
||||
void midiSendNoteOff(uint8_t note);
|
||||
void midiSendAfterTouch(uint8_t value);
|
||||
void midiSendPitchBend(uint16_t value);
|
||||
|
||||
void midiDiscardInput(void);
|
||||
void midiReset(); // reset controllers
|
||||
void midiPanic(); // turn all notes off
|
||||
|
||||
void midiInitialize(uint8_t channel=1);
|
||||
|
||||
void dinMIDIsendControlChange(uint8_t ccNumber, uint8_t cc, uint8_t ch);
|
||||
void dinMIDIsendNoteOn(uint8_t note, uint8_t vel, uint8_t ch);
|
||||
void dinMIDIsendNoteOff(uint8_t note, uint8_t vel, uint8_t ch);
|
||||
void dinMIDIsendAfterTouch(uint8_t value, uint8_t ch);
|
||||
void dinMIDIsendProgramChange(uint8_t value, uint8_t ch);
|
||||
void dinMIDIsendPitchBend(uint16_t pb, uint8_t ch);
|
||||
void dinMIDIsendSysex(const uint8_t data[], const uint8_t length);
|
||||
|
||||
void sendWLPower(const uint8_t level);
|
||||
void sendWLChannel(const uint8_t channel);
|
||||
|
||||
|
||||
//Convert things between "regular data" and MIDI data (byte order and 7-bits-per-byte)
|
||||
uint16_t convertToMidiValue(const uint16_t realdata);
|
||||
uint16_t convertFromMidiValue(const uint16_t mididata);
|
||||
uint16_t convertFromMidiValue(const uint8_t* mididata);
|
||||
uint32_t convertToMidiCRC(const uint32_t realdata);
|
||||
|
||||
#endif
|
||||
#ifndef __MIDI_H
|
||||
#define __MIDI_H
|
||||
|
||||
//This is a completely made up "European" SysEx manufacturer ID.
|
||||
static const char sysex_id[] = { 0x00, 0x3e, 0x7f };
|
||||
|
||||
//Enable use of USB and serial MIDI
|
||||
#define USE_MIDI_USB
|
||||
#define USE_MIDI_SERIAL
|
||||
|
||||
//Set / get current midi channel
|
||||
void midiSetChannel(uint8_t channel);
|
||||
uint8_t midiGetChannel();
|
||||
|
||||
void midiSendProgramChange(uint8_t patch);
|
||||
void midiSendControlChange(uint8_t ccParam, uint8_t ccValue);
|
||||
void midiSendNoteOn(uint8_t note, uint8_t velocity);
|
||||
void midiSendNoteOff(uint8_t note);
|
||||
void midiSendAfterTouch(uint8_t value);
|
||||
void midiSendPitchBend(uint16_t value);
|
||||
|
||||
void midiDiscardInput(void);
|
||||
void midiReset(); // reset controllers
|
||||
void midiPanic(); // turn all notes off
|
||||
|
||||
void midiInitialize(uint8_t channel=1);
|
||||
|
||||
void dinMIDIsendControlChange(uint8_t ccNumber, uint8_t cc, uint8_t ch);
|
||||
void dinMIDIsendNoteOn(uint8_t note, uint8_t vel, uint8_t ch);
|
||||
void dinMIDIsendNoteOff(uint8_t note, uint8_t vel, uint8_t ch);
|
||||
void dinMIDIsendAfterTouch(uint8_t value, uint8_t ch);
|
||||
void dinMIDIsendProgramChange(uint8_t value, uint8_t ch);
|
||||
void dinMIDIsendPitchBend(uint16_t pb, uint8_t ch);
|
||||
void dinMIDIsendSysex(const uint8_t data[], const uint8_t length);
|
||||
|
||||
void sendWLPower(const uint8_t level);
|
||||
void sendWLChannel(const uint8_t channel);
|
||||
|
||||
|
||||
//Convert things between "regular data" and MIDI data (byte order and 7-bits-per-byte)
|
||||
uint16_t convertToMidiValue(const uint16_t realdata);
|
||||
uint16_t convertFromMidiValue(const uint16_t mididata);
|
||||
uint16_t convertFromMidiValue(const uint8_t* mididata);
|
||||
uint32_t convertToMidiCRC(const uint32_t realdata);
|
||||
|
||||
#endif
|
||||
38
NuEVI/name.c → NuEVI/src/name.c
Executable file → Normal file
38
NuEVI/name.c → NuEVI/src/name.c
Executable file → Normal file
|
|
@ -1,22 +1,16 @@
|
|||
// To give your project a unique name, this code must be
|
||||
// placed into a .c file (its own tab). It can not be in
|
||||
// a .cpp file or your main sketch (the .ino file).
|
||||
|
||||
#include "usb_names.h"
|
||||
|
||||
// Edit these lines to create your own name. The length must
|
||||
// match the number of characters in your custom name.
|
||||
#if defined(NURAD)
|
||||
#define MIDI_NAME {'N','u','R','A','D',' ','M','I','D','I'}
|
||||
#else
|
||||
#define MIDI_NAME {'N','u','E','V','I',' ','M','I','D','I'}
|
||||
#endif
|
||||
#define MIDI_NAME_LEN 10
|
||||
|
||||
// Do not change this part. This exact format is required by USB.
|
||||
|
||||
struct usb_string_descriptor_struct usb_string_product_name = {
|
||||
2 + MIDI_NAME_LEN * 2,
|
||||
3,
|
||||
MIDI_NAME
|
||||
};
|
||||
// To give your project a unique name, this code must be
|
||||
// placed into a .c file (its own tab). It can not be in
|
||||
// a .cpp file or your main sketch (the .ino file).
|
||||
|
||||
#include "usb_names.h"
|
||||
|
||||
#define MIDI_NAME {'x','E','V','I',' ','M','I','D','I'}
|
||||
#define MIDI_NAME_LEN 9
|
||||
|
||||
// Do not change this part. This exact format is required by USB.
|
||||
|
||||
struct usb_string_descriptor_struct usb_string_product_name = {
|
||||
2 + MIDI_NAME_LEN * 2,
|
||||
3,
|
||||
MIDI_NAME
|
||||
};
|
||||
342
NuEVI/src/settings.cpp
Normal file
342
NuEVI/src/settings.cpp
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
#include <Arduino.h>
|
||||
#include <EEPROM.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
|
||||
|
||||
#include "settings.h"
|
||||
#include "globals.h"
|
||||
#include "menu.h"
|
||||
#include "hardware.h"
|
||||
#include "config.h"
|
||||
#include "midi.h"
|
||||
#include "led.h"
|
||||
|
||||
//Read and write EEPROM data
|
||||
void writeInt(const uint16_t address, const uint16_t value) {
|
||||
union {
|
||||
uint8_t v[2];
|
||||
uint16_t val;
|
||||
} data;
|
||||
data.val = value;
|
||||
EEPROM.update(address, data.v[0]);
|
||||
EEPROM.update(address+1, data.v[1]);
|
||||
}
|
||||
|
||||
uint16_t readInt(uint16_t address) {
|
||||
union {
|
||||
uint8_t v[2];
|
||||
uint16_t val;
|
||||
} data;
|
||||
data.v[0] = EEPROM.read(address);
|
||||
data.v[1] = EEPROM.read(address+1);
|
||||
return data.val;
|
||||
}
|
||||
|
||||
void writeCalibration() {
|
||||
EEPROM.put(SETTINGS_OFFSET, calibration);
|
||||
}
|
||||
|
||||
void readCalibration() {
|
||||
EEPROM.get(SETTINGS_OFFSET, calibration);
|
||||
}
|
||||
|
||||
void writePreset(uint8_t preset) {
|
||||
EEPROM.put(SETTINGS_OFFSET + preset * sizeof(preset_t), presets[preset]);
|
||||
}
|
||||
|
||||
void writePresets() {
|
||||
EEPROM.put(SETTINGS_OFFSET + CALIBRATION_MAX_SIZE, presets);
|
||||
}
|
||||
|
||||
void readPresets() {
|
||||
EEPROM.get(SETTINGS_OFFSET + CALIBRATION_MAX_SIZE, presets);
|
||||
}
|
||||
|
||||
//Functions to send and receive config (and other things) via USB MIDI SysEx messages
|
||||
uint32_t crc32(const uint8_t *message, const size_t length) {
|
||||
size_t pos=0;
|
||||
uint32_t crc=0xFFFFFFFF;
|
||||
|
||||
while (pos<length) {
|
||||
crc ^= message[pos++]; //Get next byte and increment position
|
||||
for (uint8_t j=0; j<8; ++j) { //Mask off 8 next bits
|
||||
crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1));
|
||||
}
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Send EEPROM config dump as sysex message. Message format is structured like this:
|
||||
|
||||
+------------------------------------------------------------------------------------+
|
||||
| vendor(3) | "NuEVIc01" (8) | Payload size (2) | EEPROM data (variable) | crc32 (4) |
|
||||
+------------------------------------------------------------------------------------+
|
||||
|
||||
Payload size is for the EEPROM data chunk (not including anything else before or after
|
||||
CRC32 covers the entire buffer up to and including the eeprom data (but not the checksum itself)
|
||||
|
||||
This currently operates under the assumption that the whole EEPROM chunk only consists of unsigned 16 bit ints, only using the range 0-16383
|
||||
|
||||
*/
|
||||
void sendSysexSettings() {
|
||||
const char *header = "NuEVIc01"; //NuEVI config dump 01
|
||||
|
||||
//Build a send buffer of all the things
|
||||
size_t sysex_size = 3 + strlen(header) + 2 + EEPROM_SIZE + 4;
|
||||
uint8_t *sysex_data = (uint8_t*)malloc(sysex_size);
|
||||
|
||||
//Positions (offsets) of parts in send buffer
|
||||
int header_pos = 3;
|
||||
int size_pos = header_pos + strlen(header);
|
||||
int payload_pos = size_pos + 2;
|
||||
int checksum_pos = payload_pos + EEPROM_SIZE;
|
||||
|
||||
//SysEX manufacturer ID
|
||||
memcpy(sysex_data, sysex_id, 3);
|
||||
|
||||
//Header with command code
|
||||
memcpy(sysex_data+header_pos, header, strlen(header));
|
||||
|
||||
//Payload length
|
||||
*(uint16_t*)(sysex_data+size_pos) = convertToMidiValue(EEPROM_SIZE);
|
||||
|
||||
//Config data
|
||||
uint16_t* config_buffer_start = (uint16_t*)(sysex_data+payload_pos);
|
||||
|
||||
//Read one settings item at a time, change data format, and put in send buffer
|
||||
readPresets();
|
||||
uint16_t *preset_buffer = (uint16_t*)presets;
|
||||
for(uint16_t idx=0; idx<EEPROM_SIZE/2; idx++) {
|
||||
uint16_t eepromval = preset_buffer[idx];
|
||||
config_buffer_start[idx] = convertToMidiValue(eepromval);
|
||||
}
|
||||
|
||||
uint32_t checksum = crc32(sysex_data, checksum_pos);
|
||||
|
||||
*(uint32_t*)(sysex_data+checksum_pos) = convertToMidiCRC(checksum);
|
||||
|
||||
usbMIDI.sendSysEx(sysex_size, sysex_data);
|
||||
|
||||
free(sysex_data);
|
||||
}
|
||||
|
||||
//Send a simple 3-byte message code as sysex
|
||||
void sendSysexMessage(const char* messageCode) {
|
||||
char sysexMessage[] = "vvvNuEVIccc"; //Placeholders for vendor and code
|
||||
|
||||
memcpy(sysexMessage, sysex_id, 3);
|
||||
memcpy(sysexMessage+8, messageCode, 3);
|
||||
|
||||
usbMIDI.sendSysEx(11, (const uint8_t *)sysexMessage);
|
||||
}
|
||||
|
||||
|
||||
bool receiveSysexSettings(const uint8_t* data, const uint16_t length) {
|
||||
|
||||
//Expected size of data (vendor+NuEVIc02+len+payload+crc32)
|
||||
uint16_t expected_size = 3 + 8 + 2 + EEPROM_SIZE + 4;
|
||||
|
||||
|
||||
//Positions (offsets) of parts in buffer
|
||||
int size_pos = 11;
|
||||
int payload_pos = size_pos + 2;
|
||||
int checksum_pos = payload_pos + EEPROM_SIZE;
|
||||
|
||||
//Make sure length of receive buffer is enough to read all we need to. We can accept extra junk at the end though.
|
||||
if(length<expected_size) {
|
||||
configShowMessage("Invalid config format");
|
||||
return false;
|
||||
}
|
||||
|
||||
//No need to verify vendor or header/command, already done before we get here.
|
||||
|
||||
//Calculate checksum of stuff received (everything before checksum), transform to midi format
|
||||
//(being a one-way operation, we can't do the reverse anyway)
|
||||
uint32_t crc=convertToMidiCRC(crc32(data, checksum_pos));
|
||||
uint32_t crc_rcv;
|
||||
memcpy(&crc_rcv, data+checksum_pos, 4);
|
||||
if(crc != crc_rcv && crc_rcv != NO_CHECKSUM) {
|
||||
configShowMessage("Invalid checksum");
|
||||
return false;
|
||||
}
|
||||
|
||||
//Verify that payload size matches the size of our EEPROM config
|
||||
uint16_t payload_size = convertFromMidiValue(data+size_pos);
|
||||
if(payload_size != EEPROM_SIZE) {
|
||||
configShowMessage("Invalid config size");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
uint16_t eeprom_version_rcv = convertFromMidiValue(data+(payload_pos+EEPROM_VERSION_ADDR));
|
||||
if(eeprom_version_rcv != EEPROM_VERSION) {
|
||||
configShowMessage("Invalid config version");
|
||||
return false;
|
||||
}
|
||||
|
||||
//Grab all the items in payload and save to EEPROM
|
||||
uint16_t *preset_buffer = (uint16_t*)presets;
|
||||
for(uint16_t i=0; i<payload_size/2; i++) {
|
||||
uint16_t addr = i*2;
|
||||
uint16_t val;
|
||||
|
||||
preset_buffer[addr] = convertFromMidiValue(data+(payload_pos+addr));
|
||||
}
|
||||
|
||||
writePresets();
|
||||
|
||||
//All went well
|
||||
return true;
|
||||
}
|
||||
|
||||
//Send EEPROM and firmware versions
|
||||
void sendSysexVersion() {
|
||||
char sysexMessage[] = "vvvNuEVIc04eevvvvvvvv"; //Placeholders for vendor and code
|
||||
uint8_t fwStrLen = min(strlen(FIRMWARE_VERSION), 8); //Limit firmware version string to 8 bytes
|
||||
|
||||
memcpy(sysexMessage, sysex_id, 3);
|
||||
memcpy(sysexMessage+13, FIRMWARE_VERSION, fwStrLen);
|
||||
|
||||
*(uint16_t*)(sysexMessage+11) = convertToMidiValue(EEPROM_VERSION);
|
||||
|
||||
uint8_t message_length = 13+fwStrLen;
|
||||
|
||||
usbMIDI.sendSysEx(message_length, (const uint8_t *)sysexMessage);
|
||||
}
|
||||
|
||||
extern Adafruit_SSD1306 display;
|
||||
|
||||
void configShowMessage(const char* message) {
|
||||
display.fillRect(0,32,128,64,BLACK);
|
||||
display.setCursor(0,32);
|
||||
display.setTextColor(WHITE);
|
||||
|
||||
display.print(message);
|
||||
|
||||
display.display();
|
||||
}
|
||||
|
||||
uint8_t* sysex_rcv_buffer = NULL;
|
||||
uint16_t sysex_buf_size = 0;
|
||||
|
||||
|
||||
void handleSysexChunk(const uint8_t *data, uint16_t length, bool last) {
|
||||
uint16_t pos;
|
||||
|
||||
if(!sysex_rcv_buffer) {
|
||||
//Start out with an empty buffer
|
||||
pos = 0;
|
||||
sysex_buf_size = length;
|
||||
sysex_rcv_buffer = (uint8_t *)malloc(sysex_buf_size);
|
||||
} else {
|
||||
//Increase size of current buffer
|
||||
pos = sysex_buf_size;
|
||||
sysex_buf_size += length;
|
||||
sysex_rcv_buffer = (uint8_t *)realloc(sysex_rcv_buffer, sysex_buf_size);
|
||||
}
|
||||
|
||||
//Append this chunk to buffer
|
||||
memcpy(sysex_rcv_buffer + pos, data, length);
|
||||
|
||||
//If it's the last one, call the regular handler to process it
|
||||
if(last) {
|
||||
handleSysex(sysex_rcv_buffer, sysex_buf_size);
|
||||
|
||||
//Discard the buffer
|
||||
free(sysex_rcv_buffer);
|
||||
sysex_rcv_buffer = NULL;
|
||||
sysex_buf_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void handleSysex(uint8_t *data, unsigned int length) {
|
||||
//Note: Sysex data as received here contains sysex start and end markers (0xF0 and 0xF7)
|
||||
|
||||
//Too short to even contain a 3-byte vendor id is not for us.
|
||||
if(length<4) return;
|
||||
|
||||
//Verify vendor
|
||||
if(strncmp((char*)(data+1), sysex_id, 3)) return; //Silently ignore different vendor id
|
||||
|
||||
//Verify header. Min length is 3+5+3 bytes (vendor+header+message code)
|
||||
if(length<12 || strncmp((char*)(data+4), "NuEVI", 5)) {
|
||||
configShowMessage("Invalid message.");
|
||||
sendSysexMessage("e00");
|
||||
return;
|
||||
}
|
||||
|
||||
//Get message code
|
||||
char messageCode[3];
|
||||
strncpy(messageCode, (char*)(data+9), 3);
|
||||
|
||||
if(!strncmp(messageCode, "c00", 3)) { //Config dump request
|
||||
configShowMessage("Sending config...");
|
||||
sendSysexSettings();
|
||||
configShowMessage("Config sent.");
|
||||
} else if(!strncmp(messageCode, "c03", 3)) { //Version info request
|
||||
configShowMessage("Sending version.");
|
||||
sendSysexVersion();
|
||||
} else if(!strncmp(messageCode, "c02", 3)) { //New config incoming
|
||||
configShowMessage("Receiving config...");
|
||||
|
||||
//Tell receiveSysexSettings about what's between sysex start and end markers
|
||||
if(receiveSysexSettings(data+1, length-2)) configShowMessage("New config saved.");
|
||||
} else {
|
||||
configShowMessage("Unknown message.");
|
||||
sendSysexMessage("e01"); //Unimplemented message code
|
||||
}
|
||||
}
|
||||
|
||||
void configModeSetup() {
|
||||
statusLedFlash(500);
|
||||
|
||||
display.clearDisplay();
|
||||
display.setCursor(0,0);
|
||||
display.setTextColor(WHITE);
|
||||
display.setTextSize(0);
|
||||
|
||||
display.println("Config mgmt");
|
||||
display.println("Power off NuEVI");
|
||||
display.println("to exit");
|
||||
display.display();
|
||||
|
||||
usbMIDI.setHandleSystemExclusive(handleSysexChunk);
|
||||
|
||||
statusLedFlash(500);
|
||||
|
||||
sendSysexVersion(); //Friendly hello
|
||||
|
||||
configShowMessage("Ready.");
|
||||
}
|
||||
|
||||
//"Main loop". Just sits and wait for midi messages and lets the sysex handler do all the work.
|
||||
void configModeLoop() {
|
||||
usbMIDI.read();
|
||||
}
|
||||
|
||||
//Read settings from eeprom. Returns wether or not anything was written (due to factory reset or upgrade)
|
||||
void readEEPROM(const bool factoryReset) {
|
||||
|
||||
// if stored settings are not for current version, or Enter+Menu are pressed at startup, they are replaced by factory settings
|
||||
uint16_t settings_version = readInt(EEPROM_VERSION_ADDR);
|
||||
|
||||
// blank eeprom will be 0xFFFF. For a full reset, call it "version 0" so everything gets overwritten.
|
||||
if (factoryReset || settings_version == 0xffffu) {
|
||||
settings_version = 0;
|
||||
} else {
|
||||
readPresets();
|
||||
readCalibration();
|
||||
}
|
||||
|
||||
if(settings_version != EEPROM_VERSION) {
|
||||
// Add default settings here
|
||||
|
||||
writePresets();
|
||||
writeCalibration();
|
||||
writeInt(EEPROM_VERSION_ADDR, EEPROM_VERSION);
|
||||
}
|
||||
}
|
||||
123
NuEVI/src/settings.h
Normal file
123
NuEVI/src/settings.h
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
#ifndef __SETTINGS_H
|
||||
#define __SETTINGS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "globals.h"
|
||||
|
||||
|
||||
#define EEPROM_VERSION 1
|
||||
#define EEPROM_VERSION_ADDR 0
|
||||
#define SETTINGS_OFFSET 2
|
||||
#define PRESET_MAX_SIZE 128 // Leave extra space for future settings
|
||||
#define PRESET_COUNT 8
|
||||
#define CALIBRATION_MAX_SIZE 54 // Leave extra space for future settings
|
||||
#define EEPROM_SIZE 1080 // Cannot exceed this amount of EEPROM space
|
||||
|
||||
static_assert(SETTINGS_OFFSET + PRESET_MAX_SIZE * PRESET_COUNT + CALIBRATION_MAX_SIZE <= EEPROM_SIZE,
|
||||
"Not enough EEPROM");
|
||||
|
||||
/**
|
||||
* Sensor calibration is global across presets
|
||||
*/
|
||||
struct calibration_t {
|
||||
int16_t breathThrValOffset = 5;
|
||||
int16_t breathMaxValOffset = 1500;
|
||||
int16_t breathAltThrValOffset = 5;
|
||||
int16_t breathAltMaxValOffset = 1500;
|
||||
int16_t biteThrVal = 50;
|
||||
int16_t biteMaxVal = 150;
|
||||
int16_t pbDnThrVal = 50;
|
||||
int16_t pbDnMaxVal = 150;
|
||||
int16_t pbUpThrVal = 50;
|
||||
int16_t pbUpMaxVal = 150;
|
||||
int16_t leverThrVal = 50;
|
||||
int16_t leverMaxVal = 150;
|
||||
int16_t extraThrVal = 50;
|
||||
int16_t extraMaxVal = 150;
|
||||
int16_t ctouchThrVal = 80;
|
||||
uint8_t _reserved[24];
|
||||
};
|
||||
|
||||
static_assert(sizeof(calibration_t) == CALIBRATION_MAX_SIZE, "calibration data wrong size");
|
||||
|
||||
/**
|
||||
* Per-preset config
|
||||
*/
|
||||
struct preset_t {
|
||||
uint8_t MIDIchannel = 1; // Midi channel to send on
|
||||
uint8_t breathCC = 2; // breath CC selection
|
||||
uint8_t altBreathCC = 70; // breath CC selection
|
||||
uint8_t extraCC = 1; // extra CC selection
|
||||
uint8_t leverCC = 7; // "lever" CC selection
|
||||
uint8_t biteCC = 11; // bite CC selection
|
||||
uint8_t fixedVelocity = 0; // Zero = not fixed
|
||||
uint8_t portamentoLimit = 127; // 1-127 - max portamento level
|
||||
uint8_t PBdepth = 1; // OFF:1-12 divider
|
||||
uint8_t deglitch = 20; // debounes time for key/roller inputs
|
||||
uint8_t breathCurve = 4; // breath curve selection
|
||||
uint8_t velSmpDl = 20; // velocity sample delay
|
||||
uint8_t velBias = 0; // velocity bias
|
||||
uint8_t pinkySetting = 12; // 0 - 11 (QuickTranspose -12 to -1), 12 (pb/2), 13 - 24 (QuickTranspose +1 to +12), 25 (EC2), 26 (ECSW), 27 (LVL), 28 (LVLP)
|
||||
uint8_t breathInterval; // 3-15
|
||||
int8_t trill3_interval = 4;
|
||||
uint8_t vibSquelch = 12; // vibrato signal squelch
|
||||
uint8_t cvVibRate = 0; // OFF, 1 - 8 CV extra controller LFO vibrato rate 4.5Hz to 8Hz
|
||||
int8_t cvTune = 0;
|
||||
int8_t cvScale = 0;
|
||||
|
||||
PortamentoMode portamentoMode;
|
||||
BreathMode breathMode = BreathMode::BREATH_LSB_AT;
|
||||
FingeringMode fingering = FingeringMode::EVI;
|
||||
RollerMode rollerMode = RollerMode::HIGHEST;
|
||||
ExtraControl biteControl = ExtraControl::GLIDE;
|
||||
ExtraControl leverControl = ExtraControl::VIBRATO;
|
||||
ExtraControl extraControl = ExtraControl::CC;
|
||||
|
||||
VibratoMode vibratoMode = VSTART_DOWN; // direction of first vibrato wave UPWD or DNWD
|
||||
uint8_t vibratoDepth = 1; // OFF:1-9
|
||||
uint8_t vibSens = 2; // vibrato sensitivity
|
||||
uint8_t vibRetn = 2; // vibrato return speed
|
||||
|
||||
uint8_t knob1CC = 71;
|
||||
uint8_t knob2CC = 72;
|
||||
uint8_t knob3CC = 73;
|
||||
uint8_t knob4CC = 74;
|
||||
|
||||
uint8_t icmAccelMode;
|
||||
uint8_t icmAccelCC;
|
||||
uint8_t icmTiltMode;
|
||||
uint8_t icmTiltCC;
|
||||
uint8_t icmRotationMode;
|
||||
uint8_t icmRotationCC;
|
||||
|
||||
uint8_t _reserved[87];
|
||||
};
|
||||
|
||||
static_assert(sizeof(preset_t) == PRESET_MAX_SIZE, "preset_t must be 128 bytes");
|
||||
extern preset_t presets[PRESET_COUNT];
|
||||
extern calibration_t calibration;
|
||||
extern preset_t *currentPreset;
|
||||
|
||||
#define NO_CHECKSUM 0x7F007F00
|
||||
|
||||
void readEEPROM(const bool factoryReset);
|
||||
void writePreset(uint8_t preset);
|
||||
void writeCalibration();
|
||||
|
||||
//Functions for config management mode
|
||||
void sendSysexSettings();
|
||||
void sendSysexMessage(const char* messageCode);
|
||||
void sendSysexVersion();
|
||||
|
||||
void handleSysex(uint8_t *data, unsigned int length);
|
||||
void handleSysexChunk(const uint8_t *data, uint16_t length, bool last);
|
||||
|
||||
uint32_t crc32(const uint8_t *message, const size_t length);
|
||||
|
||||
void configInitScreen();
|
||||
void configShowMessage(const char* message);
|
||||
|
||||
void configModeSetup();
|
||||
void configModeLoop();
|
||||
|
||||
#endif
|
||||
57
NuEVI/src/test.cpp
Normal file
57
NuEVI/src/test.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#include "hardware.h"
|
||||
|
||||
uint8_t oldButtons = 0;
|
||||
uint16_t oldKeys = 0;
|
||||
uint16_t oldUtil = 0;
|
||||
bool plotCap = false;
|
||||
|
||||
void handleTestMode() {
|
||||
uint8_t buttons = buttonState();
|
||||
if (buttons != oldButtons) {
|
||||
oldButtons = buttons;
|
||||
Serial.print("Buttons:");
|
||||
Serial.println(buttons, HEX);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int k = readKnob(i);
|
||||
if (k != 0) {
|
||||
Serial.print("Knob");
|
||||
Serial.print(i);
|
||||
Serial.print(":");
|
||||
Serial.println(k);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t keys = keysTouched();
|
||||
if (keys != oldKeys) {
|
||||
Serial.print("Keys:");
|
||||
Serial.println(keys, HEX);
|
||||
}
|
||||
|
||||
uint16_t util = utilTouched();
|
||||
if (util != oldUtil) {
|
||||
Serial.print("Util:");
|
||||
Serial.println(util, HEX);
|
||||
}
|
||||
|
||||
if (buttons == 0x01) {
|
||||
plotCap = !plotCap;
|
||||
}
|
||||
|
||||
if (plotCap) {
|
||||
for (int i = 0; i < 12; i++) {
|
||||
Serial.print(">key");
|
||||
Serial.print(i);
|
||||
Serial.print(":");
|
||||
Serial.println(readTouchKey(i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 12; i++) {
|
||||
Serial.print(">util");
|
||||
Serial.print(i);
|
||||
Serial.print(":");
|
||||
Serial.println(readTouchUtil(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
6
NuEVI/src/test.h
Normal file
6
NuEVI/src/test.h
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef __TEST_H
|
||||
#define __TEST_H
|
||||
|
||||
void handleTestMode();
|
||||
|
||||
#endif
|
||||
823
NuEVI/src/xEVI.cpp
Normal file
823
NuEVI/src/xEVI.cpp
Normal file
|
|
@ -0,0 +1,823 @@
|
|||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
#include <array>
|
||||
|
||||
#include "globals.h"
|
||||
#include "hardware.h"
|
||||
#include "midi.h"
|
||||
#include "menu.h"
|
||||
#include "config.h"
|
||||
#include "settings.h"
|
||||
#include "led.h"
|
||||
|
||||
/*
|
||||
NAME: xEVI
|
||||
WRITTEN BY: BRIAN HREBEC
|
||||
BASED ON: NuEVI by JOHAN BERGLUND
|
||||
DATE: 2023-8-23
|
||||
FOR: PJRC Teensy 4.0 and 2x MPR121 capactive touch sensor board.
|
||||
Uses an SSD1306 controlled OLED display communicating over I2C and a NeoPixel LED strip for status display
|
||||
ICM20948 for intertial measurement.
|
||||
FUNCTION: EVI Wind Controller using MPRLS pressure sensors and capacitive touch keys. Output to USB MIDI and CV.
|
||||
*/
|
||||
|
||||
#if !defined(USB_MIDI) && !defined(USB_MIDI_SERIAL)
|
||||
#error "USB MIDI not enabled. Please set USB type to 'MIDI' or 'Serial + MIDI'."
|
||||
#endif
|
||||
|
||||
preset_t presets[PRESET_COUNT];
|
||||
instrument_state_t state;
|
||||
preset_t *currentPreset;
|
||||
calibration_t calibration;
|
||||
|
||||
static const int pbDepthList[13] = { 8192, 8192, 4096, 2731, 2048, 1638, 1365, 1170, 1024, 910, 819, 744, 683 };
|
||||
static const float vibDepth[10] = { 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.40, 0.45 }; // max pitch bend values (+/-) for the vibrato settings
|
||||
static const short vibMaxBiteList[16] = { 1400, 1200, 1000, 900, 800, 700, 600, 500, 400, 300, 250, 200, 150, 100, 50, 25 };
|
||||
static const short vibMaxList[12] = { 300, 275, 250, 225, 200, 175, 150, 125, 100, 75, 50, 25 };
|
||||
static const int timeDividerList[9] = { 0, 222, 200, 181, 167, 152, 143, 130, 125 }; // For CV vibrato - 222 is 4.5Hz, 200 is 5Hz, 181 is 5.5Hz 167 is 6Hz, 152 is 6.5Hz, 143 is 7Hz, 130 is 7.5Hz, 125 is 8Hz
|
||||
|
||||
static const unsigned short curveM4[] = { 0, 4300, 7000, 8700, 9900, 10950, 11900, 12600, 13300, 13900, 14500, 15000, 15450, 15700, 16000, 16250, 16383 };
|
||||
static const unsigned short curveM3[] = { 0, 2900, 5100, 6650, 8200, 9500, 10550, 11500, 12300, 13100, 13800, 14450, 14950, 15350, 15750, 16150, 16383 };
|
||||
static const unsigned short curveM2[] = { 0, 2000, 3600, 5000, 6450, 7850, 9000, 10100, 11100, 12100, 12900, 13700, 14400, 14950, 15500, 16000, 16383 };
|
||||
static const unsigned short curveM1[] = { 0, 1400, 2850, 4100, 5300, 6450, 7600, 8700, 9800, 10750, 11650, 12600, 13350, 14150, 14950, 15650, 16383 };
|
||||
const unsigned short curveIn[] = { 0, 1023, 2047, 3071, 4095, 5119, 6143, 7167, 8191, 9215, 10239, 11263, 12287, 13311, 14335, 15359, 16383 };
|
||||
static const unsigned short curveP1[] = { 0, 600, 1350, 2150, 2900, 3800, 4700, 5600, 6650, 7700, 8800, 9900, 11100, 12300, 13500, 14850, 16383 };
|
||||
static const unsigned short curveP2[] = { 0, 400, 800, 1300, 2000, 2650, 3500, 4300, 5300, 6250, 7400, 8500, 9600, 11050, 12400, 14100, 16383 };
|
||||
static const unsigned short curveP3[] = { 0, 200, 500, 900, 1300, 1800, 2350, 3100, 3800, 4600, 5550, 6550, 8000, 9500, 11250, 13400, 16383 };
|
||||
static const unsigned short curveP4[] = { 0, 100, 200, 400, 700, 1050, 1500, 1950, 2550, 3200, 4000, 4900, 6050, 7500, 9300, 12100, 16383 };
|
||||
static const unsigned short curveS1[] = { 0, 600, 1350, 2150, 2900, 3800, 4700, 6000, 8700, 11000, 12400, 13400, 14300, 14950, 15500, 16000, 16383 };
|
||||
static const unsigned short curveS2[] = { 0, 600, 1350, 2150, 2900, 4000, 6100, 9000, 11000, 12100, 12900, 13700, 14400, 14950, 15500, 16000, 16383 };
|
||||
// static const unsigned short curveS3[] = {0,600,1350,2300,3800,6200,8700,10200,11100,12100,12900,13700,14400,14950,15500,16000,16383};
|
||||
// static const unsigned short curveS4[] = {0,600,1700,4000,6600,8550,9700,10550,11400,12200,12900,13700,14400,14950,15500,16000,16383};
|
||||
|
||||
static const unsigned short curveZ1[] = { 0, 1400, 2100, 2900, 3200, 3900, 4700, 5600, 6650, 7700, 8800, 9900, 11100, 12300, 13500, 14850, 16383 };
|
||||
static const unsigned short curveZ2[] = { 0, 2000, 3200, 3800, 4096, 4800, 5100, 5900, 6650, 7700, 8800, 9900, 11100, 12300, 13500, 14850, 16383 };
|
||||
|
||||
const std::array<const unsigned short*, 13> curves = {
|
||||
curveM4, curveM3, curveM2, curveM1, curveIn, curveP1, curveP2,
|
||||
curveP3, curveP4, curveS1, curveS2, curveZ1, curveZ2 };
|
||||
|
||||
static int waveformsTable[maxSamplesNum] = {
|
||||
// Sine wave
|
||||
0x7ff, 0x86a, 0x8d5, 0x93f, 0x9a9, 0xa11, 0xa78, 0xadd, 0xb40, 0xba1,
|
||||
0xbff, 0xc5a, 0xcb2, 0xd08, 0xd59, 0xda7, 0xdf1, 0xe36, 0xe77, 0xeb4,
|
||||
0xeec, 0xf1f, 0xf4d, 0xf77, 0xf9a, 0xfb9, 0xfd2, 0xfe5, 0xff3, 0xffc,
|
||||
0xfff, 0xffc, 0xff3, 0xfe5, 0xfd2, 0xfb9, 0xf9a, 0xf77, 0xf4d, 0xf1f,
|
||||
0xeec, 0xeb4, 0xe77, 0xe36, 0xdf1, 0xda7, 0xd59, 0xd08, 0xcb2, 0xc5a,
|
||||
0xbff, 0xba1, 0xb40, 0xadd, 0xa78, 0xa11, 0x9a9, 0x93f, 0x8d5, 0x86a,
|
||||
0x7ff, 0x794, 0x729, 0x6bf, 0x655, 0x5ed, 0x586, 0x521, 0x4be, 0x45d,
|
||||
0x3ff, 0x3a4, 0x34c, 0x2f6, 0x2a5, 0x257, 0x20d, 0x1c8, 0x187, 0x14a,
|
||||
0x112, 0xdf, 0xb1, 0x87, 0x64, 0x45, 0x2c, 0x19, 0xb, 0x2,
|
||||
0x0, 0x2, 0xb, 0x19, 0x2c, 0x45, 0x64, 0x87, 0xb1, 0xdf,
|
||||
0x112, 0x14a, 0x187, 0x1c8, 0x20d, 0x257, 0x2a5, 0x2f6, 0x34c, 0x3a4,
|
||||
0x3ff, 0x45d, 0x4be, 0x521, 0x586, 0x5ed, 0x655, 0x6bf, 0x729, 0x794 };
|
||||
|
||||
const int rollerHarmonic[2][7] = { {0, 7, 12, 16, 19, 24, 26}, // F horn 2,3,4,5,6,8,9 hrm
|
||||
{7, 12, 16, 19, 24, 26, 31} }; // Bb horn 3,4,5,6,8,9,12 hrm
|
||||
|
||||
const int trumpetHarmonic[2][7] = { {0, 7, 12, 16, 19, 26, 31}, //! K4: hrm 8->9, 10->12
|
||||
{0, 7, 12, 16, 19, 24, 28} }; // trumpet 2,3,4,5,6,8,10 hrm
|
||||
|
||||
bool configManagementMode = false;
|
||||
bool testMode = false;
|
||||
|
||||
//_______________________________________________________________________________________________ SETUP
|
||||
|
||||
// MIDI note value check with out of range octave repeat
|
||||
inline int noteValueCheck(int note) {
|
||||
if (note > 127) {
|
||||
note = 115 + (note - 127) % 12;
|
||||
} else if (note < 0) {
|
||||
note = 12 - abs(note) % 12;
|
||||
}
|
||||
return note;
|
||||
}
|
||||
|
||||
//***********************************************************
|
||||
|
||||
void port(int portCC) {
|
||||
if (portCC == state.portamentoVal) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentPreset->portamentoMode == PortamentoMode::PON || currentPreset->portamentoMode == PortamentoMode::PGLIDE_ONLY) {
|
||||
if (state.portamentoVal > 0 && portCC == 0) {
|
||||
midiSendControlChange(CCN_PortOnOff, 0);
|
||||
} else if (state.portamentoVal == 0 && portCC > 0) {
|
||||
midiSendControlChange(CCN_PortOnOff, 127);
|
||||
}
|
||||
}
|
||||
|
||||
midiSendControlChange(CCN_Port, portCC);
|
||||
state.portamentoVal = portCC;
|
||||
}
|
||||
|
||||
// Update CV output pin, run from timer.
|
||||
void cvUpdate() {
|
||||
static byte cvPortaTuneCount = 0;
|
||||
uint32_t currentTime = millis();
|
||||
int cvPressure = readPressure();
|
||||
analogWrite(cvBreathPin, cvPressure);
|
||||
state.targetPitch = (state.activeNote - 24) * 42;
|
||||
state.targetPitch += map(state.pitchBend, 0, 16383, -84, 84);
|
||||
state.targetPitch -= state.quarterToneTrigger * 21;
|
||||
if (state.portamentoVal > 0) {
|
||||
if (state.targetPitch > state.cvPitch) {
|
||||
if (!cvPortaTuneCount) {
|
||||
state.cvPitch += 1 + (127 - state.portamentoVal) / 4;
|
||||
} else {
|
||||
cvPortaTuneCount++;
|
||||
if (cvPortaTuneCount > CVPORTATUNE)
|
||||
cvPortaTuneCount = 0;
|
||||
}
|
||||
if (state.cvPitch > state.targetPitch)
|
||||
state.cvPitch = state.targetPitch;
|
||||
} else if (state.targetPitch < state.cvPitch) {
|
||||
if (!cvPortaTuneCount) {
|
||||
state.cvPitch -= 1 + (127 - state.portamentoVal) / 4;
|
||||
} else {
|
||||
cvPortaTuneCount++;
|
||||
if (cvPortaTuneCount > CVPORTATUNE)
|
||||
cvPortaTuneCount = 0;
|
||||
}
|
||||
if (state.cvPitch < state.targetPitch)
|
||||
state.cvPitch = state.targetPitch;
|
||||
} else {
|
||||
state.cvPitch = state.targetPitch;
|
||||
}
|
||||
} else {
|
||||
state.cvPitch = state.targetPitch;
|
||||
}
|
||||
|
||||
if (currentPreset->cvVibRate) {
|
||||
int timeDivider = timeDividerList[currentPreset->cvVibRate];
|
||||
int cvVib = map(((waveformsTable[map(currentTime % timeDivider, 0, timeDivider, 0, maxSamplesNum - 1)] - 2047)), -259968, 259969, -11, 11);
|
||||
state.cvPitch += cvVib;
|
||||
}
|
||||
int cvPitchTuned = 2 * (currentPreset->cvTune) + map(state.cvPitch, 0, 4032, 0, 4032 + 2 * (currentPreset->cvScale));
|
||||
analogWrite(cvPitchPin, constrain(cvPitchTuned, 0, 4095));
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
// non linear mapping function (http://playground.arduino.cc/Main/MultiMap)
|
||||
// note: the _in array should have increasing values
|
||||
unsigned int multiMap(unsigned short val, const unsigned short* _in, const unsigned short* _out, uint8_t size) {
|
||||
// take care the value is within range
|
||||
// val = constrain(val, _in[0], _in[size-1]);
|
||||
if (val <= _in[0])
|
||||
return _out[0];
|
||||
if (val >= _in[size - 1])
|
||||
return _out[size - 1];
|
||||
|
||||
// search right interval
|
||||
uint8_t pos = 1; // _in[0] allready tested
|
||||
while (val > _in[pos])
|
||||
pos++;
|
||||
|
||||
// this will handle all exact "points" in the _in array
|
||||
if (val == _in[pos])
|
||||
return _out[pos];
|
||||
|
||||
// interpolate in the right segment for the rest
|
||||
return (val - _in[pos - 1]) * (_out[pos] - _out[pos - 1]) / (_in[pos] - _in[pos - 1]) + _out[pos - 1];
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**************************************************************
|
||||
|
||||
// map breath values to selected curve
|
||||
unsigned int breathCurve(unsigned int inputVal) {
|
||||
if (currentPreset->breathCurve >= curves.size())
|
||||
return inputVal;
|
||||
return multiMap(inputVal, curveIn, curves[currentPreset->breathCurve], 17);
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
int patchLimit(int value) {
|
||||
return constrain(value, 1, 128);
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
int breath() {
|
||||
static int oldbreath = 0;
|
||||
static unsigned int oldbreathhires = 0;
|
||||
|
||||
int breathCCval, breathCCvalFine;
|
||||
unsigned int breathCCvalHires;
|
||||
breathCCvalHires = breathCurve(mapConstrain(state.breathSignal, state.breathThrVal, state.breathMaxVal, 0, 16383));
|
||||
breathCCval = (breathCCvalHires >> 7) & 0x007F;
|
||||
breathCCvalFine = breathCCvalHires & 0x007F;
|
||||
if (breathCCval != oldbreath) { // only send midi data if breath has changed from previous value
|
||||
if (currentPreset->breathCC) {
|
||||
// send midi cc
|
||||
midiSendControlChange(currentPreset->breathCC, breathCCval);
|
||||
}
|
||||
if (currentPreset->breathMode == BreathMode::BREATH_AT || currentPreset->breathMode == BreathMode::BREATH_LSB_AT) {
|
||||
// send aftertouch
|
||||
midiSendAfterTouch(breathCCval);
|
||||
}
|
||||
oldbreath = breathCCval;
|
||||
}
|
||||
|
||||
if (breathCCvalHires != oldbreathhires
|
||||
&& (currentPreset->breathMode == BreathMode::BREATH_LSB || currentPreset->breathMode == BreathMode::BREATH_LSB_AT)) {
|
||||
midiSendControlChange(currentPreset->breathCC + 32, breathCCvalFine);
|
||||
}
|
||||
|
||||
oldbreathhires = breathCCvalHires;
|
||||
|
||||
return breathCCval;
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
|
||||
void pitch_bend() {
|
||||
// handle input from pitchbend touchpads and
|
||||
// on-pcb variable capacitor for vibrato.
|
||||
static int oldpb = 0;
|
||||
int vibMax;
|
||||
int vibMaxBite;
|
||||
int calculatedPBdepth;
|
||||
byte pbTouched = 0;
|
||||
int vibRead = 0;
|
||||
int vibReadBite = 0;
|
||||
state.pbUpSignal = readTouchUtil(pbUpPin); // PCB PIN "Pu"
|
||||
state.pbDnSignal = readTouchUtil(pbDnPin); // PCB PIN "Pd"
|
||||
bool halfPitchBendKey = (currentPreset->pinkySetting == PBD) && state.pinkyKey; // hold pinky key for 1/2 pitchbend value
|
||||
state.quarterToneTrigger = (currentPreset->pinkySetting == QTN) && state.pinkyKey; // pinky key for a quarter tone down using pitch bend (assuming PB range on synth is set to 2 semitones)
|
||||
|
||||
calculatedPBdepth = pbDepthList[currentPreset->PBdepth];
|
||||
if (halfPitchBendKey)
|
||||
calculatedPBdepth = calculatedPBdepth * 0.5;
|
||||
|
||||
vibMax = vibMaxList[currentPreset->vibSens - 1];
|
||||
|
||||
float calculatedDepth = 0;
|
||||
if (currentPreset->vibratoMode == VibratoMode::VSTART_DOWN) {
|
||||
calculatedDepth = calculatedPBdepth * vibDepth[currentPreset->vibratoDepth];
|
||||
} else {
|
||||
calculatedDepth = (0 - calculatedPBdepth * vibDepth[currentPreset->vibratoDepth]);
|
||||
}
|
||||
|
||||
if (ExtraControl::VIBRATO == currentPreset->biteControl) { // bite vibrato
|
||||
vibMaxBite = vibMaxBiteList[currentPreset->vibSens - 1];
|
||||
vibReadBite = readTouchUtil(bitePin); // get sensor data, do some smoothing - SENSOR PIN 17 - PCB PINS LABELED "BITE" (GND left, sensor pin right)
|
||||
|
||||
if (vibReadBite < state.vibThrBite) {
|
||||
state.vibSignal = (state.vibSignal + mapConstrain(
|
||||
vibReadBite, (state.vibZeroBite - vibMaxBite), state.vibThrBite, calculatedDepth, 0)
|
||||
) / 2;
|
||||
} else if (vibReadBite > state.vibThrBiteLo) {
|
||||
state.vibSignal = (state.vibSignal + mapConstrain(
|
||||
vibReadBite, (state.vibZeroBite + vibMaxBite), state.vibThrBite, calculatedDepth, 0)
|
||||
) / 2;
|
||||
} else {
|
||||
state.vibSignal = state.vibSignal / 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (ExtraControl::VIBRATO == currentPreset->leverControl) { // lever vibrato
|
||||
vibRead = readTouchUtil(vibratoPin);
|
||||
if (vibRead < state.vibThr) {
|
||||
state.vibSignal = (state.vibSignal +
|
||||
mapConstrain(vibRead, (state.vibZero - vibMax), state.vibThr, calculatedDepth, 0)
|
||||
) / 2;
|
||||
} else if (vibRead > state.vibThrLo) {
|
||||
state.vibSignal = (state.vibSignal +
|
||||
mapConstrain(vibRead, (state.vibZero + vibMax), state.vibThr, calculatedDepth, 0)
|
||||
) / 2;
|
||||
} else {
|
||||
state.vibSignal = state.vibSignal / 2;
|
||||
}
|
||||
}
|
||||
|
||||
switch (currentPreset->vibRetn) { // moving baseline
|
||||
case 0:
|
||||
// keep vibZero value
|
||||
break;
|
||||
case 1:
|
||||
state.vibZero = state.vibZero * 0.95 + vibRead * 0.05;
|
||||
state.vibZeroBite = state.vibZeroBite * 0.95 + vibReadBite * 0.05;
|
||||
break;
|
||||
case 2:
|
||||
state.vibZero = state.vibZero * 0.9 + vibRead * 0.1;
|
||||
state.vibZeroBite = state.vibZeroBite * 0.9 + vibReadBite * 0.1;
|
||||
break;
|
||||
case 3:
|
||||
state.vibZero = state.vibZero * 0.8 + vibRead * 0.2;
|
||||
state.vibZeroBite = state.vibZeroBite * 0.8 + vibReadBite * 0.2;
|
||||
break;
|
||||
case 4:
|
||||
state.vibZero = state.vibZero * 0.6 + vibRead * 0.4;
|
||||
state.vibZeroBite = state.vibZeroBite * 0.6 + vibReadBite * 0.4;
|
||||
}
|
||||
state.vibThr = state.vibZero - currentPreset->vibSquelch;
|
||||
state.vibThrLo = state.vibZero + currentPreset->vibSquelch;
|
||||
state.vibThrBite = state.vibZeroBite - currentPreset->vibSquelch;
|
||||
state.vibThrBiteLo = state.vibZeroBite + currentPreset->vibSquelch;
|
||||
int pbPos = mapConstrain(state.pbUpSignal, calibration.pbUpMaxVal, calibration.pbUpThrVal, calculatedPBdepth, 0);
|
||||
int pbNeg = mapConstrain(state.pbDnSignal, calibration.pbDnMaxVal, calibration.pbDnThrVal, calculatedPBdepth, 0);
|
||||
int pbSum = 8193 + pbPos - pbNeg;
|
||||
int pbDif = abs(pbPos - pbNeg);
|
||||
|
||||
if ((state.pbUpSignal < calibration.pbUpThrVal || state.pbDnSignal < calibration.pbDnThrVal) && currentPreset->PBdepth) {
|
||||
if (pbDif < 10) {
|
||||
state.pitchBend = 8192;
|
||||
} else {
|
||||
state.pitchBend = state.pitchBend * 0.6 + 0.4 * pbSum;
|
||||
}
|
||||
pbTouched = 1;
|
||||
}
|
||||
if (!pbTouched) {
|
||||
state.pitchBend = state.pitchBend * 0.6 + 8192 * 0.4; // released, so smooth your way back to zero
|
||||
if ((state.pitchBend > 8187) && (state.pitchBend < 8197))
|
||||
state.pitchBend = 8192; // 8192 is 0 pitch bend, don't miss it bc of smoothing
|
||||
}
|
||||
|
||||
state.pitchBend = state.pitchBend + state.vibSignal;
|
||||
state.pitchBend = constrain(state.pitchBend, 0, 16383);
|
||||
|
||||
state.pbSend = state.pitchBend - state.quarterToneTrigger * calculatedPBdepth * 0.25;
|
||||
state.pbSend = constrain(state.pbSend, 0, 16383);
|
||||
|
||||
if (state.pbSend != oldpb) { // only send midi data if pitch bend has changed from previous value
|
||||
midiSendPitchBend(state.pbSend);
|
||||
oldpb = state.pbSend;
|
||||
}
|
||||
}
|
||||
|
||||
//***********************************************************
|
||||
|
||||
void portamento_() {
|
||||
if (currentPreset->portamentoMode == PortamentoMode::POFF) {
|
||||
port(0); // ensure it's off
|
||||
return;
|
||||
}
|
||||
|
||||
int portSumCC = 0;
|
||||
if (currentPreset->pinkySetting == GLD) {
|
||||
if (state.pinkyKey) {
|
||||
portSumCC += currentPreset->portamentoLimit;
|
||||
}
|
||||
}
|
||||
if (ExtraControl::GLIDE == currentPreset->biteControl) {
|
||||
// Portamento is controlled with the bite sensor in the mouthpiece
|
||||
state.biteSignal = readTouchUtil(bitePin);
|
||||
if (state.biteSignal >= calibration.biteThrVal) { // if we are enabled and over the threshold, send portamento
|
||||
portSumCC += mapConstrain(state.biteSignal, calibration.biteThrVal, calibration.biteMaxVal, 0, currentPreset->portamentoLimit);
|
||||
}
|
||||
}
|
||||
|
||||
if (ExtraControl::GLIDE == currentPreset->leverControl) {
|
||||
// Portamento is controlled with thumb lever
|
||||
state.leverSignal = readTouchUtil(vibratoPin);
|
||||
if (((3000 - state.leverSignal) >= calibration.leverThrVal)) { // if we are enabled and over the threshold, send portamento
|
||||
portSumCC += mapConstrain((3000 - state.leverSignal), calibration.leverThrVal, calibration.leverMaxVal, 0, currentPreset->portamentoLimit);
|
||||
}
|
||||
}
|
||||
|
||||
port(constrain(portSumCC, 0, currentPreset->portamentoLimit)); // Total output glide rate limited to glide max setting
|
||||
}
|
||||
|
||||
//***********************************************************
|
||||
|
||||
void biteCC_() {
|
||||
int biteVal = 0;
|
||||
if (ExtraControl::CC == currentPreset->biteControl) {
|
||||
state.biteSignal = readTouchUtil(bitePin); // get sensor data, do some smoothing - SENSOR PIN 17 - PCB PINS LABELED "BITE" (GND left, sensor pin right)
|
||||
if (state.biteSignal >= calibration.biteThrVal) { // we are over the threshold, calculate CC value
|
||||
biteVal = mapConstrain(state.biteSignal, calibration.biteThrVal, calibration.biteMaxVal, 0, 127);
|
||||
}
|
||||
|
||||
if (biteVal != state.biteVal) {
|
||||
midiSendControlChange(currentPreset->biteCC, biteVal);
|
||||
}
|
||||
state.biteVal = biteVal;
|
||||
}
|
||||
}
|
||||
|
||||
void autoCal() {
|
||||
state.vibZero = state.vibZeroBite = 0;
|
||||
for(int i = 1 ; i <= CALIBRATE_SAMPLE_COUNT; ++i) {
|
||||
state.breathZero += readPressure();
|
||||
state.breathAltZero += readAltPressure();
|
||||
state.vibZero += readTouchUtil(vibratoPin);
|
||||
state.vibZeroBite += readTouchUtil(bitePin);
|
||||
}
|
||||
|
||||
state.breathZero /= CALIBRATE_SAMPLE_COUNT;
|
||||
state.breathAltZero /= CALIBRATE_SAMPLE_COUNT;
|
||||
state.vibZero /= CALIBRATE_SAMPLE_COUNT;
|
||||
state.vibZeroBite /= CALIBRATE_SAMPLE_COUNT;
|
||||
|
||||
state.vibThr = state.vibZero - currentPreset->vibSquelch;
|
||||
state.vibThrLo = state.vibZero + currentPreset->vibSquelch;
|
||||
state.vibThrBite = state.vibZeroBite - currentPreset->vibSquelch;
|
||||
state.vibThrBiteLo = state.vibZeroBite + currentPreset->vibSquelch;
|
||||
|
||||
state.breathThrVal = state.breathZero + calibration.breathThrValOffset;
|
||||
state.breathMaxVal = state.breathThrVal + calibration.breathMaxValOffset;
|
||||
state.breathAltThrVal = state.breathAltZero + calibration.breathAltThrValOffset;
|
||||
state.breathAltMaxVal = state.breathAltThrVal + calibration.breathAltMaxValOffset;
|
||||
|
||||
}
|
||||
|
||||
void fullAutoCal() {
|
||||
int calRead;
|
||||
int calReadNext;
|
||||
autoCal();
|
||||
|
||||
// Lever
|
||||
calRead = 3000 - readTouchUtil(vibratoPin);
|
||||
calibration.leverThrVal = constrain(calRead + 60, LEVER_LO_LIMIT, LEVER_HI_LIMIT);
|
||||
calibration.leverMaxVal = constrain(calRead + 120, LEVER_LO_LIMIT, LEVER_HI_LIMIT);
|
||||
|
||||
// Bite sensor
|
||||
calRead = readTouchUtil(bitePin);
|
||||
calibration.biteThrVal = constrain(calRead + 100, BITE_LO_LIMIT, BITE_HI_LIMIT);
|
||||
calibration.biteMaxVal = constrain(calibration.biteThrVal + 300, BITE_LO_LIMIT, BITE_HI_LIMIT);
|
||||
|
||||
// Touch sensors
|
||||
calRead = CTOUCH_HI_LIMIT;
|
||||
for (byte i = 0; i < 12; i++) {
|
||||
calReadNext = readTouchKey(i);
|
||||
if (calReadNext < calRead)
|
||||
calRead = calReadNext; // use lowest value
|
||||
}
|
||||
|
||||
calibration.ctouchThrVal = calRead - 20;
|
||||
}
|
||||
|
||||
//***********************************************************
|
||||
|
||||
/*
|
||||
* Read octave and return offset
|
||||
*/
|
||||
int readOctave() {
|
||||
static byte lastOctaveR = 0;
|
||||
|
||||
// Roller modes
|
||||
// 1: Highest touched roller, release memory
|
||||
// 2: Highest touched roller, extend range on top/bottom release
|
||||
// 3: Touched roller pair
|
||||
// 4: Touched roller pair, extend range
|
||||
// 5: Touched roller, pair = 5th partial
|
||||
// 6: Touched roller, pair = 5th partial, extend range
|
||||
RollerMode rollerMode = currentPreset->rollerMode;
|
||||
byte extend = rollerMode == RollerMode::HIGHEST_EXTEND || rollerMode == RollerMode::HIGHEST_PAIR_EXTEND || rollerMode == RollerMode::PARTIAL_EXTEND ? 1 : 0;
|
||||
|
||||
byte rollers[6];
|
||||
uint16_t ctouchThrVal = calibration.ctouchThrVal;
|
||||
rollers[0] = readTouchUtil(R1Pin) < ctouchThrVal;
|
||||
rollers[1] = readTouchUtil(R2Pin) < ctouchThrVal;
|
||||
rollers[2] = readTouchUtil(R3Pin) < ctouchThrVal;
|
||||
rollers[3] = readTouchUtil(R4Pin) < ctouchThrVal;
|
||||
rollers[4] = readTouchUtil(R5Pin) < ctouchThrVal;
|
||||
rollers[5] = readTouchUtil(R6Pin) < ctouchThrVal;
|
||||
|
||||
byte offset = 0;
|
||||
byte octaveR = 0;
|
||||
if (rollerMode == RollerMode::HIGHEST || rollerMode == RollerMode::HIGHEST_EXTEND) {
|
||||
for (int i = 5; i >= 0; i--) {
|
||||
if (rollers[i]) {
|
||||
octaveR = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (rollerMode == RollerMode::HIGHEST_PAIR || rollerMode == RollerMode::HIGHEST_PAIR_EXTEND) {
|
||||
for (int i = 5; i >= 1; i--) {
|
||||
if (rollers[i] && rollers[i - 1]) {
|
||||
octaveR = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Allow top/bottom single rollers in extended mode
|
||||
if (octaveR == 0 && extend) {
|
||||
if (rollers[0]) {
|
||||
octaveR = 1;
|
||||
} else if (rollers[5]) {
|
||||
octaveR = 6;
|
||||
}
|
||||
}
|
||||
} else if (rollerMode == RollerMode::PARTIAL || rollerMode == RollerMode::PARTIAL_EXTEND) {
|
||||
for (int i = 5; i >= 0; i--) {
|
||||
if (rollers[i]) {
|
||||
octaveR = i + 1;
|
||||
if (i > 0 && rollers[i - 1]) {
|
||||
offset = -5;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Go up/down a partial on top/bottom release
|
||||
if (extend && octaveR == 0) {
|
||||
if (lastOctaveR == 1) {
|
||||
offset = -5;
|
||||
} else if (lastOctaveR == 6) {
|
||||
offset = 7;
|
||||
}
|
||||
|
||||
octaveR = lastOctaveR;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle extended release
|
||||
if (extend && octaveR == 0) {
|
||||
if (rollerMode == RollerMode::HIGHEST_EXTEND && lastOctaveR == 6) {
|
||||
octaveR = 7;
|
||||
} else if (rollerMode == RollerMode::PARTIAL_EXTEND && lastOctaveR == 7) {
|
||||
octaveR = 8;
|
||||
} else if (lastOctaveR == 1) {
|
||||
octaveR = 0;
|
||||
} else {
|
||||
octaveR = lastOctaveR;
|
||||
}
|
||||
}
|
||||
|
||||
lastOctaveR = octaveR;
|
||||
|
||||
FingeringMode fingering = currentPreset->fingering;
|
||||
byte K4 = readTouchKey(K4Pin) < calibration.ctouchThrVal;
|
||||
if (FingeringMode::TPT == fingering) { // TPT fingering
|
||||
return 24 + offset + trumpetHarmonic[K4][octaveR]; // roller harmonics
|
||||
} else if (FingeringMode::HRN == fingering) { // HRN fingering
|
||||
return 12 + offset + rollerHarmonic[K4][octaveR]; // roller harmonics
|
||||
} else if (FingeringMode::EVR == fingering) { // HRN fingering
|
||||
return 12 * (6 - octaveR) + offset;
|
||||
} else { // EVI
|
||||
return 12 * octaveR + offset;
|
||||
}
|
||||
}
|
||||
|
||||
int readSwitches() {
|
||||
// Keep the last fingering value for debouncing
|
||||
static int lastFingering = 0;
|
||||
static int fingeredNote = 0;
|
||||
static unsigned long lastDeglitchTime = 0; // The last time the fingering was changed
|
||||
|
||||
// Read touch pads (MPR121), compare against threshold value
|
||||
bool touchKeys[12];
|
||||
for (byte i = 0; i < 12; i++) {
|
||||
touchKeys[i] = readTouchKey(i) < calibration.ctouchThrVal;
|
||||
}
|
||||
|
||||
// Valves and trill keys, TRUE (1) for pressed, FALSE (0) for not pressed
|
||||
byte K1 = touchKeys[K1Pin]; // Valve 1 (pitch change -2)
|
||||
byte K2 = touchKeys[K2Pin]; // Valve 2 (pitch change -1)
|
||||
byte K3 = touchKeys[K3Pin]; // Valve 3 (pitch change -3)
|
||||
byte K4 = touchKeys[K4Pin]; // Left Hand index finger (pitch change -5)
|
||||
byte K5 = touchKeys[K5Pin]; // Trill key 1 (pitch change +2)
|
||||
byte K6 = touchKeys[K6Pin]; // Trill key 2 (pitch change +1)
|
||||
byte K7 = touchKeys[K7Pin]; // Trill key 3 (pitch change +4)
|
||||
|
||||
state.pinkyKey = touchKeys[K8Pin];
|
||||
|
||||
int qTransp = (state.pinkyKey && (currentPreset->pinkySetting < 25)) ? currentPreset->pinkySetting - 12 : 0;
|
||||
|
||||
// Calculate midi note number from pressed keys
|
||||
int fingeredNoteUntransposed = 0;
|
||||
if (EVI == currentPreset->fingering) { // EVI fingering
|
||||
fingeredNoteUntransposed = START_NOTE - 2 * K1 - K2 - 3 * K3 //"Trumpet valves"
|
||||
- 5 * K4 // Fifth key
|
||||
+ 2 * K5 + K6 + currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting
|
||||
} else if (EVR == currentPreset->fingering) { // EVR fingering
|
||||
fingeredNoteUntransposed = START_NOTE - 2 * K1 - K2 - 3 * K3 //"Trumpet valves"
|
||||
- 5 * K4 // Fifth key
|
||||
+ 2 * K5 + K6 + currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting
|
||||
} else if (TPT == currentPreset->fingering) { // TPT fingering
|
||||
fingeredNoteUntransposed = START_NOTE - 2 * K1 - K2 - 3 * K3 //"Trumpet valves"
|
||||
- 2 // Trumpet in B flat
|
||||
+ 2 * K5 + K6 + currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting
|
||||
} else if (HRN == currentPreset->fingering) { // HRN fingering
|
||||
fingeredNoteUntransposed = START_NOTE - 2 * K1 - K2 - 3 * K3 //"Trumpet valves"
|
||||
+ 5 * K4 // Switch to Bb horn
|
||||
+ 5 // Horn in F
|
||||
+ 2 * K5 + K6 + currentPreset->trill3_interval * K7; // Trill keys. 3rd trill key interval controlled by setting
|
||||
}
|
||||
|
||||
if (K3 && K7) {
|
||||
if (4 == currentPreset->trill3_interval)
|
||||
fingeredNoteUntransposed += 2;
|
||||
else
|
||||
fingeredNoteUntransposed += 4;
|
||||
}
|
||||
|
||||
int fingeredNoteRead = fingeredNoteUntransposed + state.transpose - 12 + qTransp;
|
||||
|
||||
if (fingeredNoteRead != lastFingering) { //
|
||||
// reset the debouncing timer
|
||||
lastDeglitchTime = millis();
|
||||
}
|
||||
|
||||
if ((millis() - lastDeglitchTime) > currentPreset->deglitch) {
|
||||
// whatever the reading is at, it's been there for longer
|
||||
// than the debounce delay, so take it as the actual current state
|
||||
fingeredNote = fingeredNoteRead;
|
||||
}
|
||||
|
||||
lastFingering = fingeredNoteRead;
|
||||
|
||||
return fingeredNote;
|
||||
}
|
||||
|
||||
void noteOn(int fingeredNote, float pressureSensor, int initial_breath_value) {
|
||||
// Yes, so calculate MIDI note and velocity, then send a note on event
|
||||
// We should be at tonguing peak, so set velocity based on current pressureSensor value unless fixed velocity is set
|
||||
state.breathSignal = constrain(max(pressureSensor, initial_breath_value), state.breathThrVal, state.breathMaxVal);
|
||||
byte velocitySend;
|
||||
if (!currentPreset->fixedVelocity) {
|
||||
unsigned int breathValHires = breathCurve(mapConstrain(state.breathSignal, state.breathThrVal, state.breathMaxVal, 0, 16383));
|
||||
velocitySend = (breathValHires >> 7) & 0x007F;
|
||||
velocitySend = constrain(velocitySend + velocitySend * .1 * currentPreset->velBias, 1, 127);
|
||||
} else {
|
||||
velocitySend = currentPreset->fixedVelocity;
|
||||
}
|
||||
|
||||
breath(); // send breath data
|
||||
midiSendNoteOn(fingeredNote, velocitySend); // send Note On message for new note
|
||||
state.activeNote = fingeredNote;
|
||||
}
|
||||
|
||||
void handleOffStateActions() {
|
||||
if (state.activeMIDIchannel != currentPreset->MIDIchannel) {
|
||||
state.activeMIDIchannel = currentPreset->MIDIchannel; // only switch channel if no active note
|
||||
midiSetChannel(state.activeMIDIchannel);
|
||||
}
|
||||
if ((state.activePatch != state.patch) && state.doPatchUpdate) {
|
||||
state.activePatch = state.patch;
|
||||
midiSendProgramChange(state.activePatch);
|
||||
state.doPatchUpdate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize the main instrument state
|
||||
*/
|
||||
void initState() {
|
||||
state.activePatch = 0;
|
||||
state.mainState = NOTE_OFF; // initialize main state machine
|
||||
|
||||
state.activeMIDIchannel = currentPreset->MIDIchannel;
|
||||
midiInitialize(currentPreset->MIDIchannel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send CC data when needed
|
||||
*/
|
||||
void sendCCs() {
|
||||
static unsigned long ccBreathSendTime = 0L; // The last time we sent breath CC values
|
||||
static unsigned long ccSendTime = 0L; // The last time we sent CC values
|
||||
static unsigned long ccSendTime2 = 0L; // The last time we sent CC values 2 (slower)
|
||||
static unsigned long ccSendTime3 = 0L; // The last time we sent CC values 3 (and slower)
|
||||
|
||||
// Is it time to send more CC data?
|
||||
uint32_t currentTime = millis();
|
||||
if ((currentTime - ccBreathSendTime) > (currentPreset->breathInterval - 1u)) {
|
||||
breath();
|
||||
ccBreathSendTime = currentTime;
|
||||
}
|
||||
if (currentTime - ccSendTime > CC_INTERVAL_PRIMARY) {
|
||||
// deal with Pitch Bend, Modulation, etc.
|
||||
pitch_bend();
|
||||
biteCC_();
|
||||
ccSendTime = currentTime;
|
||||
}
|
||||
if (currentTime - ccSendTime2 > CC_INTERVAL_PORT) {
|
||||
portamento_();
|
||||
ccSendTime2 = currentTime;
|
||||
}
|
||||
if (currentTime - ccSendTime3 > CC_INTERVAL_OTHER) {
|
||||
updateSensorLEDs();
|
||||
ccSendTime3 = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main instrument state machine
|
||||
*/
|
||||
void runStateMachine() {
|
||||
static unsigned long breath_on_time = 0L; // Time when breath sensor value went over the ON threshold
|
||||
static int initial_breath_value = 0; // The breath value at the time we observed the transition
|
||||
|
||||
int fingeredNote = noteValueCheck(readSwitches() + readOctave());
|
||||
if (state.mainState == NOTE_OFF) {
|
||||
handleOffStateActions();
|
||||
if ((state.breathSignal > state.breathThrVal)) {
|
||||
// Value has risen above threshold. Move to the RISE_WAIT
|
||||
// state. Record time and initial breath value.
|
||||
breath_on_time = millis();
|
||||
initial_breath_value = state.breathSignal;
|
||||
state.mainState = RISE_WAIT; // Go to next state
|
||||
}
|
||||
} else if (state.mainState == RISE_WAIT) {
|
||||
if ((state.breathSignal > state.breathThrVal)) {
|
||||
// Has enough time passed for us to collect our second sample?
|
||||
if ((millis() - breath_on_time > currentPreset->velSmpDl) || (0 == currentPreset->velSmpDl) || currentPreset->fixedVelocity) {
|
||||
noteOn(fingeredNote, state.breathSignal, initial_breath_value);
|
||||
state.mainState = NOTE_ON;
|
||||
}
|
||||
} else {
|
||||
// Value fell below threshold before velocity sample delay time passed. Return to NOTE_OFF state
|
||||
state.mainState = NOTE_OFF;
|
||||
}
|
||||
} else if (state.mainState == NOTE_ON) {
|
||||
if ((state.breathSignal < state.breathThrVal)) {
|
||||
// Value has fallen below threshold - turn the note off
|
||||
midiSendNoteOff(state.activeNote); // send Note Off message
|
||||
state.breathSignal = 0;
|
||||
state.mainState = NOTE_OFF;
|
||||
} else {
|
||||
if (fingeredNote != state.activeNote) {
|
||||
// Player has moved to a new fingering while still blowing.
|
||||
// Send a note off for the current note and a note on for
|
||||
// the new note.
|
||||
noteOn(fingeredNote, state.breathSignal, 0);
|
||||
delayMicroseconds(2000); // delay for midi recording fix
|
||||
midiSendNoteOff(state.activeNote); // send Note Off message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
if (checkButtonState(DEBUG_CONFIG)) {
|
||||
Serial.begin(9600); // debug
|
||||
Serial.println("Debug Startup");
|
||||
}
|
||||
|
||||
bool factoryReset = checkButtonState(STARTUP_FACTORY_RESET);
|
||||
configManagementMode = checkButtonState(STARTUP_CONFIG);
|
||||
testMode = checkButtonState(TEST_CONFIG);
|
||||
|
||||
initDisplay(); // Start up display and show logo
|
||||
initHardware();
|
||||
|
||||
// If going into config management mode, stop here before we even touch the EEPROM.
|
||||
if (configManagementMode) {
|
||||
configModeSetup();
|
||||
return;
|
||||
}
|
||||
|
||||
// Read eeprom data into global vars
|
||||
readEEPROM(factoryReset);
|
||||
|
||||
statusLedFlash(500);
|
||||
statusLedOff();
|
||||
|
||||
if (factoryReset) {
|
||||
// Full calibration
|
||||
fullAutoCal();
|
||||
} else {
|
||||
// Minimal startup calibration (atmo pressure)
|
||||
autoCal();
|
||||
}
|
||||
|
||||
showVersion();
|
||||
delay(1000);
|
||||
|
||||
initState(); // Set up midi/etc
|
||||
statusLedOn(); // Switch on the onboard LED to indicate power on/ready
|
||||
}
|
||||
|
||||
//_______________________________________________________________________________________________ MAIN LOOP
|
||||
|
||||
void loop() {
|
||||
static unsigned long pixelUpdateTime = 0;
|
||||
static const unsigned long pixelUpdateInterval = 80;
|
||||
|
||||
// If in config mgmt loop, do that and nothing else
|
||||
if (configManagementMode) {
|
||||
configModeLoop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (testMode) {
|
||||
|
||||
}
|
||||
|
||||
state.breathSignal = constrain(readPressure(), BREATH_LO_LIMIT, BREATH_HI_LIMIT); // Get the filtered pressure sensor reading from analog pin A0, input from sensor MP3V5004GP
|
||||
|
||||
runStateMachine();
|
||||
sendCCs();
|
||||
|
||||
// cvUpdate();
|
||||
midiDiscardInput();
|
||||
|
||||
if (millis() - pixelUpdateTime > pixelUpdateInterval) {
|
||||
// even if we just alter a pixel, the whole display is redrawn (35ms of MPU lockup) and we can't do that all the time
|
||||
// this is one of the big reasons the display is for setup use only
|
||||
// TODO: is this still true on teensy 4?
|
||||
pixelUpdateTime = millis();
|
||||
handleMenu(true);
|
||||
} else {
|
||||
handleMenu(false);
|
||||
}
|
||||
|
||||
}
|
||||
70
README.md
Executable file → Normal file
70
README.md
Executable file → Normal file
|
|
@ -1,35 +1,35 @@
|
|||
# NuEVI
|
||||
A project by wind controller enthusiasts wanting to save the endangered Electronic Valve Instrument.
|
||||
|
||||
Follow the project at https://hackaday.io/project/25756-diy-evi-style-windcontroller
|
||||
|
||||
|
||||
## Building NuEVI
|
||||
|
||||
NuEVI is easiest to build using the Arduino IDE. You will also need to download and install
|
||||
[Teensyduino](https://www.pjrc.com/teensy/td_download.html) to build for and upload to the Teensy.
|
||||
|
||||
### Libraries
|
||||
|
||||
A few libraries need to be added that are not part of the default Arduino install. These can be
|
||||
added directly via the Library Manager in the Arduino IDE:
|
||||
* Adafruit MPR121
|
||||
* Adafruit GFX
|
||||
* Adafruit SSD1306 (version 1.2.9 or above)
|
||||
* NuEVI also includes on the [Filters](https://github.com/JonHub/Filters) library by Jonathan Driscoll, but that is no longer an external dependency.
|
||||
|
||||
|
||||
### Compile options
|
||||
|
||||
Open NuEVI.ino in the Arduino IDE. Under "Tools -> Board", select "Teensy 3.2 / 3.1". Then set
|
||||
"Tools -> USB Type" to "MIDI".
|
||||
|
||||
### Building and uploading
|
||||
|
||||
Connect the NuEVI via USB to your computer, open the Teensy application and make sure the "Auto"
|
||||
option is selected (the green round icon). In Arduino IDE, select "Sketch -> Verify/Compile" and
|
||||
once that is complete press the reset button on the Teensy chip (you have to remove the top cover
|
||||
on the NuEVI to access this). Upon resetting, it should upload the new firmware onto the NuEVI.
|
||||
|
||||
After uploading new firmware, you may need to reset the config memory of the NuEVI. To do this, press
|
||||
and hold the MENU and ENTER buttons while turning on the NuEVI. Note that this resets all sensor calibrations too. For new versions this should not be neccessary, as value and version checks are in place.
|
||||
# NuEVI
|
||||
A project by wind controller enthusiasts wanting to save the endangered Electronic Valve Instrument.
|
||||
|
||||
Follow the project at https://hackaday.io/project/25756-diy-evi-style-windcontroller
|
||||
|
||||
|
||||
## Building NuEVI
|
||||
|
||||
NuEVI is easiest to build using the Arduino IDE. You will also need to download and install
|
||||
[Teensyduino](https://www.pjrc.com/teensy/td_download.html) to build for and upload to the Teensy.
|
||||
|
||||
### Libraries
|
||||
|
||||
A few libraries need to be added that are not part of the default Arduino install. These can be
|
||||
added directly via the Library Manager in the Arduino IDE:
|
||||
* Adafruit MPR121
|
||||
* Adafruit GFX
|
||||
* Adafruit SSD1306 (version 1.2.9 or above)
|
||||
* NuEVI also includes on the [Filters](https://github.com/JonHub/Filters) library by Jonathan Driscoll, but that is no longer an external dependency.
|
||||
|
||||
|
||||
### Compile options
|
||||
|
||||
Open NuEVI.ino in the Arduino IDE. Under "Tools -> Board", select "Teensy 3.2 / 3.1". Then set
|
||||
"Tools -> USB Type" to "MIDI".
|
||||
|
||||
### Building and uploading
|
||||
|
||||
Connect the NuEVI via USB to your computer, open the Teensy application and make sure the "Auto"
|
||||
option is selected (the green round icon). In Arduino IDE, select "Sketch -> Verify/Compile" and
|
||||
once that is complete press the reset button on the Teensy chip (you have to remove the top cover
|
||||
on the NuEVI to access this). Upon resetting, it should upload the new firmware onto the NuEVI.
|
||||
|
||||
After uploading new firmware, you may need to reset the config memory of the NuEVI. To do this, press
|
||||
and hold the MENU and ENTER buttons while turning on the NuEVI. Note that this resets all sensor calibrations too. For new versions this should not be neccessary, as value and version checks are in place.
|
||||
|
|
|
|||
|
|
@ -1,153 +1,153 @@
|
|||
#include <Wire.h>
|
||||
#include <Adafruit_MPR121.h>
|
||||
|
||||
/*
|
||||
Tool to test an MPR121 unit. Wires each touch input to a teensy pin to simulate touch sensor signals.
|
||||
Used to detect faulty MPR121 units before assembly.
|
||||
*/
|
||||
|
||||
Adafruit_MPR121 touchSensor = Adafruit_MPR121(); // This is the 12-input touch sensor
|
||||
|
||||
//LED output pins. Red is the onboard one, other two are just wired via resistors to +3.3V
|
||||
#define RED_LED 13
|
||||
#define GREEN_LED 20
|
||||
#define YELLOW_LED 21
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
|
||||
//Set all "test ports" to high-impedance for now
|
||||
for(int i=0; i<=11; i++) {
|
||||
pinMode(i, INPUT);
|
||||
}
|
||||
|
||||
pinMode(RED_LED, OUTPUT); led(RED_LED, true);
|
||||
pinMode(GREEN_LED, OUTPUT); led(GREEN_LED, true);
|
||||
pinMode(YELLOW_LED, OUTPUT); led(YELLOW_LED, true);
|
||||
|
||||
delay(100);
|
||||
int serialwait = 100; //Max time to wait for serial port initialization
|
||||
while(!Serial && serialwait)
|
||||
{
|
||||
delay(1);
|
||||
--serialwait;
|
||||
}
|
||||
|
||||
led(RED_LED, false);
|
||||
led(GREEN_LED, false);
|
||||
led(YELLOW_LED, false);
|
||||
|
||||
Serial.println("Running MPR121 test");
|
||||
|
||||
if (!touchSensor.begin(0x5A)) {
|
||||
//Bail out if MPR121 cannot be initialized (chip broken or not present).
|
||||
Serial.println("MPR121 initialization failed!");
|
||||
failure();
|
||||
return;
|
||||
} else {
|
||||
Serial.println("MPR121 init ok.");
|
||||
}
|
||||
|
||||
//Attempt some kind of random seeding
|
||||
srandom(analogRead(0) ^ millis());
|
||||
delay(200);
|
||||
|
||||
run_all();
|
||||
}
|
||||
|
||||
void led(uint8_t pin, bool state) {
|
||||
//Onboard red LED is wired a bit differently
|
||||
if(pin != RED_LED) {
|
||||
digitalWrite(pin, state?LOW:HIGH);
|
||||
} else {
|
||||
digitalWrite(pin, state?HIGH:LOW);
|
||||
}
|
||||
}
|
||||
|
||||
void set_touch_pins(uint16_t value)
|
||||
{
|
||||
for(int pin=0; pin<12; ++pin)
|
||||
{
|
||||
uint16_t touched = (value >> pin) & 0x0001; //Mask out bit value of pin
|
||||
int teensyPin = 11-pin; //Row of teensy pins is 0-11 but mirrored vs MPR121
|
||||
|
||||
if(touched) {
|
||||
pinMode(teensyPin, INPUT_PULLDOWN);
|
||||
} else {
|
||||
pinMode(teensyPin, INPUT_PULLUP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool run_test(const char* name, uint16_t value) {
|
||||
Serial.print(name);
|
||||
set_touch_pins(value);
|
||||
led(YELLOW_LED, true);
|
||||
delay(50);
|
||||
led(YELLOW_LED, false);
|
||||
delay(50);
|
||||
uint16_t t = touchSensor.touched();
|
||||
Serial.print(", expected: ");
|
||||
Serial.print(value, HEX);
|
||||
Serial.print(" got: ");
|
||||
Serial.print(t, HEX);
|
||||
|
||||
if(value == t) {
|
||||
Serial.println(" PASS");
|
||||
return true;
|
||||
} else {
|
||||
Serial.println(" FAIL");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void failure() {
|
||||
led(RED_LED, true);
|
||||
led(GREEN_LED, false);
|
||||
Serial.println("Test failed!");
|
||||
}
|
||||
|
||||
void success() {
|
||||
led(RED_LED, false);
|
||||
led(GREEN_LED, true);
|
||||
Serial.println("All tests succeeded!");
|
||||
}
|
||||
|
||||
//Macro to bail out on any failure
|
||||
#define TEST(x) if(!x) { failure(); return; }
|
||||
|
||||
void run_all(void) {
|
||||
|
||||
TEST(run_test("ALL_OFF", 0x000));
|
||||
TEST(run_test("ALL_ON", 0xFFF));
|
||||
|
||||
//Pins one at a time
|
||||
TEST(run_test("P0", 0x001 << 0));
|
||||
TEST(run_test("P1", 0x001 << 1));
|
||||
TEST(run_test("P2", 0x001 << 2));
|
||||
TEST(run_test("P3", 0x001 << 3));
|
||||
TEST(run_test("P4", 0x001 << 4));
|
||||
TEST(run_test("P5", 0x001 << 5));
|
||||
TEST(run_test("P6", 0x001 << 6));
|
||||
TEST(run_test("P7", 0x001 << 7));
|
||||
TEST(run_test("P8", 0x001 << 8));
|
||||
TEST(run_test("P9", 0x001 << 9));
|
||||
TEST(run_test("P10", 0x001 << 10));
|
||||
TEST(run_test("P11", 0x001 << 11));
|
||||
|
||||
//Alternating pattern
|
||||
TEST(run_test("ODD", 0x0555));
|
||||
TEST(run_test("EVEN", 0x0AAA));
|
||||
|
||||
//A few random ones for good measure
|
||||
for(int i=0; i<8; i++) {
|
||||
TEST(run_test("RANDOM", random() % 0x1000));
|
||||
}
|
||||
|
||||
success();
|
||||
}
|
||||
|
||||
//Dummy loop does nothing
|
||||
void loop() {
|
||||
delay(100);
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_MPR121.h>
|
||||
|
||||
/*
|
||||
Tool to test an MPR121 unit. Wires each touch input to a teensy pin to simulate touch sensor signals.
|
||||
Used to detect faulty MPR121 units before assembly.
|
||||
*/
|
||||
|
||||
Adafruit_MPR121 touchSensor = Adafruit_MPR121(); // This is the 12-input touch sensor
|
||||
|
||||
//LED output pins. Red is the onboard one, other two are just wired via resistors to +3.3V
|
||||
#define RED_LED 13
|
||||
#define GREEN_LED 20
|
||||
#define YELLOW_LED 21
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
|
||||
//Set all "test ports" to high-impedance for now
|
||||
for(int i=0; i<=11; i++) {
|
||||
pinMode(i, INPUT);
|
||||
}
|
||||
|
||||
pinMode(RED_LED, OUTPUT); led(RED_LED, true);
|
||||
pinMode(GREEN_LED, OUTPUT); led(GREEN_LED, true);
|
||||
pinMode(YELLOW_LED, OUTPUT); led(YELLOW_LED, true);
|
||||
|
||||
delay(100);
|
||||
int serialwait = 100; //Max time to wait for serial port initialization
|
||||
while(!Serial && serialwait)
|
||||
{
|
||||
delay(1);
|
||||
--serialwait;
|
||||
}
|
||||
|
||||
led(RED_LED, false);
|
||||
led(GREEN_LED, false);
|
||||
led(YELLOW_LED, false);
|
||||
|
||||
Serial.println("Running MPR121 test");
|
||||
|
||||
if (!touchSensor.begin(0x5A)) {
|
||||
//Bail out if MPR121 cannot be initialized (chip broken or not present).
|
||||
Serial.println("MPR121 initialization failed!");
|
||||
failure();
|
||||
return;
|
||||
} else {
|
||||
Serial.println("MPR121 init ok.");
|
||||
}
|
||||
|
||||
//Attempt some kind of random seeding
|
||||
srandom(analogRead(0) ^ millis());
|
||||
delay(200);
|
||||
|
||||
run_all();
|
||||
}
|
||||
|
||||
void led(uint8_t pin, bool state) {
|
||||
//Onboard red LED is wired a bit differently
|
||||
if(pin != RED_LED) {
|
||||
digitalWrite(pin, state?LOW:HIGH);
|
||||
} else {
|
||||
digitalWrite(pin, state?HIGH:LOW);
|
||||
}
|
||||
}
|
||||
|
||||
void set_touch_pins(uint16_t value)
|
||||
{
|
||||
for(int pin=0; pin<12; ++pin)
|
||||
{
|
||||
uint16_t touched = (value >> pin) & 0x0001; //Mask out bit value of pin
|
||||
int teensyPin = 11-pin; //Row of teensy pins is 0-11 but mirrored vs MPR121
|
||||
|
||||
if(touched) {
|
||||
pinMode(teensyPin, INPUT_PULLDOWN);
|
||||
} else {
|
||||
pinMode(teensyPin, INPUT_PULLUP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool run_test(const char* name, uint16_t value) {
|
||||
Serial.print(name);
|
||||
set_touch_pins(value);
|
||||
led(YELLOW_LED, true);
|
||||
delay(50);
|
||||
led(YELLOW_LED, false);
|
||||
delay(50);
|
||||
uint16_t t = touchSensor.touched();
|
||||
Serial.print(", expected: ");
|
||||
Serial.print(value, HEX);
|
||||
Serial.print(" got: ");
|
||||
Serial.print(t, HEX);
|
||||
|
||||
if(value == t) {
|
||||
Serial.println(" PASS");
|
||||
return true;
|
||||
} else {
|
||||
Serial.println(" FAIL");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void failure() {
|
||||
led(RED_LED, true);
|
||||
led(GREEN_LED, false);
|
||||
Serial.println("Test failed!");
|
||||
}
|
||||
|
||||
void success() {
|
||||
led(RED_LED, false);
|
||||
led(GREEN_LED, true);
|
||||
Serial.println("All tests succeeded!");
|
||||
}
|
||||
|
||||
//Macro to bail out on any failure
|
||||
#define TEST(x) if(!x) { failure(); return; }
|
||||
|
||||
void run_all(void) {
|
||||
|
||||
TEST(run_test("ALL_OFF", 0x000));
|
||||
TEST(run_test("ALL_ON", 0xFFF));
|
||||
|
||||
//Pins one at a time
|
||||
TEST(run_test("P0", 0x001 << 0));
|
||||
TEST(run_test("P1", 0x001 << 1));
|
||||
TEST(run_test("P2", 0x001 << 2));
|
||||
TEST(run_test("P3", 0x001 << 3));
|
||||
TEST(run_test("P4", 0x001 << 4));
|
||||
TEST(run_test("P5", 0x001 << 5));
|
||||
TEST(run_test("P6", 0x001 << 6));
|
||||
TEST(run_test("P7", 0x001 << 7));
|
||||
TEST(run_test("P8", 0x001 << 8));
|
||||
TEST(run_test("P9", 0x001 << 9));
|
||||
TEST(run_test("P10", 0x001 << 10));
|
||||
TEST(run_test("P11", 0x001 << 11));
|
||||
|
||||
//Alternating pattern
|
||||
TEST(run_test("ODD", 0x0555));
|
||||
TEST(run_test("EVEN", 0x0AAA));
|
||||
|
||||
//A few random ones for good measure
|
||||
for(int i=0; i<8; i++) {
|
||||
TEST(run_test("RANDOM", random() % 0x1000));
|
||||
}
|
||||
|
||||
success();
|
||||
}
|
||||
|
||||
//Dummy loop does nothing
|
||||
void loop() {
|
||||
delay(100);
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,35 +1,35 @@
|
|||
w=8; //key width, default 8
|
||||
wc=10; //mounting end outer diameter, default 10
|
||||
l=15; //key length (range normally increase in steps of 5)
|
||||
hght=3; //key height, default 3,3.5 and 4
|
||||
angl=25; //key end angle, default 25
|
||||
estp=1.5; //end step before angle, default 0.5
|
||||
noext=0; //set to 1 to get just the round part
|
||||
|
||||
// 20/3,26/3.5,32/4 sk: 15/3 (estp 1.5)
|
||||
|
||||
module prism(l, w, h){
|
||||
polyhedron(
|
||||
points=[[0,0,0], [l,0,0], [l,w,0], [0,w,0], [0,w,h], [l,w,h]],
|
||||
faces=[[0,1,2,3],[5,4,3,2],[0,4,5,1],[0,3,4],[5,2,1]]
|
||||
);
|
||||
}
|
||||
|
||||
difference(){
|
||||
translate([0,0,0]) cylinder(h=hght,r=wc/2,,$fn=100);
|
||||
translate([0,0,hght-2]) cylinder(h=2.2,r1=1.6,r2=3.2,$fn=100);
|
||||
translate([0,0,-1]) cylinder(h=hght+5,r=1.6,$fn=100);
|
||||
//translate([-8,-8,0]) cube([16,2,3]);
|
||||
|
||||
}
|
||||
if (!noext){
|
||||
difference(){
|
||||
translate([-w/2,-l+1,0]) cube([w,l,hght]);
|
||||
translate([0,0,hght-2]) cylinder(h=2.2,r1=1.6,r2=3.2,$fn=100);
|
||||
translate([0,0,-1]) cylinder(h=hght+5,r=1.6,$fn=100);
|
||||
translate([w/2-1,-l,hght]) rotate([180,0,90]) prism(l,1,1);
|
||||
translate([-w/2-0.001,-l,hght-1]) rotate([90,0,90]) prism(l,1,1);
|
||||
//translate([-w/2,-l+5.5,hght]) rotate([160,0,0])prism(w,15,15);
|
||||
translate([-w/2,-l,estp]) rotate([angl,0,0])cube(40,40,40);
|
||||
}
|
||||
}
|
||||
w=8; //key width, default 8
|
||||
wc=10; //mounting end outer diameter, default 10
|
||||
l=15; //key length (range normally increase in steps of 5)
|
||||
hght=3; //key height, default 3,3.5 and 4
|
||||
angl=25; //key end angle, default 25
|
||||
estp=1.5; //end step before angle, default 0.5
|
||||
noext=0; //set to 1 to get just the round part
|
||||
|
||||
// 20/3,26/3.5,32/4 sk: 15/3 (estp 1.5)
|
||||
|
||||
module prism(l, w, h){
|
||||
polyhedron(
|
||||
points=[[0,0,0], [l,0,0], [l,w,0], [0,w,0], [0,w,h], [l,w,h]],
|
||||
faces=[[0,1,2,3],[5,4,3,2],[0,4,5,1],[0,3,4],[5,2,1]]
|
||||
);
|
||||
}
|
||||
|
||||
difference(){
|
||||
translate([0,0,0]) cylinder(h=hght,r=wc/2,,$fn=100);
|
||||
translate([0,0,hght-2]) cylinder(h=2.2,r1=1.6,r2=3.2,$fn=100);
|
||||
translate([0,0,-1]) cylinder(h=hght+5,r=1.6,$fn=100);
|
||||
//translate([-8,-8,0]) cube([16,2,3]);
|
||||
|
||||
}
|
||||
if (!noext){
|
||||
difference(){
|
||||
translate([-w/2,-l+1,0]) cube([w,l,hght]);
|
||||
translate([0,0,hght-2]) cylinder(h=2.2,r1=1.6,r2=3.2,$fn=100);
|
||||
translate([0,0,-1]) cylinder(h=hght+5,r=1.6,$fn=100);
|
||||
translate([w/2-1,-l,hght]) rotate([180,0,90]) prism(l,1,1);
|
||||
translate([-w/2-0.001,-l,hght-1]) rotate([90,0,90]) prism(l,1,1);
|
||||
//translate([-w/2,-l+5.5,hght]) rotate([160,0,0])prism(w,15,15);
|
||||
translate([-w/2,-l,estp]) rotate([angl,0,0])cube(40,40,40);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,85 +1,85 @@
|
|||
CC=clang
|
||||
CXX=clang++
|
||||
|
||||
CFLAGS=-Wall -Wextra -Wpedantic -Wno-gnu -mmacosx-version-min=10.9 -F/Library/Frameworks
|
||||
CFLAGS += -DARDUINO=10808 -DTEENSYDUINO=146 -D__MK20DX256__ -DUSB_MIDI
|
||||
|
||||
RELEASE ?= 0
|
||||
ifeq ($(RELEASE), 1)
|
||||
CFLAGS +=-O3
|
||||
else
|
||||
CFLAGS += -O0 -g
|
||||
endif
|
||||
|
||||
|
||||
CXXFLAGS= $(CFLAGS) -std=c++14
|
||||
|
||||
LIBS=-framework SDL2 -lc++ -lc -framework OpenGL
|
||||
LDFLAGS=-macosx_version_min 10.9 -rpath @executable_path/../Frameworks
|
||||
|
||||
SYSINC = ./include
|
||||
INCS = ../NuEVI ./include ./imgui ./gl3w
|
||||
|
||||
INCDIRS = $(addprefix -isystem ,$(SYSINC))
|
||||
INCDIRS += $(addprefix -I,$(INCS))
|
||||
|
||||
|
||||
TARGET=nuevisim
|
||||
|
||||
CXXFILES= ../NuEVI/menu.cpp \
|
||||
../NuEVI/adjustmenu.cpp \
|
||||
../NuEVI/midi.cpp \
|
||||
../NuEVI/settings.cpp \
|
||||
../NuEVI/led.cpp \
|
||||
src/nuevisim.cpp \
|
||||
src/simeeprom.cpp \
|
||||
src/Print.cpp \
|
||||
src/simserial.cpp \
|
||||
src/simwire.cpp \
|
||||
src/simusbmidi.cpp \
|
||||
src/filters.cpp \
|
||||
src/Adafruit_GFX_sim.cpp \
|
||||
src/Adafruit_SSD1306_sim.cpp \
|
||||
src/Adafruit_MPR121_sim.cpp \
|
||||
imgui/imgui.cpp \
|
||||
imgui/imgui_draw.cpp \
|
||||
imgui/imgui_widgets.cpp \
|
||||
imgui/examples/imgui_impl_sdl.cpp \
|
||||
imgui/examples/imgui_impl_opengl3.cpp
|
||||
|
||||
|
||||
CFILES= gl3w/gl3w.c
|
||||
|
||||
OBJS=$(CXXFILES:.cpp=.o) $(CFILES:.c=.o)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
nuevisim: $(OBJS)
|
||||
$(LD) $(LDFLAGS) -o $(TARGET) $(LIBS) $^
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(INCDIRS) -c -o $@ $<
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CXXFLAGS) $(INCDIRS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET) $(OBJS) *.o
|
||||
|
||||
.PHONY: all
|
||||
|
||||
|
||||
# Dependecies
|
||||
DEPS=make.deps
|
||||
|
||||
.PHONY: deps mrproper
|
||||
mrproper: clean
|
||||
rm $(DEPS)
|
||||
deps: $(DEPS)
|
||||
|
||||
H_DEPS=$(wildcard src/*.h) $(wildcard ../NuEVI/*.h)
|
||||
|
||||
make.deps: $(CXXFILES) $(H_DEPS)
|
||||
$(CXX) $(CXXFLAGS) -Wno-deprecated $(INCDIRS) -MM $(DEPS_HS) $^ > $@
|
||||
|
||||
-include .deps/*
|
||||
CC=clang
|
||||
CXX=clang++
|
||||
|
||||
CFLAGS=-Wall -Wextra -Wpedantic -Wno-gnu -mmacosx-version-min=10.9 -F/Library/Frameworks
|
||||
CFLAGS += -DARDUINO=10808 -DTEENSYDUINO=146 -D__MK20DX256__ -DUSB_MIDI
|
||||
|
||||
RELEASE ?= 0
|
||||
ifeq ($(RELEASE), 1)
|
||||
CFLAGS +=-O3
|
||||
else
|
||||
CFLAGS += -O0 -g
|
||||
endif
|
||||
|
||||
|
||||
CXXFLAGS= $(CFLAGS) -std=c++14
|
||||
|
||||
LIBS=-framework SDL2 -lc++ -lc -framework OpenGL
|
||||
LDFLAGS=-macosx_version_min 10.9 -rpath @executable_path/../Frameworks
|
||||
|
||||
SYSINC = ./include
|
||||
INCS = ../NuEVI ./include ./imgui ./gl3w
|
||||
|
||||
INCDIRS = $(addprefix -isystem ,$(SYSINC))
|
||||
INCDIRS += $(addprefix -I,$(INCS))
|
||||
|
||||
|
||||
TARGET=nuevisim
|
||||
|
||||
CXXFILES= ../NuEVI/menu.cpp \
|
||||
../NuEVI/adjustmenu.cpp \
|
||||
../NuEVI/midi.cpp \
|
||||
../NuEVI/settings.cpp \
|
||||
../NuEVI/led.cpp \
|
||||
src/nuevisim.cpp \
|
||||
src/simeeprom.cpp \
|
||||
src/Print.cpp \
|
||||
src/simserial.cpp \
|
||||
src/simwire.cpp \
|
||||
src/simusbmidi.cpp \
|
||||
src/filters.cpp \
|
||||
src/Adafruit_GFX_sim.cpp \
|
||||
src/Adafruit_SSD1306_sim.cpp \
|
||||
src/Adafruit_MPR121_sim.cpp \
|
||||
imgui/imgui.cpp \
|
||||
imgui/imgui_draw.cpp \
|
||||
imgui/imgui_widgets.cpp \
|
||||
imgui/examples/imgui_impl_sdl.cpp \
|
||||
imgui/examples/imgui_impl_opengl3.cpp
|
||||
|
||||
|
||||
CFILES= gl3w/gl3w.c
|
||||
|
||||
OBJS=$(CXXFILES:.cpp=.o) $(CFILES:.c=.o)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
nuevisim: $(OBJS)
|
||||
$(LD) $(LDFLAGS) -o $(TARGET) $(LIBS) $^
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(INCDIRS) -c -o $@ $<
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CXXFLAGS) $(INCDIRS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET) $(OBJS) *.o
|
||||
|
||||
.PHONY: all
|
||||
|
||||
|
||||
# Dependecies
|
||||
DEPS=make.deps
|
||||
|
||||
.PHONY: deps mrproper
|
||||
mrproper: clean
|
||||
rm $(DEPS)
|
||||
deps: $(DEPS)
|
||||
|
||||
H_DEPS=$(wildcard src/*.h) $(wildcard ../NuEVI/*.h)
|
||||
|
||||
make.deps: $(CXXFILES) $(H_DEPS)
|
||||
$(CXX) $(CXXFLAGS) -Wno-deprecated $(INCDIRS) -MM $(DEPS_HS) $^ > $@
|
||||
|
||||
-include .deps/*
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,233 +1,233 @@
|
|||
#ifndef _ADAFRUIT_GFX_H
|
||||
#define _ADAFRUIT_GFX_H
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#include "Print.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
#include "gfxfont.h"
|
||||
|
||||
/// A generic graphics superclass that can handle all sorts of drawing. At a minimum you can subclass and provide drawPixel(). At a maximum you can do a ton of overriding to optimize. Used for any/all Adafruit displays!
|
||||
class Adafruit_GFX : public Print {
|
||||
|
||||
public: // Exposed simulation variables...
|
||||
bool dimmed_;
|
||||
bool enabled_;
|
||||
bool inverted_;
|
||||
bool dirty_;
|
||||
|
||||
public:
|
||||
|
||||
Adafruit_GFX(int16_t w, int16_t h); // Constructor
|
||||
|
||||
// This MUST be defined by the subclass:
|
||||
virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0; ///< Virtual drawPixel() function to draw to the screen/framebuffer/etc, must be overridden in subclass. @param x X coordinate. @param y Y coordinate. @param color 16-bit pixel color.
|
||||
|
||||
// TRANSACTION API / CORE DRAW API
|
||||
// These MAY be overridden by the subclass to provide device-specific
|
||||
// optimized code. Otherwise 'generic' versions are used.
|
||||
virtual void startWrite(void);
|
||||
virtual void writePixel(int16_t x, int16_t y, uint16_t color);
|
||||
virtual void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||||
virtual void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
|
||||
virtual void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||
virtual void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
|
||||
virtual void endWrite(void);
|
||||
|
||||
// CONTROL API
|
||||
// These MAY be overridden by the subclass to provide device-specific
|
||||
// optimized code. Otherwise 'generic' versions are used.
|
||||
virtual void setRotation(uint8_t r);
|
||||
virtual void invertDisplay(boolean i);
|
||||
|
||||
// BASIC DRAW API
|
||||
// These MAY be overridden by the subclass to provide device-specific
|
||||
// optimized code. Otherwise 'generic' versions are used.
|
||||
virtual void
|
||||
// It's good to implement those, even if using transaction API
|
||||
drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color),
|
||||
drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color),
|
||||
fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color),
|
||||
fillScreen(uint16_t color),
|
||||
// Optional and probably not necessary to change
|
||||
drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color),
|
||||
drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||||
|
||||
// These exist only with Adafruit_GFX (no subclass overrides)
|
||||
void
|
||||
drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color),
|
||||
drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
|
||||
uint16_t color),
|
||||
fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color),
|
||||
fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
|
||||
int16_t delta, uint16_t color),
|
||||
drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
|
||||
int16_t x2, int16_t y2, uint16_t color),
|
||||
fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
|
||||
int16_t x2, int16_t y2, uint16_t color),
|
||||
drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
|
||||
int16_t radius, uint16_t color),
|
||||
fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
|
||||
int16_t radius, uint16_t color),
|
||||
drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
|
||||
int16_t w, int16_t h, uint16_t color),
|
||||
drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
|
||||
int16_t w, int16_t h, uint16_t color, uint16_t bg),
|
||||
drawBitmap(int16_t x, int16_t y, uint8_t *bitmap,
|
||||
int16_t w, int16_t h, uint16_t color),
|
||||
drawBitmap(int16_t x, int16_t y, uint8_t *bitmap,
|
||||
int16_t w, int16_t h, uint16_t color, uint16_t bg),
|
||||
drawXBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
|
||||
int16_t w, int16_t h, uint16_t color),
|
||||
drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
|
||||
int16_t w, int16_t h),
|
||||
drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap,
|
||||
int16_t w, int16_t h),
|
||||
drawGrayscaleBitmap(int16_t x, int16_t y,
|
||||
const uint8_t bitmap[], const uint8_t mask[],
|
||||
int16_t w, int16_t h),
|
||||
drawGrayscaleBitmap(int16_t x, int16_t y,
|
||||
uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h),
|
||||
drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[],
|
||||
int16_t w, int16_t h),
|
||||
drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap,
|
||||
int16_t w, int16_t h),
|
||||
drawRGBBitmap(int16_t x, int16_t y,
|
||||
const uint16_t bitmap[], const uint8_t mask[],
|
||||
int16_t w, int16_t h),
|
||||
drawRGBBitmap(int16_t x, int16_t y,
|
||||
uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h),
|
||||
drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color,
|
||||
uint16_t bg, uint8_t size),
|
||||
setCursor(int16_t x, int16_t y),
|
||||
setTextColor(uint16_t c),
|
||||
setTextColor(uint16_t c, uint16_t bg),
|
||||
setTextSize(uint8_t s),
|
||||
setTextWrap(boolean w),
|
||||
cp437(boolean x=true),
|
||||
setFont(const GFXfont *f = NULL),
|
||||
getTextBounds(const char *string, int16_t x, int16_t y,
|
||||
int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h),
|
||||
getTextBounds(const __FlashStringHelper *s, int16_t x, int16_t y,
|
||||
int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h),
|
||||
getTextBounds(const String &str, int16_t x, int16_t y,
|
||||
int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h);
|
||||
|
||||
|
||||
#if ARDUINO >= 100
|
||||
virtual size_t write(uint8_t);
|
||||
#else
|
||||
virtual void write(uint8_t);
|
||||
#endif
|
||||
|
||||
int16_t height(void) const;
|
||||
int16_t width(void) const;
|
||||
|
||||
uint8_t getRotation(void) const;
|
||||
|
||||
// get current cursor position (get rotation safe maximum values, using: width() for x, height() for y)
|
||||
int16_t getCursorX(void) const;
|
||||
int16_t getCursorY(void) const;
|
||||
|
||||
protected:
|
||||
void
|
||||
charBounds(char c, int16_t *x, int16_t *y,
|
||||
int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy);
|
||||
const int16_t
|
||||
WIDTH, ///< This is the 'raw' display width - never changes
|
||||
HEIGHT; ///< This is the 'raw' display height - never changes
|
||||
int16_t
|
||||
_width, ///< Display width as modified by current rotation
|
||||
_height, ///< Display height as modified by current rotation
|
||||
cursor_x, ///< x location to start print()ing text
|
||||
cursor_y; ///< y location to start print()ing text
|
||||
uint16_t
|
||||
textcolor, ///< 16-bit background color for print()
|
||||
textbgcolor; ///< 16-bit text color for print()
|
||||
uint8_t
|
||||
textsize, ///< Desired magnification of text to print()
|
||||
rotation; ///< Display rotation (0 thru 3)
|
||||
boolean
|
||||
wrap, ///< If set, 'wrap' text at right edge of display
|
||||
_cp437; ///< If set, use correct CP437 charset (default is off)
|
||||
GFXfont
|
||||
*gfxFont; ///< Pointer to special font
|
||||
};
|
||||
|
||||
|
||||
/// A simple drawn button UI element
|
||||
class Adafruit_GFX_Button {
|
||||
|
||||
public:
|
||||
Adafruit_GFX_Button(void);
|
||||
// "Classic" initButton() uses center & size
|
||||
void initButton(Adafruit_GFX *gfx, int16_t x, int16_t y,
|
||||
uint16_t w, uint16_t h, uint16_t outline, uint16_t fill,
|
||||
uint16_t textcolor, char *label, uint8_t textsize);
|
||||
// New/alt initButton() uses upper-left corner & size
|
||||
void initButtonUL(Adafruit_GFX *gfx, int16_t x1, int16_t y1,
|
||||
uint16_t w, uint16_t h, uint16_t outline, uint16_t fill,
|
||||
uint16_t textcolor, char *label, uint8_t textsize);
|
||||
void drawButton(boolean inverted = false);
|
||||
boolean contains(int16_t x, int16_t y);
|
||||
|
||||
void press(boolean p);
|
||||
boolean isPressed();
|
||||
boolean justPressed();
|
||||
boolean justReleased();
|
||||
|
||||
private:
|
||||
Adafruit_GFX *_gfx;
|
||||
int16_t _x1, _y1; // Coordinates of top-left corner
|
||||
uint16_t _w, _h;
|
||||
uint8_t _textsize;
|
||||
uint16_t _outlinecolor, _fillcolor, _textcolor;
|
||||
char _label[10];
|
||||
|
||||
boolean currstate, laststate;
|
||||
};
|
||||
|
||||
|
||||
/// A GFX 1-bit canvas context for graphics
|
||||
class GFXcanvas1 : public Adafruit_GFX {
|
||||
public:
|
||||
GFXcanvas1(uint16_t w, uint16_t h);
|
||||
~GFXcanvas1(void);
|
||||
void drawPixel(int16_t x, int16_t y, uint16_t color),
|
||||
fillScreen(uint16_t color);
|
||||
uint8_t *getBuffer(void);
|
||||
private:
|
||||
uint8_t *buffer;
|
||||
};
|
||||
|
||||
|
||||
/// A GFX 8-bit canvas context for graphics
|
||||
class GFXcanvas8 : public Adafruit_GFX {
|
||||
public:
|
||||
GFXcanvas8(uint16_t w, uint16_t h);
|
||||
~GFXcanvas8(void);
|
||||
void drawPixel(int16_t x, int16_t y, uint16_t color),
|
||||
fillScreen(uint16_t color),
|
||||
writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||
|
||||
uint8_t *getBuffer(void);
|
||||
private:
|
||||
uint8_t *buffer;
|
||||
};
|
||||
|
||||
|
||||
/// A GFX 16-bit canvas context for graphics
|
||||
class GFXcanvas16 : public Adafruit_GFX {
|
||||
public:
|
||||
GFXcanvas16(uint16_t w, uint16_t h);
|
||||
~GFXcanvas16(void);
|
||||
void drawPixel(int16_t x, int16_t y, uint16_t color),
|
||||
fillScreen(uint16_t color);
|
||||
uint16_t *getBuffer(void);
|
||||
private:
|
||||
uint16_t *buffer;
|
||||
};
|
||||
|
||||
#endif // _ADAFRUIT_GFX_H
|
||||
#ifndef _ADAFRUIT_GFX_H
|
||||
#define _ADAFRUIT_GFX_H
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#include "Print.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
#include "gfxfont.h"
|
||||
|
||||
/// A generic graphics superclass that can handle all sorts of drawing. At a minimum you can subclass and provide drawPixel(). At a maximum you can do a ton of overriding to optimize. Used for any/all Adafruit displays!
|
||||
class Adafruit_GFX : public Print {
|
||||
|
||||
public: // Exposed simulation variables...
|
||||
bool dimmed_;
|
||||
bool enabled_;
|
||||
bool inverted_;
|
||||
bool dirty_;
|
||||
|
||||
public:
|
||||
|
||||
Adafruit_GFX(int16_t w, int16_t h); // Constructor
|
||||
|
||||
// This MUST be defined by the subclass:
|
||||
virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0; ///< Virtual drawPixel() function to draw to the screen/framebuffer/etc, must be overridden in subclass. @param x X coordinate. @param y Y coordinate. @param color 16-bit pixel color.
|
||||
|
||||
// TRANSACTION API / CORE DRAW API
|
||||
// These MAY be overridden by the subclass to provide device-specific
|
||||
// optimized code. Otherwise 'generic' versions are used.
|
||||
virtual void startWrite(void);
|
||||
virtual void writePixel(int16_t x, int16_t y, uint16_t color);
|
||||
virtual void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||||
virtual void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
|
||||
virtual void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||
virtual void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
|
||||
virtual void endWrite(void);
|
||||
|
||||
// CONTROL API
|
||||
// These MAY be overridden by the subclass to provide device-specific
|
||||
// optimized code. Otherwise 'generic' versions are used.
|
||||
virtual void setRotation(uint8_t r);
|
||||
virtual void invertDisplay(boolean i);
|
||||
|
||||
// BASIC DRAW API
|
||||
// These MAY be overridden by the subclass to provide device-specific
|
||||
// optimized code. Otherwise 'generic' versions are used.
|
||||
virtual void
|
||||
// It's good to implement those, even if using transaction API
|
||||
drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color),
|
||||
drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color),
|
||||
fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color),
|
||||
fillScreen(uint16_t color),
|
||||
// Optional and probably not necessary to change
|
||||
drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color),
|
||||
drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||||
|
||||
// These exist only with Adafruit_GFX (no subclass overrides)
|
||||
void
|
||||
drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color),
|
||||
drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
|
||||
uint16_t color),
|
||||
fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color),
|
||||
fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
|
||||
int16_t delta, uint16_t color),
|
||||
drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
|
||||
int16_t x2, int16_t y2, uint16_t color),
|
||||
fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
|
||||
int16_t x2, int16_t y2, uint16_t color),
|
||||
drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
|
||||
int16_t radius, uint16_t color),
|
||||
fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
|
||||
int16_t radius, uint16_t color),
|
||||
drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
|
||||
int16_t w, int16_t h, uint16_t color),
|
||||
drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
|
||||
int16_t w, int16_t h, uint16_t color, uint16_t bg),
|
||||
drawBitmap(int16_t x, int16_t y, uint8_t *bitmap,
|
||||
int16_t w, int16_t h, uint16_t color),
|
||||
drawBitmap(int16_t x, int16_t y, uint8_t *bitmap,
|
||||
int16_t w, int16_t h, uint16_t color, uint16_t bg),
|
||||
drawXBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
|
||||
int16_t w, int16_t h, uint16_t color),
|
||||
drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
|
||||
int16_t w, int16_t h),
|
||||
drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap,
|
||||
int16_t w, int16_t h),
|
||||
drawGrayscaleBitmap(int16_t x, int16_t y,
|
||||
const uint8_t bitmap[], const uint8_t mask[],
|
||||
int16_t w, int16_t h),
|
||||
drawGrayscaleBitmap(int16_t x, int16_t y,
|
||||
uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h),
|
||||
drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[],
|
||||
int16_t w, int16_t h),
|
||||
drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap,
|
||||
int16_t w, int16_t h),
|
||||
drawRGBBitmap(int16_t x, int16_t y,
|
||||
const uint16_t bitmap[], const uint8_t mask[],
|
||||
int16_t w, int16_t h),
|
||||
drawRGBBitmap(int16_t x, int16_t y,
|
||||
uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h),
|
||||
drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color,
|
||||
uint16_t bg, uint8_t size),
|
||||
setCursor(int16_t x, int16_t y),
|
||||
setTextColor(uint16_t c),
|
||||
setTextColor(uint16_t c, uint16_t bg),
|
||||
setTextSize(uint8_t s),
|
||||
setTextWrap(boolean w),
|
||||
cp437(boolean x=true),
|
||||
setFont(const GFXfont *f = NULL),
|
||||
getTextBounds(const char *string, int16_t x, int16_t y,
|
||||
int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h),
|
||||
getTextBounds(const __FlashStringHelper *s, int16_t x, int16_t y,
|
||||
int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h),
|
||||
getTextBounds(const String &str, int16_t x, int16_t y,
|
||||
int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h);
|
||||
|
||||
|
||||
#if ARDUINO >= 100
|
||||
virtual size_t write(uint8_t);
|
||||
#else
|
||||
virtual void write(uint8_t);
|
||||
#endif
|
||||
|
||||
int16_t height(void) const;
|
||||
int16_t width(void) const;
|
||||
|
||||
uint8_t getRotation(void) const;
|
||||
|
||||
// get current cursor position (get rotation safe maximum values, using: width() for x, height() for y)
|
||||
int16_t getCursorX(void) const;
|
||||
int16_t getCursorY(void) const;
|
||||
|
||||
protected:
|
||||
void
|
||||
charBounds(char c, int16_t *x, int16_t *y,
|
||||
int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy);
|
||||
const int16_t
|
||||
WIDTH, ///< This is the 'raw' display width - never changes
|
||||
HEIGHT; ///< This is the 'raw' display height - never changes
|
||||
int16_t
|
||||
_width, ///< Display width as modified by current rotation
|
||||
_height, ///< Display height as modified by current rotation
|
||||
cursor_x, ///< x location to start print()ing text
|
||||
cursor_y; ///< y location to start print()ing text
|
||||
uint16_t
|
||||
textcolor, ///< 16-bit background color for print()
|
||||
textbgcolor; ///< 16-bit text color for print()
|
||||
uint8_t
|
||||
textsize, ///< Desired magnification of text to print()
|
||||
rotation; ///< Display rotation (0 thru 3)
|
||||
boolean
|
||||
wrap, ///< If set, 'wrap' text at right edge of display
|
||||
_cp437; ///< If set, use correct CP437 charset (default is off)
|
||||
GFXfont
|
||||
*gfxFont; ///< Pointer to special font
|
||||
};
|
||||
|
||||
|
||||
/// A simple drawn button UI element
|
||||
class Adafruit_GFX_Button {
|
||||
|
||||
public:
|
||||
Adafruit_GFX_Button(void);
|
||||
// "Classic" initButton() uses center & size
|
||||
void initButton(Adafruit_GFX *gfx, int16_t x, int16_t y,
|
||||
uint16_t w, uint16_t h, uint16_t outline, uint16_t fill,
|
||||
uint16_t textcolor, char *label, uint8_t textsize);
|
||||
// New/alt initButton() uses upper-left corner & size
|
||||
void initButtonUL(Adafruit_GFX *gfx, int16_t x1, int16_t y1,
|
||||
uint16_t w, uint16_t h, uint16_t outline, uint16_t fill,
|
||||
uint16_t textcolor, char *label, uint8_t textsize);
|
||||
void drawButton(boolean inverted = false);
|
||||
boolean contains(int16_t x, int16_t y);
|
||||
|
||||
void press(boolean p);
|
||||
boolean isPressed();
|
||||
boolean justPressed();
|
||||
boolean justReleased();
|
||||
|
||||
private:
|
||||
Adafruit_GFX *_gfx;
|
||||
int16_t _x1, _y1; // Coordinates of top-left corner
|
||||
uint16_t _w, _h;
|
||||
uint8_t _textsize;
|
||||
uint16_t _outlinecolor, _fillcolor, _textcolor;
|
||||
char _label[10];
|
||||
|
||||
boolean currstate, laststate;
|
||||
};
|
||||
|
||||
|
||||
/// A GFX 1-bit canvas context for graphics
|
||||
class GFXcanvas1 : public Adafruit_GFX {
|
||||
public:
|
||||
GFXcanvas1(uint16_t w, uint16_t h);
|
||||
~GFXcanvas1(void);
|
||||
void drawPixel(int16_t x, int16_t y, uint16_t color),
|
||||
fillScreen(uint16_t color);
|
||||
uint8_t *getBuffer(void);
|
||||
private:
|
||||
uint8_t *buffer;
|
||||
};
|
||||
|
||||
|
||||
/// A GFX 8-bit canvas context for graphics
|
||||
class GFXcanvas8 : public Adafruit_GFX {
|
||||
public:
|
||||
GFXcanvas8(uint16_t w, uint16_t h);
|
||||
~GFXcanvas8(void);
|
||||
void drawPixel(int16_t x, int16_t y, uint16_t color),
|
||||
fillScreen(uint16_t color),
|
||||
writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||
|
||||
uint8_t *getBuffer(void);
|
||||
private:
|
||||
uint8_t *buffer;
|
||||
};
|
||||
|
||||
|
||||
/// A GFX 16-bit canvas context for graphics
|
||||
class GFXcanvas16 : public Adafruit_GFX {
|
||||
public:
|
||||
GFXcanvas16(uint16_t w, uint16_t h);
|
||||
~GFXcanvas16(void);
|
||||
void drawPixel(int16_t x, int16_t y, uint16_t color),
|
||||
fillScreen(uint16_t color);
|
||||
uint16_t *getBuffer(void);
|
||||
private:
|
||||
uint16_t *buffer;
|
||||
};
|
||||
|
||||
#endif // _ADAFRUIT_GFX_H
|
||||
|
|
|
|||
|
|
@ -1,114 +1,114 @@
|
|||
/*!
|
||||
* @file Adafruit_MPR121.h
|
||||
*
|
||||
This is a library for the MPR121 12-Channel Capacitive Sensor
|
||||
|
||||
Designed specifically to work with the MPR121 breakout from Adafruit
|
||||
----> https://www.adafruit.com/products/1982
|
||||
|
||||
These sensors use I2C to communicate, 2+ pins are required to
|
||||
interface
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ADAFRUIT_MPR121_H
|
||||
#define ADAFRUIT_MPR121_H
|
||||
|
||||
// #if (ARDUINO >= 100)
|
||||
#include "Arduino.h"
|
||||
// #else
|
||||
// #include "WProgram.h"
|
||||
// #endif
|
||||
#include <Wire.h>
|
||||
|
||||
// The default I2C address
|
||||
#define MPR121_I2CADDR_DEFAULT 0x5A ///< default I2C address
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Device register map
|
||||
****************************************************************************************/
|
||||
enum {
|
||||
MPR121_TOUCHSTATUS_L = 0x00,
|
||||
MPR121_TOUCHSTATUS_H = 0x01,
|
||||
MPR121_FILTDATA_0L = 0x04,
|
||||
MPR121_FILTDATA_0H = 0x05,
|
||||
MPR121_BASELINE_0 = 0x1E,
|
||||
MPR121_MHDR = 0x2B,
|
||||
MPR121_NHDR = 0x2C,
|
||||
MPR121_NCLR = 0x2D,
|
||||
MPR121_FDLR = 0x2E,
|
||||
MPR121_MHDF = 0x2F,
|
||||
MPR121_NHDF = 0x30,
|
||||
MPR121_NCLF = 0x31,
|
||||
MPR121_FDLF = 0x32,
|
||||
MPR121_NHDT = 0x33,
|
||||
MPR121_NCLT = 0x34,
|
||||
MPR121_FDLT = 0x35,
|
||||
|
||||
MPR121_TOUCHTH_0 = 0x41,
|
||||
MPR121_RELEASETH_0 = 0x42,
|
||||
MPR121_DEBOUNCE = 0x5B,
|
||||
MPR121_CONFIG1 = 0x5C,
|
||||
MPR121_CONFIG2 = 0x5D,
|
||||
MPR121_CHARGECURR_0 = 0x5F,
|
||||
MPR121_CHARGETIME_1 = 0x6C,
|
||||
MPR121_ECR = 0x5E,
|
||||
MPR121_AUTOCONFIG0 = 0x7B,
|
||||
MPR121_AUTOCONFIG1 = 0x7C,
|
||||
MPR121_UPLIMIT = 0x7D,
|
||||
MPR121_LOWLIMIT = 0x7E,
|
||||
MPR121_TARGETLIMIT = 0x7F,
|
||||
|
||||
MPR121_GPIODIR = 0x76,
|
||||
MPR121_GPIOEN = 0x77,
|
||||
MPR121_GPIOSET = 0x78,
|
||||
MPR121_GPIOCLR = 0x79,
|
||||
MPR121_GPIOTOGGLE = 0x7A,
|
||||
|
||||
MPR121_SOFTRESET = 0x80,
|
||||
};
|
||||
|
||||
//.. thru to 0x1C/0x1D
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Class that stores state and functions for interacting with MPR121
|
||||
proximity capacitive touch sensor controller.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class Adafruit_MPR121 {
|
||||
public:
|
||||
// Hardware I2C
|
||||
Adafruit_MPR121(void);
|
||||
|
||||
boolean begin(uint8_t i2caddr = MPR121_I2CADDR_DEFAULT);
|
||||
|
||||
uint16_t filteredData(uint8_t t);
|
||||
uint16_t baselineData(uint8_t t);
|
||||
|
||||
uint8_t readRegister8(uint8_t reg);
|
||||
uint16_t readRegister16(uint8_t reg);
|
||||
void writeRegister(uint8_t reg, uint8_t value);
|
||||
uint16_t touched(void);
|
||||
// Add deprecated attribute so that the compiler shows a warning
|
||||
void setThreshholds(uint8_t touch, uint8_t release) __attribute__((deprecated));
|
||||
void setThresholds(uint8_t touch, uint8_t release);
|
||||
|
||||
uint8_t _registers[48];
|
||||
|
||||
|
||||
// Simulator specific stuff
|
||||
void mockFilteredData(int register, uint16_t value);
|
||||
|
||||
private:
|
||||
int8_t _i2caddr;
|
||||
};
|
||||
|
||||
#endif // ADAFRUIT_MPR121_H
|
||||
/*!
|
||||
* @file Adafruit_MPR121.h
|
||||
*
|
||||
This is a library for the MPR121 12-Channel Capacitive Sensor
|
||||
|
||||
Designed specifically to work with the MPR121 breakout from Adafruit
|
||||
----> https://www.adafruit.com/products/1982
|
||||
|
||||
These sensors use I2C to communicate, 2+ pins are required to
|
||||
interface
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ADAFRUIT_MPR121_H
|
||||
#define ADAFRUIT_MPR121_H
|
||||
|
||||
// #if (ARDUINO >= 100)
|
||||
#include "Arduino.h"
|
||||
// #else
|
||||
// #include "WProgram.h"
|
||||
// #endif
|
||||
#include <Wire.h>
|
||||
|
||||
// The default I2C address
|
||||
#define MPR121_I2CADDR_DEFAULT 0x5A ///< default I2C address
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Device register map
|
||||
****************************************************************************************/
|
||||
enum {
|
||||
MPR121_TOUCHSTATUS_L = 0x00,
|
||||
MPR121_TOUCHSTATUS_H = 0x01,
|
||||
MPR121_FILTDATA_0L = 0x04,
|
||||
MPR121_FILTDATA_0H = 0x05,
|
||||
MPR121_BASELINE_0 = 0x1E,
|
||||
MPR121_MHDR = 0x2B,
|
||||
MPR121_NHDR = 0x2C,
|
||||
MPR121_NCLR = 0x2D,
|
||||
MPR121_FDLR = 0x2E,
|
||||
MPR121_MHDF = 0x2F,
|
||||
MPR121_NHDF = 0x30,
|
||||
MPR121_NCLF = 0x31,
|
||||
MPR121_FDLF = 0x32,
|
||||
MPR121_NHDT = 0x33,
|
||||
MPR121_NCLT = 0x34,
|
||||
MPR121_FDLT = 0x35,
|
||||
|
||||
MPR121_TOUCHTH_0 = 0x41,
|
||||
MPR121_RELEASETH_0 = 0x42,
|
||||
MPR121_DEBOUNCE = 0x5B,
|
||||
MPR121_CONFIG1 = 0x5C,
|
||||
MPR121_CONFIG2 = 0x5D,
|
||||
MPR121_CHARGECURR_0 = 0x5F,
|
||||
MPR121_CHARGETIME_1 = 0x6C,
|
||||
MPR121_ECR = 0x5E,
|
||||
MPR121_AUTOCONFIG0 = 0x7B,
|
||||
MPR121_AUTOCONFIG1 = 0x7C,
|
||||
MPR121_UPLIMIT = 0x7D,
|
||||
MPR121_LOWLIMIT = 0x7E,
|
||||
MPR121_TARGETLIMIT = 0x7F,
|
||||
|
||||
MPR121_GPIODIR = 0x76,
|
||||
MPR121_GPIOEN = 0x77,
|
||||
MPR121_GPIOSET = 0x78,
|
||||
MPR121_GPIOCLR = 0x79,
|
||||
MPR121_GPIOTOGGLE = 0x7A,
|
||||
|
||||
MPR121_SOFTRESET = 0x80,
|
||||
};
|
||||
|
||||
//.. thru to 0x1C/0x1D
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Class that stores state and functions for interacting with MPR121
|
||||
proximity capacitive touch sensor controller.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class Adafruit_MPR121 {
|
||||
public:
|
||||
// Hardware I2C
|
||||
Adafruit_MPR121(void);
|
||||
|
||||
boolean begin(uint8_t i2caddr = MPR121_I2CADDR_DEFAULT);
|
||||
|
||||
uint16_t filteredData(uint8_t t);
|
||||
uint16_t baselineData(uint8_t t);
|
||||
|
||||
uint8_t readRegister8(uint8_t reg);
|
||||
uint16_t readRegister16(uint8_t reg);
|
||||
void writeRegister(uint8_t reg, uint8_t value);
|
||||
uint16_t touched(void);
|
||||
// Add deprecated attribute so that the compiler shows a warning
|
||||
void setThreshholds(uint8_t touch, uint8_t release) __attribute__((deprecated));
|
||||
void setThresholds(uint8_t touch, uint8_t release);
|
||||
|
||||
uint8_t _registers[48];
|
||||
|
||||
|
||||
// Simulator specific stuff
|
||||
void mockFilteredData(int register, uint16_t value);
|
||||
|
||||
private:
|
||||
int8_t _i2caddr;
|
||||
};
|
||||
|
||||
#endif // ADAFRUIT_MPR121_H
|
||||
|
|
|
|||
|
|
@ -1,169 +1,169 @@
|
|||
/*!
|
||||
* @file Adafruit_SSD1306.h
|
||||
*
|
||||
* This is part of for Adafruit's SSD1306 library for monochrome
|
||||
* OLED displays: http://www.adafruit.com/category/63_98
|
||||
*
|
||||
* These displays use I2C or SPI to communicate. I2C requires 2 pins
|
||||
* (SCL+SDA) and optionally a RESET pin. SPI requires 4 pins (MOSI, SCK,
|
||||
* select, data/command) and optionally a reset pin. Hardware SPI or
|
||||
* 'bitbang' software SPI are both supported.
|
||||
*
|
||||
* Adafruit invests time and resources providing this open source code,
|
||||
* please support Adafruit and open-source hardware by purchasing
|
||||
* products from Adafruit!
|
||||
*
|
||||
* Written by Limor Fried/Ladyada for Adafruit Industries, with
|
||||
* contributions from the open source community.
|
||||
*
|
||||
* BSD license, all text above, and the splash screen header file,
|
||||
* must be included in any redistribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _Adafruit_SSD1306_H_
|
||||
#define _Adafruit_SSD1306_H_
|
||||
|
||||
#include <Wire.h>
|
||||
|
||||
#include <Adafruit_GFX.h>
|
||||
|
||||
typedef void* SPIClass;
|
||||
|
||||
// #if defined(__AVR__)
|
||||
// typedef volatile uint8_t PortReg;
|
||||
// typedef uint8_t PortMask;
|
||||
// #define HAVE_PORTREG
|
||||
// #elif defined(__SAM3X8E__)
|
||||
// typedef volatile RwReg PortReg;
|
||||
// typedef uint32_t PortMask;
|
||||
// #define HAVE_PORTREG
|
||||
// #elif defined(__arm__) || defined(ARDUINO_FEATHER52)
|
||||
// typedef volatile uint32_t PortReg;
|
||||
// typedef uint32_t PortMask;
|
||||
// #define HAVE_PORTREG
|
||||
// #endif
|
||||
|
||||
#define BLACK 0 ///< Draw 'off' pixels
|
||||
#define WHITE 1 ///< Draw 'on' pixels
|
||||
#define INVERSE 2 ///< Invert pixels
|
||||
|
||||
#define SSD1306_MEMORYMODE 0x20 ///< See datasheet
|
||||
#define SSD1306_COLUMNADDR 0x21 ///< See datasheet
|
||||
#define SSD1306_PAGEADDR 0x22 ///< See datasheet
|
||||
#define SSD1306_SETCONTRAST 0x81 ///< See datasheet
|
||||
#define SSD1306_CHARGEPUMP 0x8D ///< See datasheet
|
||||
#define SSD1306_SEGREMAP 0xA0 ///< See datasheet
|
||||
#define SSD1306_DISPLAYALLON_RESUME 0xA4 ///< See datasheet
|
||||
#define SSD1306_DISPLAYALLON 0xA5 ///< Not currently used
|
||||
#define SSD1306_NORMALDISPLAY 0xA6 ///< See datasheet
|
||||
#define SSD1306_INVERTDISPLAY 0xA7 ///< See datasheet
|
||||
#define SSD1306_SETMULTIPLEX 0xA8 ///< See datasheet
|
||||
#define SSD1306_DISPLAYOFF 0xAE ///< See datasheet
|
||||
#define SSD1306_DISPLAYON 0xAF ///< See datasheet
|
||||
#define SSD1306_COMSCANINC 0xC0 ///< Not currently used
|
||||
#define SSD1306_COMSCANDEC 0xC8 ///< See datasheet
|
||||
#define SSD1306_SETDISPLAYOFFSET 0xD3 ///< See datasheet
|
||||
#define SSD1306_SETDISPLAYCLOCKDIV 0xD5 ///< See datasheet
|
||||
#define SSD1306_SETPRECHARGE 0xD9 ///< See datasheet
|
||||
#define SSD1306_SETCOMPINS 0xDA ///< See datasheet
|
||||
#define SSD1306_SETVCOMDETECT 0xDB ///< See datasheet
|
||||
|
||||
#define SSD1306_SETLOWCOLUMN 0x00 ///< Not currently used
|
||||
#define SSD1306_SETHIGHCOLUMN 0x10 ///< Not currently used
|
||||
#define SSD1306_SETSTARTLINE 0x40 ///< See datasheet
|
||||
|
||||
#define SSD1306_EXTERNALVCC 0x01 ///< External display voltage source
|
||||
#define SSD1306_SWITCHCAPVCC 0x02 ///< Gen. display voltage from 3.3V
|
||||
|
||||
#define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26 ///< Init rt scroll
|
||||
#define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27 ///< Init left scroll
|
||||
#define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29 ///< Init diag scroll
|
||||
#define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A ///< Init diag scroll
|
||||
#define SSD1306_DEACTIVATE_SCROLL 0x2E ///< Stop scroll
|
||||
#define SSD1306_ACTIVATE_SCROLL 0x2F ///< Start scroll
|
||||
#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 ///< Set scroll range
|
||||
|
||||
// Deprecated size stuff for backwards compatibility with old sketches
|
||||
#if defined SSD1306_128_64
|
||||
#define SSD1306_LCDWIDTH 128 ///< DEPRECATED: width w/SSD1306_128_64 defined
|
||||
#define SSD1306_LCDHEIGHT 64 ///< DEPRECATED: height w/SSD1306_128_64 defined
|
||||
#endif
|
||||
#if defined SSD1306_128_32
|
||||
#define SSD1306_LCDWIDTH 128 ///< DEPRECATED: width w/SSD1306_128_32 defined
|
||||
#define SSD1306_LCDHEIGHT 32 ///< DEPRECATED: height w/SSD1306_128_32 defined
|
||||
#endif
|
||||
#if defined SSD1306_96_16
|
||||
#define SSD1306_LCDWIDTH 96 ///< DEPRECATED: width w/SSD1306_96_16 defined
|
||||
#define SSD1306_LCDHEIGHT 16 ///< DEPRECATED: height w/SSD1306_96_16 defined
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief Class that stores state and functions for interacting with
|
||||
SSD1306 OLED displays.
|
||||
*/
|
||||
class Adafruit_SSD1306 : public Adafruit_GFX {
|
||||
public:
|
||||
// NEW CONSTRUCTORS -- recommended for new projects
|
||||
Adafruit_SSD1306(uint8_t w, uint8_t h, TwoWire *twi=&Wire, int8_t rst_pin=-1,
|
||||
uint32_t clkDuring=400000UL, uint32_t clkAfter=100000UL);
|
||||
Adafruit_SSD1306(uint8_t w, uint8_t h, int8_t mosi_pin, int8_t sclk_pin,
|
||||
int8_t dc_pin, int8_t rst_pin, int8_t cs_pin);
|
||||
Adafruit_SSD1306(uint8_t w, uint8_t h, SPIClass *spi,
|
||||
int8_t dc_pin, int8_t rst_pin, int8_t cs_pin, uint32_t bitrate=8000000UL);
|
||||
|
||||
// DEPRECATED CONSTRUCTORS - for back compatibility, avoid in new projects
|
||||
Adafruit_SSD1306(int8_t mosi_pin, int8_t sclk_pin, int8_t dc_pin,
|
||||
int8_t rst_pin, int8_t cs_pin);
|
||||
Adafruit_SSD1306(int8_t dc_pin, int8_t rst_pin, int8_t cs_pin);
|
||||
Adafruit_SSD1306(int8_t rst_pin = -1);
|
||||
|
||||
~Adafruit_SSD1306(void);
|
||||
|
||||
boolean begin(uint8_t switchvcc=SSD1306_SWITCHCAPVCC,
|
||||
uint8_t i2caddr=0, boolean reset=true,
|
||||
boolean periphBegin=true);
|
||||
void display(void);
|
||||
void clearDisplay(void);
|
||||
void invertDisplay(boolean i);
|
||||
void dim(boolean dim);
|
||||
void drawPixel(int16_t x, int16_t y, uint16_t color);
|
||||
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
|
||||
void startscrollright(uint8_t start, uint8_t stop);
|
||||
void startscrollleft(uint8_t start, uint8_t stop);
|
||||
void startscrolldiagright(uint8_t start, uint8_t stop);
|
||||
void startscrolldiagleft(uint8_t start, uint8_t stop);
|
||||
void stopscroll(void);
|
||||
void ssd1306_command(uint8_t c);
|
||||
boolean getPixel(int16_t x, int16_t y);
|
||||
uint8_t *getBuffer(void);
|
||||
|
||||
private:
|
||||
inline void SPIwrite(uint8_t d) __attribute__((always_inline));
|
||||
void drawFastHLineInternal(int16_t x, int16_t y, int16_t w,
|
||||
uint16_t color);
|
||||
void drawFastVLineInternal(int16_t x, int16_t y, int16_t h,
|
||||
uint16_t color);
|
||||
void ssd1306_command1(uint8_t c);
|
||||
void ssd1306_commandList(const uint8_t *c, uint8_t n);
|
||||
|
||||
SPIClass *spi;
|
||||
TwoWire *wire;
|
||||
uint8_t *buffer;
|
||||
int8_t i2caddr, vccstate, page_end;
|
||||
int8_t mosiPin , clkPin , dcPin , csPin, rstPin;
|
||||
#ifdef HAVE_PORTREG
|
||||
PortReg *mosiPort , *clkPort , *dcPort , *csPort;
|
||||
PortMask mosiPinMask, clkPinMask, dcPinMask, csPinMask;
|
||||
#endif
|
||||
#if defined(SPI_HAS_TRANSACTION)
|
||||
SPISettings spiSettings;
|
||||
#endif
|
||||
#if ARDUINO >= 157
|
||||
uint32_t wireClk; // Wire speed for SSD1306 transfers
|
||||
uint32_t restoreClk; // Wire speed following SSD1306 transfers
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // _Adafruit_SSD1306_H_
|
||||
/*!
|
||||
* @file Adafruit_SSD1306.h
|
||||
*
|
||||
* This is part of for Adafruit's SSD1306 library for monochrome
|
||||
* OLED displays: http://www.adafruit.com/category/63_98
|
||||
*
|
||||
* These displays use I2C or SPI to communicate. I2C requires 2 pins
|
||||
* (SCL+SDA) and optionally a RESET pin. SPI requires 4 pins (MOSI, SCK,
|
||||
* select, data/command) and optionally a reset pin. Hardware SPI or
|
||||
* 'bitbang' software SPI are both supported.
|
||||
*
|
||||
* Adafruit invests time and resources providing this open source code,
|
||||
* please support Adafruit and open-source hardware by purchasing
|
||||
* products from Adafruit!
|
||||
*
|
||||
* Written by Limor Fried/Ladyada for Adafruit Industries, with
|
||||
* contributions from the open source community.
|
||||
*
|
||||
* BSD license, all text above, and the splash screen header file,
|
||||
* must be included in any redistribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _Adafruit_SSD1306_H_
|
||||
#define _Adafruit_SSD1306_H_
|
||||
|
||||
#include <Wire.h>
|
||||
|
||||
#include <Adafruit_GFX.h>
|
||||
|
||||
typedef void* SPIClass;
|
||||
|
||||
// #if defined(__AVR__)
|
||||
// typedef volatile uint8_t PortReg;
|
||||
// typedef uint8_t PortMask;
|
||||
// #define HAVE_PORTREG
|
||||
// #elif defined(__SAM3X8E__)
|
||||
// typedef volatile RwReg PortReg;
|
||||
// typedef uint32_t PortMask;
|
||||
// #define HAVE_PORTREG
|
||||
// #elif defined(__arm__) || defined(ARDUINO_FEATHER52)
|
||||
// typedef volatile uint32_t PortReg;
|
||||
// typedef uint32_t PortMask;
|
||||
// #define HAVE_PORTREG
|
||||
// #endif
|
||||
|
||||
#define BLACK 0 ///< Draw 'off' pixels
|
||||
#define WHITE 1 ///< Draw 'on' pixels
|
||||
#define INVERSE 2 ///< Invert pixels
|
||||
|
||||
#define SSD1306_MEMORYMODE 0x20 ///< See datasheet
|
||||
#define SSD1306_COLUMNADDR 0x21 ///< See datasheet
|
||||
#define SSD1306_PAGEADDR 0x22 ///< See datasheet
|
||||
#define SSD1306_SETCONTRAST 0x81 ///< See datasheet
|
||||
#define SSD1306_CHARGEPUMP 0x8D ///< See datasheet
|
||||
#define SSD1306_SEGREMAP 0xA0 ///< See datasheet
|
||||
#define SSD1306_DISPLAYALLON_RESUME 0xA4 ///< See datasheet
|
||||
#define SSD1306_DISPLAYALLON 0xA5 ///< Not currently used
|
||||
#define SSD1306_NORMALDISPLAY 0xA6 ///< See datasheet
|
||||
#define SSD1306_INVERTDISPLAY 0xA7 ///< See datasheet
|
||||
#define SSD1306_SETMULTIPLEX 0xA8 ///< See datasheet
|
||||
#define SSD1306_DISPLAYOFF 0xAE ///< See datasheet
|
||||
#define SSD1306_DISPLAYON 0xAF ///< See datasheet
|
||||
#define SSD1306_COMSCANINC 0xC0 ///< Not currently used
|
||||
#define SSD1306_COMSCANDEC 0xC8 ///< See datasheet
|
||||
#define SSD1306_SETDISPLAYOFFSET 0xD3 ///< See datasheet
|
||||
#define SSD1306_SETDISPLAYCLOCKDIV 0xD5 ///< See datasheet
|
||||
#define SSD1306_SETPRECHARGE 0xD9 ///< See datasheet
|
||||
#define SSD1306_SETCOMPINS 0xDA ///< See datasheet
|
||||
#define SSD1306_SETVCOMDETECT 0xDB ///< See datasheet
|
||||
|
||||
#define SSD1306_SETLOWCOLUMN 0x00 ///< Not currently used
|
||||
#define SSD1306_SETHIGHCOLUMN 0x10 ///< Not currently used
|
||||
#define SSD1306_SETSTARTLINE 0x40 ///< See datasheet
|
||||
|
||||
#define SSD1306_EXTERNALVCC 0x01 ///< External display voltage source
|
||||
#define SSD1306_SWITCHCAPVCC 0x02 ///< Gen. display voltage from 3.3V
|
||||
|
||||
#define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26 ///< Init rt scroll
|
||||
#define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27 ///< Init left scroll
|
||||
#define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29 ///< Init diag scroll
|
||||
#define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A ///< Init diag scroll
|
||||
#define SSD1306_DEACTIVATE_SCROLL 0x2E ///< Stop scroll
|
||||
#define SSD1306_ACTIVATE_SCROLL 0x2F ///< Start scroll
|
||||
#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 ///< Set scroll range
|
||||
|
||||
// Deprecated size stuff for backwards compatibility with old sketches
|
||||
#if defined SSD1306_128_64
|
||||
#define SSD1306_LCDWIDTH 128 ///< DEPRECATED: width w/SSD1306_128_64 defined
|
||||
#define SSD1306_LCDHEIGHT 64 ///< DEPRECATED: height w/SSD1306_128_64 defined
|
||||
#endif
|
||||
#if defined SSD1306_128_32
|
||||
#define SSD1306_LCDWIDTH 128 ///< DEPRECATED: width w/SSD1306_128_32 defined
|
||||
#define SSD1306_LCDHEIGHT 32 ///< DEPRECATED: height w/SSD1306_128_32 defined
|
||||
#endif
|
||||
#if defined SSD1306_96_16
|
||||
#define SSD1306_LCDWIDTH 96 ///< DEPRECATED: width w/SSD1306_96_16 defined
|
||||
#define SSD1306_LCDHEIGHT 16 ///< DEPRECATED: height w/SSD1306_96_16 defined
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief Class that stores state and functions for interacting with
|
||||
SSD1306 OLED displays.
|
||||
*/
|
||||
class Adafruit_SSD1306 : public Adafruit_GFX {
|
||||
public:
|
||||
// NEW CONSTRUCTORS -- recommended for new projects
|
||||
Adafruit_SSD1306(uint8_t w, uint8_t h, TwoWire *twi=&Wire, int8_t rst_pin=-1,
|
||||
uint32_t clkDuring=400000UL, uint32_t clkAfter=100000UL);
|
||||
Adafruit_SSD1306(uint8_t w, uint8_t h, int8_t mosi_pin, int8_t sclk_pin,
|
||||
int8_t dc_pin, int8_t rst_pin, int8_t cs_pin);
|
||||
Adafruit_SSD1306(uint8_t w, uint8_t h, SPIClass *spi,
|
||||
int8_t dc_pin, int8_t rst_pin, int8_t cs_pin, uint32_t bitrate=8000000UL);
|
||||
|
||||
// DEPRECATED CONSTRUCTORS - for back compatibility, avoid in new projects
|
||||
Adafruit_SSD1306(int8_t mosi_pin, int8_t sclk_pin, int8_t dc_pin,
|
||||
int8_t rst_pin, int8_t cs_pin);
|
||||
Adafruit_SSD1306(int8_t dc_pin, int8_t rst_pin, int8_t cs_pin);
|
||||
Adafruit_SSD1306(int8_t rst_pin = -1);
|
||||
|
||||
~Adafruit_SSD1306(void);
|
||||
|
||||
boolean begin(uint8_t switchvcc=SSD1306_SWITCHCAPVCC,
|
||||
uint8_t i2caddr=0, boolean reset=true,
|
||||
boolean periphBegin=true);
|
||||
void display(void);
|
||||
void clearDisplay(void);
|
||||
void invertDisplay(boolean i);
|
||||
void dim(boolean dim);
|
||||
void drawPixel(int16_t x, int16_t y, uint16_t color);
|
||||
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
|
||||
void startscrollright(uint8_t start, uint8_t stop);
|
||||
void startscrollleft(uint8_t start, uint8_t stop);
|
||||
void startscrolldiagright(uint8_t start, uint8_t stop);
|
||||
void startscrolldiagleft(uint8_t start, uint8_t stop);
|
||||
void stopscroll(void);
|
||||
void ssd1306_command(uint8_t c);
|
||||
boolean getPixel(int16_t x, int16_t y);
|
||||
uint8_t *getBuffer(void);
|
||||
|
||||
private:
|
||||
inline void SPIwrite(uint8_t d) __attribute__((always_inline));
|
||||
void drawFastHLineInternal(int16_t x, int16_t y, int16_t w,
|
||||
uint16_t color);
|
||||
void drawFastVLineInternal(int16_t x, int16_t y, int16_t h,
|
||||
uint16_t color);
|
||||
void ssd1306_command1(uint8_t c);
|
||||
void ssd1306_commandList(const uint8_t *c, uint8_t n);
|
||||
|
||||
SPIClass *spi;
|
||||
TwoWire *wire;
|
||||
uint8_t *buffer;
|
||||
int8_t i2caddr, vccstate, page_end;
|
||||
int8_t mosiPin , clkPin , dcPin , csPin, rstPin;
|
||||
#ifdef HAVE_PORTREG
|
||||
PortReg *mosiPort , *clkPort , *dcPort , *csPort;
|
||||
PortMask mosiPinMask, clkPinMask, dcPinMask, csPinMask;
|
||||
#endif
|
||||
#if defined(SPI_HAS_TRANSACTION)
|
||||
SPISettings spiSettings;
|
||||
#endif
|
||||
#if ARDUINO >= 157
|
||||
uint32_t wireClk; // Wire speed for SSD1306 transfers
|
||||
uint32_t restoreClk; // Wire speed following SSD1306 transfers
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // _Adafruit_SSD1306_H_
|
||||
|
|
|
|||
|
|
@ -1,105 +1,105 @@
|
|||
#ifndef __ARDUINO_H__
|
||||
#define __ARDUINO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "Wiring.h"
|
||||
#include "simusbmidi.h"
|
||||
|
||||
#include "core_pins.h"
|
||||
|
||||
#define PROGMEM
|
||||
|
||||
#ifndef _BV
|
||||
#define _BV(x) (1u<<(x))
|
||||
#endif
|
||||
|
||||
// SPI CTRL REG BITS
|
||||
#define SPIE 7
|
||||
#define SPE 6
|
||||
#define DORD 5
|
||||
#define MSTR 4
|
||||
#define CPOL 3
|
||||
#define CPHA 2
|
||||
#define SPR1 1
|
||||
#define SPR0 0
|
||||
|
||||
|
||||
#define A11 (0xa1)
|
||||
|
||||
/*
|
||||
SPCR
|
||||
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
| SPIE | SPE | DORD | MSTR | CPOL | CPHA | SPR1 | SPR0 |
|
||||
|
||||
SPIE - Enables the SPI interrupt when 1
|
||||
SPE - Enables the SPI when 1
|
||||
DORD - Sends data least Significant Bit First when 1, most Significant Bit first when 0
|
||||
MSTR - Sets the Arduino in master mode when 1, slave mode when 0
|
||||
CPOL - Sets the data clock to be idle when high if set to 1, idle when low if set to 0
|
||||
CPHA - Samples data on the falling edge of the data clock when 1, rising edge when 0
|
||||
SPR1 and SPR0 - Sets the SPI speed, 00 is fastest (4MHz) 11 is slowest (250KHz)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define LSBFIRST 0
|
||||
#define MSBFIRST 1
|
||||
|
||||
typedef bool boolean;
|
||||
typedef uint8_t byte;
|
||||
|
||||
// class Print
|
||||
// {
|
||||
// public:
|
||||
// };
|
||||
|
||||
|
||||
class SimSerial
|
||||
{
|
||||
public:
|
||||
void begin(uint32_t speed);
|
||||
void println(uint32_t value);
|
||||
void println();
|
||||
void println(const char* str);
|
||||
void print(const char* str);
|
||||
void print(uint32_t intValue);
|
||||
void write(const uint8_t str);
|
||||
void flush();
|
||||
|
||||
};
|
||||
|
||||
|
||||
extern SimSerial Serial;
|
||||
extern SimSerial Serial3; //Used for MIDI serial putput with default hardware
|
||||
extern SimUsbMidi usbMIDI;
|
||||
|
||||
//extern void putString(int row, int col, int color, const char* msg, const FONT_INFO fontInfo);
|
||||
|
||||
uint32_t micros();
|
||||
uint32_t millis();
|
||||
void delay(uint32_t millis);
|
||||
void delayMicroseconds(uint32_t micros);
|
||||
|
||||
|
||||
void pinMode(uint8_t, uint8_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
//void digitalWrite(uint8_t, uint8_t);
|
||||
//int digitalRead(uint8_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
int analogRead(uint8_t);
|
||||
void analogReference(uint8_t mode);
|
||||
void analogWrite(uint8_t, int);
|
||||
|
||||
#endif
|
||||
#ifndef __ARDUINO_H__
|
||||
#define __ARDUINO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "Wiring.h"
|
||||
#include "simusbmidi.h"
|
||||
|
||||
#include "core_pins.h"
|
||||
|
||||
#define PROGMEM
|
||||
|
||||
#ifndef _BV
|
||||
#define _BV(x) (1u<<(x))
|
||||
#endif
|
||||
|
||||
// SPI CTRL REG BITS
|
||||
#define SPIE 7
|
||||
#define SPE 6
|
||||
#define DORD 5
|
||||
#define MSTR 4
|
||||
#define CPOL 3
|
||||
#define CPHA 2
|
||||
#define SPR1 1
|
||||
#define SPR0 0
|
||||
|
||||
|
||||
#define A11 (0xa1)
|
||||
|
||||
/*
|
||||
SPCR
|
||||
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
| SPIE | SPE | DORD | MSTR | CPOL | CPHA | SPR1 | SPR0 |
|
||||
|
||||
SPIE - Enables the SPI interrupt when 1
|
||||
SPE - Enables the SPI when 1
|
||||
DORD - Sends data least Significant Bit First when 1, most Significant Bit first when 0
|
||||
MSTR - Sets the Arduino in master mode when 1, slave mode when 0
|
||||
CPOL - Sets the data clock to be idle when high if set to 1, idle when low if set to 0
|
||||
CPHA - Samples data on the falling edge of the data clock when 1, rising edge when 0
|
||||
SPR1 and SPR0 - Sets the SPI speed, 00 is fastest (4MHz) 11 is slowest (250KHz)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define LSBFIRST 0
|
||||
#define MSBFIRST 1
|
||||
|
||||
typedef bool boolean;
|
||||
typedef uint8_t byte;
|
||||
|
||||
// class Print
|
||||
// {
|
||||
// public:
|
||||
// };
|
||||
|
||||
|
||||
class SimSerial
|
||||
{
|
||||
public:
|
||||
void begin(uint32_t speed);
|
||||
void println(uint32_t value);
|
||||
void println();
|
||||
void println(const char* str);
|
||||
void print(const char* str);
|
||||
void print(uint32_t intValue);
|
||||
void write(const uint8_t str);
|
||||
void flush();
|
||||
|
||||
};
|
||||
|
||||
|
||||
extern SimSerial Serial;
|
||||
extern SimSerial Serial3; //Used for MIDI serial putput with default hardware
|
||||
extern SimUsbMidi usbMIDI;
|
||||
|
||||
//extern void putString(int row, int col, int color, const char* msg, const FONT_INFO fontInfo);
|
||||
|
||||
uint32_t micros();
|
||||
uint32_t millis();
|
||||
void delay(uint32_t millis);
|
||||
void delayMicroseconds(uint32_t micros);
|
||||
|
||||
|
||||
void pinMode(uint8_t, uint8_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
//void digitalWrite(uint8_t, uint8_t);
|
||||
//int digitalRead(uint8_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
int analogRead(uint8_t);
|
||||
void analogReference(uint8_t mode);
|
||||
void analogWrite(uint8_t, int);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,55 +1,55 @@
|
|||
#ifndef __EEPROM_H
|
||||
#define __EEPROM_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct EEPROMClass
|
||||
{
|
||||
EEPROMClass();
|
||||
//Basic user access methods.
|
||||
// EERef operator[]( const int idx ) { return idx; }
|
||||
uint8_t read( int idx ); // { return EERef( idx ); }
|
||||
void write( int idx, uint8_t val ); // { (EERef( idx )) = val; }
|
||||
void update( int idx, uint8_t val ); // { EERef( idx ).update( val ); }
|
||||
|
||||
//STL and C++11 iteration capability.
|
||||
// EEPtr begin() { return 0x00; }
|
||||
// EEPtr end() { return length(); } //Standards requires this to be the item after the last valid entry. The returned pointer is invalid.
|
||||
uint16_t length(); // { return E2END + 1; }
|
||||
|
||||
//Functionality to 'get' and 'put' objects to and from EEPROM.
|
||||
// template< typename T > T &get( int idx, T &t ){
|
||||
// EEPtr e = idx;
|
||||
// uint8_t *ptr = (uint8_t*) &t;
|
||||
// for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e;
|
||||
// return t;
|
||||
// }
|
||||
|
||||
// template< typename T > const T &put( int idx, const T &t ){
|
||||
// const uint8_t *ptr = (const uint8_t*) &t;
|
||||
// #ifdef __arm__
|
||||
// eeprom_write_block(ptr, (void *)idx, sizeof(T));
|
||||
// #else
|
||||
// EEPtr e = idx;
|
||||
// for( int count = sizeof(T) ; count ; --count, ++e ) (*e).update( *ptr++ );
|
||||
// #endif
|
||||
// return t;
|
||||
// }
|
||||
|
||||
//Make EEPROM persistent by storing to a file
|
||||
int16_t setStorage(const char* filename, bool write);
|
||||
void closeStorage();
|
||||
|
||||
private:
|
||||
uint8_t someFakeEEPROM_memory[2048]; //Teensy 3.2 size
|
||||
FILE *storage;
|
||||
bool autoUpdate;
|
||||
|
||||
|
||||
};
|
||||
|
||||
extern EEPROMClass EEPROM __unused;
|
||||
|
||||
|
||||
#endif
|
||||
#ifndef __EEPROM_H
|
||||
#define __EEPROM_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct EEPROMClass
|
||||
{
|
||||
EEPROMClass();
|
||||
//Basic user access methods.
|
||||
// EERef operator[]( const int idx ) { return idx; }
|
||||
uint8_t read( int idx ); // { return EERef( idx ); }
|
||||
void write( int idx, uint8_t val ); // { (EERef( idx )) = val; }
|
||||
void update( int idx, uint8_t val ); // { EERef( idx ).update( val ); }
|
||||
|
||||
//STL and C++11 iteration capability.
|
||||
// EEPtr begin() { return 0x00; }
|
||||
// EEPtr end() { return length(); } //Standards requires this to be the item after the last valid entry. The returned pointer is invalid.
|
||||
uint16_t length(); // { return E2END + 1; }
|
||||
|
||||
//Functionality to 'get' and 'put' objects to and from EEPROM.
|
||||
// template< typename T > T &get( int idx, T &t ){
|
||||
// EEPtr e = idx;
|
||||
// uint8_t *ptr = (uint8_t*) &t;
|
||||
// for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e;
|
||||
// return t;
|
||||
// }
|
||||
|
||||
// template< typename T > const T &put( int idx, const T &t ){
|
||||
// const uint8_t *ptr = (const uint8_t*) &t;
|
||||
// #ifdef __arm__
|
||||
// eeprom_write_block(ptr, (void *)idx, sizeof(T));
|
||||
// #else
|
||||
// EEPtr e = idx;
|
||||
// for( int count = sizeof(T) ; count ; --count, ++e ) (*e).update( *ptr++ );
|
||||
// #endif
|
||||
// return t;
|
||||
// }
|
||||
|
||||
//Make EEPROM persistent by storing to a file
|
||||
int16_t setStorage(const char* filename, bool write);
|
||||
void closeStorage();
|
||||
|
||||
private:
|
||||
uint8_t someFakeEEPROM_memory[2048]; //Teensy 3.2 size
|
||||
FILE *storage;
|
||||
bool autoUpdate;
|
||||
|
||||
|
||||
};
|
||||
|
||||
extern EEPROMClass EEPROM __unused;
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,136 +1,136 @@
|
|||
/* Teensyduino Core Library
|
||||
* http://www.pjrc.com/teensy/
|
||||
* Copyright (c) 2017 PJRC.COM, LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* 1. The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* 2. If the Software is incorporated into a build system that allows
|
||||
* selection among a list of target devices, then similar target
|
||||
* devices manufactured by PJRC.COM must be included in the list of
|
||||
* target devices and selectable in the same manner.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef Print_h
|
||||
#define Print_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h> // for size_t - gives sprintf and other stuff to all sketches & libs
|
||||
#include <stdarg.h>
|
||||
#include "core_id.h"
|
||||
#include "WString.h"
|
||||
#include "Printable.h"
|
||||
|
||||
#define DEC 10
|
||||
#define HEX 16
|
||||
#define OCT 8
|
||||
#define BIN 2
|
||||
|
||||
|
||||
#ifndef isnan
|
||||
#define isnan(__x) (__builtin_isnan (__x))
|
||||
#endif
|
||||
|
||||
#ifndef isinf
|
||||
#define isinf(__x) (__builtin_isinf (__x))
|
||||
#endif
|
||||
|
||||
|
||||
class __FlashStringHelper;
|
||||
|
||||
class Print
|
||||
{
|
||||
public:
|
||||
constexpr Print() : write_error(0) {}
|
||||
virtual size_t write(uint8_t b) = 0;
|
||||
size_t write(const char *str) { return write((const uint8_t *)str, strlen(str)); }
|
||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||
virtual int availableForWrite(void) { return 0; }
|
||||
virtual void flush() { }
|
||||
size_t write(const char *buffer, size_t size) { return write((const uint8_t *)buffer, size); }
|
||||
// size_t print(const String &s);
|
||||
size_t print(char c) { return write((uint8_t)c); }
|
||||
size_t print(const char s[]) { return write(s); }
|
||||
size_t print(const __FlashStringHelper *f) { return write((const char *)f); }
|
||||
|
||||
size_t print(uint8_t b) { return printNumber(b, 10, 0); }
|
||||
size_t print(int n) { return print((long)n); }
|
||||
size_t print(unsigned int n) { return printNumber(n, 10, 0); }
|
||||
size_t print(long n);
|
||||
size_t print(unsigned long n) { return printNumber(n, 10, 0); }
|
||||
|
||||
size_t print(unsigned char n, int base) { return printNumber(n, base, 0); }
|
||||
size_t print(int n, int base) { return (base == 10) ? print(n) : printNumber(n, base, 0); }
|
||||
size_t print(unsigned int n, int base) { return printNumber(n, base, 0); }
|
||||
size_t print(long n, int base) { return (base == 10) ? print(n) : printNumber(n, base, 0); }
|
||||
size_t print(unsigned long n, int base) { return printNumber(n, base, 0); }
|
||||
|
||||
size_t print(double n, int digits = 2) { return printFloat(n, digits); }
|
||||
size_t print(const Printable &obj) { return obj.printTo(*this); }
|
||||
size_t println(void);
|
||||
// size_t println(const String &s) { return print(s) + println(); }
|
||||
size_t println(char c) { return print(c) + println(); }
|
||||
size_t println(const char s[]) { return print(s) + println(); }
|
||||
size_t println(const __FlashStringHelper *f) { return print(f) + println(); }
|
||||
|
||||
size_t println(uint8_t b) { return print(b) + println(); }
|
||||
size_t println(int n) { return print(n) + println(); }
|
||||
size_t println(unsigned int n) { return print(n) + println(); }
|
||||
size_t println(long n) { return print(n) + println(); }
|
||||
size_t println(unsigned long n) { return print(n) + println(); }
|
||||
|
||||
size_t println(unsigned char n, int base) { return print(n, base) + println(); }
|
||||
size_t println(int n, int base) { return print(n, base) + println(); }
|
||||
size_t println(unsigned int n, int base) { return print(n, base) + println(); }
|
||||
size_t println(long n, int base) { return print(n, base) + println(); }
|
||||
size_t println(unsigned long n, int base) { return print(n, base) + println(); }
|
||||
|
||||
size_t println(double n, int digits = 2) { return print(n, digits) + println(); }
|
||||
size_t println(const Printable &obj) { return obj.printTo(*this) + println(); }
|
||||
int getWriteError() { return write_error; }
|
||||
void clearWriteError() { setWriteError(0); }
|
||||
int printf(const char *format, ...);
|
||||
int printf(const __FlashStringHelper *format, ...);
|
||||
protected:
|
||||
void setWriteError(int err = 1) { write_error = err; }
|
||||
private:
|
||||
char write_error;
|
||||
size_t printFloat(double n, uint8_t digits);
|
||||
#ifdef __MKL26Z64__
|
||||
size_t printNumberDec(unsigned long n, uint8_t sign);
|
||||
size_t printNumberHex(unsigned long n);
|
||||
size_t printNumberBin(unsigned long n);
|
||||
size_t printNumberAny(unsigned long n, uint8_t base);
|
||||
inline size_t printNumber(unsigned long n, uint8_t base, uint8_t sign) __attribute__((always_inline)) {
|
||||
// when "base" is a constant (pretty much always), the
|
||||
// compiler optimizes this to a single function call.
|
||||
if (base == 0) return write((uint8_t)n);
|
||||
if (base == 10 || base < 2) return printNumberDec(n, sign);
|
||||
if (base == 16) return printNumberHex(n);
|
||||
if (base == 2) return printNumberBin(n);
|
||||
return printNumberAny(n, base);
|
||||
}
|
||||
#else
|
||||
size_t printNumber(unsigned long n, uint8_t base, uint8_t sign);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
/* Teensyduino Core Library
|
||||
* http://www.pjrc.com/teensy/
|
||||
* Copyright (c) 2017 PJRC.COM, LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* 1. The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* 2. If the Software is incorporated into a build system that allows
|
||||
* selection among a list of target devices, then similar target
|
||||
* devices manufactured by PJRC.COM must be included in the list of
|
||||
* target devices and selectable in the same manner.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef Print_h
|
||||
#define Print_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h> // for size_t - gives sprintf and other stuff to all sketches & libs
|
||||
#include <stdarg.h>
|
||||
#include "core_id.h"
|
||||
#include "WString.h"
|
||||
#include "Printable.h"
|
||||
|
||||
#define DEC 10
|
||||
#define HEX 16
|
||||
#define OCT 8
|
||||
#define BIN 2
|
||||
|
||||
|
||||
#ifndef isnan
|
||||
#define isnan(__x) (__builtin_isnan (__x))
|
||||
#endif
|
||||
|
||||
#ifndef isinf
|
||||
#define isinf(__x) (__builtin_isinf (__x))
|
||||
#endif
|
||||
|
||||
|
||||
class __FlashStringHelper;
|
||||
|
||||
class Print
|
||||
{
|
||||
public:
|
||||
constexpr Print() : write_error(0) {}
|
||||
virtual size_t write(uint8_t b) = 0;
|
||||
size_t write(const char *str) { return write((const uint8_t *)str, strlen(str)); }
|
||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||
virtual int availableForWrite(void) { return 0; }
|
||||
virtual void flush() { }
|
||||
size_t write(const char *buffer, size_t size) { return write((const uint8_t *)buffer, size); }
|
||||
// size_t print(const String &s);
|
||||
size_t print(char c) { return write((uint8_t)c); }
|
||||
size_t print(const char s[]) { return write(s); }
|
||||
size_t print(const __FlashStringHelper *f) { return write((const char *)f); }
|
||||
|
||||
size_t print(uint8_t b) { return printNumber(b, 10, 0); }
|
||||
size_t print(int n) { return print((long)n); }
|
||||
size_t print(unsigned int n) { return printNumber(n, 10, 0); }
|
||||
size_t print(long n);
|
||||
size_t print(unsigned long n) { return printNumber(n, 10, 0); }
|
||||
|
||||
size_t print(unsigned char n, int base) { return printNumber(n, base, 0); }
|
||||
size_t print(int n, int base) { return (base == 10) ? print(n) : printNumber(n, base, 0); }
|
||||
size_t print(unsigned int n, int base) { return printNumber(n, base, 0); }
|
||||
size_t print(long n, int base) { return (base == 10) ? print(n) : printNumber(n, base, 0); }
|
||||
size_t print(unsigned long n, int base) { return printNumber(n, base, 0); }
|
||||
|
||||
size_t print(double n, int digits = 2) { return printFloat(n, digits); }
|
||||
size_t print(const Printable &obj) { return obj.printTo(*this); }
|
||||
size_t println(void);
|
||||
// size_t println(const String &s) { return print(s) + println(); }
|
||||
size_t println(char c) { return print(c) + println(); }
|
||||
size_t println(const char s[]) { return print(s) + println(); }
|
||||
size_t println(const __FlashStringHelper *f) { return print(f) + println(); }
|
||||
|
||||
size_t println(uint8_t b) { return print(b) + println(); }
|
||||
size_t println(int n) { return print(n) + println(); }
|
||||
size_t println(unsigned int n) { return print(n) + println(); }
|
||||
size_t println(long n) { return print(n) + println(); }
|
||||
size_t println(unsigned long n) { return print(n) + println(); }
|
||||
|
||||
size_t println(unsigned char n, int base) { return print(n, base) + println(); }
|
||||
size_t println(int n, int base) { return print(n, base) + println(); }
|
||||
size_t println(unsigned int n, int base) { return print(n, base) + println(); }
|
||||
size_t println(long n, int base) { return print(n, base) + println(); }
|
||||
size_t println(unsigned long n, int base) { return print(n, base) + println(); }
|
||||
|
||||
size_t println(double n, int digits = 2) { return print(n, digits) + println(); }
|
||||
size_t println(const Printable &obj) { return obj.printTo(*this) + println(); }
|
||||
int getWriteError() { return write_error; }
|
||||
void clearWriteError() { setWriteError(0); }
|
||||
int printf(const char *format, ...);
|
||||
int printf(const __FlashStringHelper *format, ...);
|
||||
protected:
|
||||
void setWriteError(int err = 1) { write_error = err; }
|
||||
private:
|
||||
char write_error;
|
||||
size_t printFloat(double n, uint8_t digits);
|
||||
#ifdef __MKL26Z64__
|
||||
size_t printNumberDec(unsigned long n, uint8_t sign);
|
||||
size_t printNumberHex(unsigned long n);
|
||||
size_t printNumberBin(unsigned long n);
|
||||
size_t printNumberAny(unsigned long n, uint8_t base);
|
||||
inline size_t printNumber(unsigned long n, uint8_t base, uint8_t sign) __attribute__((always_inline)) {
|
||||
// when "base" is a constant (pretty much always), the
|
||||
// compiler optimizes this to a single function call.
|
||||
if (base == 0) return write((uint8_t)n);
|
||||
if (base == 10 || base < 2) return printNumberDec(n, sign);
|
||||
if (base == 16) return printNumberHex(n);
|
||||
if (base == 2) return printNumberBin(n);
|
||||
return printNumberAny(n, base);
|
||||
}
|
||||
#else
|
||||
size_t printNumber(unsigned long n, uint8_t base, uint8_t sign);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,42 +1,42 @@
|
|||
/*
|
||||
Printable.h - Interface class that allows printing of complex types
|
||||
Copyright (c) 2011 Adrian McEwen. All right 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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef Printable_h
|
||||
#define Printable_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// #include "new.h"
|
||||
|
||||
class Print;
|
||||
|
||||
/** The Printable class provides a way for new classes to allow themselves to be printed.
|
||||
By deriving from Printable and implementing the printTo method, it will then be possible
|
||||
for users to print out instances of this class by passing them into the usual
|
||||
Print::print and Print::println methods.
|
||||
*/
|
||||
class Printable
|
||||
{
|
||||
public:
|
||||
virtual size_t printTo(Print& p) const = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
/*
|
||||
Printable.h - Interface class that allows printing of complex types
|
||||
Copyright (c) 2011 Adrian McEwen. All right 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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef Printable_h
|
||||
#define Printable_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// #include "new.h"
|
||||
|
||||
class Print;
|
||||
|
||||
/** The Printable class provides a way for new classes to allow themselves to be printed.
|
||||
By deriving from Printable and implementing the printTo method, it will then be possible
|
||||
for users to print out instances of this class by passing them into the usual
|
||||
Print::print and Print::println methods.
|
||||
*/
|
||||
class Printable
|
||||
{
|
||||
public:
|
||||
virtual size_t printTo(Print& p) const = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#if defined(__APPLE__)
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#else
|
||||
#error "Platform not supported, fix include paths and stuff.."
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#else
|
||||
#error "Platform not supported, fix include paths and stuff.."
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
#include <SDL2/SDL_syswm.h>
|
||||
#include <SDL2/SDL_syswm.h>
|
||||
|
|
|
|||
|
|
@ -1,165 +1,165 @@
|
|||
#ifndef __SPI_H__
|
||||
#define __SPI_H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
#define SPIClass SimSPI
|
||||
|
||||
|
||||
#ifndef SPI_MODE0
|
||||
#define SPI_MODE0 0
|
||||
#endif
|
||||
|
||||
#ifndef SPI_CLOCK_DIV2
|
||||
#define SPI_CLOCK_DIV2 0
|
||||
#endif
|
||||
|
||||
#define SPDR *SPI.SPI_dataReg
|
||||
#define SPCR *SPI.SPI_ctrlReg
|
||||
#define SPSR *SPI.SPI_statusReg
|
||||
|
||||
//#define SPSR 0xff
|
||||
#define SPIF (SPI.SPI_IF)
|
||||
|
||||
|
||||
// Forward declare
|
||||
class SimSPI;
|
||||
class DataRegister;
|
||||
class SPICtrlRegister;
|
||||
class SPIStatusRegister;
|
||||
|
||||
|
||||
extern SimSPI SPI;
|
||||
|
||||
|
||||
class ISPIDevice
|
||||
{
|
||||
public:
|
||||
virtual uint8_t spiSlaveWrite( uint8_t ) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class SimSPI
|
||||
{
|
||||
public:
|
||||
SimSPI();
|
||||
|
||||
void AddDevice( ISPIDevice* device );
|
||||
|
||||
void begin();
|
||||
|
||||
void transfer( uint8_t something );
|
||||
|
||||
void setDataMode( uint8_t mode );
|
||||
void setClockDivider( uint32_t divider );
|
||||
void writeReg( DataRegister *reg, uint8_t data);
|
||||
|
||||
// Members
|
||||
DataRegister* SPI_dataReg;
|
||||
SPICtrlRegister* SPI_ctrlReg;
|
||||
SPIStatusRegister* SPI_statusReg;
|
||||
|
||||
|
||||
uint8_t SPI_IF;
|
||||
|
||||
private:
|
||||
ISPIDevice** devices;
|
||||
uint32_t devicesArraySize;
|
||||
|
||||
ISPIDevice* currentSlave;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class HWRegister
|
||||
{
|
||||
public:
|
||||
HWRegister( SimSPI& owner) : spi_( owner ) {}
|
||||
protected:
|
||||
SimSPI& spi_;
|
||||
};
|
||||
|
||||
|
||||
class DataRegister : HWRegister
|
||||
{
|
||||
public:
|
||||
DataRegister( SimSPI& owner) : HWRegister( owner ) {}
|
||||
void operator=(uint8_t data)
|
||||
{
|
||||
spi_.writeReg( this, data );
|
||||
}
|
||||
|
||||
operator uint8_t()
|
||||
{
|
||||
// TODO: Get last read byte
|
||||
return 0xffu;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class SPIStatusRegister : HWRegister
|
||||
{
|
||||
public:
|
||||
SPIStatusRegister( SimSPI& owner) : HWRegister( owner ) {}
|
||||
void operator =(uint8_t value)
|
||||
{
|
||||
reg_ = value;
|
||||
}
|
||||
|
||||
void operator |=(uint8_t value)
|
||||
{
|
||||
reg_ |= value;
|
||||
}
|
||||
|
||||
void operator &=(uint8_t value)
|
||||
{
|
||||
reg_ &= value;
|
||||
}
|
||||
/*
|
||||
operator uint8_t()
|
||||
{
|
||||
return reg_|0xff;
|
||||
}
|
||||
*/
|
||||
operator uint32_t()
|
||||
{
|
||||
return reg_|0xff;
|
||||
}
|
||||
|
||||
uint8_t reg_;
|
||||
};
|
||||
|
||||
class SPICtrlRegister : HWRegister
|
||||
{
|
||||
public:
|
||||
SPICtrlRegister( SimSPI& owner) : HWRegister( owner ) {}
|
||||
|
||||
void operator =(uint8_t value)
|
||||
{
|
||||
reg_ = value;
|
||||
}
|
||||
|
||||
void operator |=(uint8_t value)
|
||||
{
|
||||
reg_ |= value;
|
||||
}
|
||||
|
||||
void operator &=(uint8_t value)
|
||||
{
|
||||
reg_ &= value;
|
||||
}
|
||||
|
||||
|
||||
operator uint8_t()
|
||||
{
|
||||
return reg_;
|
||||
}
|
||||
|
||||
|
||||
uint8_t reg_;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
#ifndef __SPI_H__
|
||||
#define __SPI_H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
#define SPIClass SimSPI
|
||||
|
||||
|
||||
#ifndef SPI_MODE0
|
||||
#define SPI_MODE0 0
|
||||
#endif
|
||||
|
||||
#ifndef SPI_CLOCK_DIV2
|
||||
#define SPI_CLOCK_DIV2 0
|
||||
#endif
|
||||
|
||||
#define SPDR *SPI.SPI_dataReg
|
||||
#define SPCR *SPI.SPI_ctrlReg
|
||||
#define SPSR *SPI.SPI_statusReg
|
||||
|
||||
//#define SPSR 0xff
|
||||
#define SPIF (SPI.SPI_IF)
|
||||
|
||||
|
||||
// Forward declare
|
||||
class SimSPI;
|
||||
class DataRegister;
|
||||
class SPICtrlRegister;
|
||||
class SPIStatusRegister;
|
||||
|
||||
|
||||
extern SimSPI SPI;
|
||||
|
||||
|
||||
class ISPIDevice
|
||||
{
|
||||
public:
|
||||
virtual uint8_t spiSlaveWrite( uint8_t ) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class SimSPI
|
||||
{
|
||||
public:
|
||||
SimSPI();
|
||||
|
||||
void AddDevice( ISPIDevice* device );
|
||||
|
||||
void begin();
|
||||
|
||||
void transfer( uint8_t something );
|
||||
|
||||
void setDataMode( uint8_t mode );
|
||||
void setClockDivider( uint32_t divider );
|
||||
void writeReg( DataRegister *reg, uint8_t data);
|
||||
|
||||
// Members
|
||||
DataRegister* SPI_dataReg;
|
||||
SPICtrlRegister* SPI_ctrlReg;
|
||||
SPIStatusRegister* SPI_statusReg;
|
||||
|
||||
|
||||
uint8_t SPI_IF;
|
||||
|
||||
private:
|
||||
ISPIDevice** devices;
|
||||
uint32_t devicesArraySize;
|
||||
|
||||
ISPIDevice* currentSlave;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class HWRegister
|
||||
{
|
||||
public:
|
||||
HWRegister( SimSPI& owner) : spi_( owner ) {}
|
||||
protected:
|
||||
SimSPI& spi_;
|
||||
};
|
||||
|
||||
|
||||
class DataRegister : HWRegister
|
||||
{
|
||||
public:
|
||||
DataRegister( SimSPI& owner) : HWRegister( owner ) {}
|
||||
void operator=(uint8_t data)
|
||||
{
|
||||
spi_.writeReg( this, data );
|
||||
}
|
||||
|
||||
operator uint8_t()
|
||||
{
|
||||
// TODO: Get last read byte
|
||||
return 0xffu;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class SPIStatusRegister : HWRegister
|
||||
{
|
||||
public:
|
||||
SPIStatusRegister( SimSPI& owner) : HWRegister( owner ) {}
|
||||
void operator =(uint8_t value)
|
||||
{
|
||||
reg_ = value;
|
||||
}
|
||||
|
||||
void operator |=(uint8_t value)
|
||||
{
|
||||
reg_ |= value;
|
||||
}
|
||||
|
||||
void operator &=(uint8_t value)
|
||||
{
|
||||
reg_ &= value;
|
||||
}
|
||||
/*
|
||||
operator uint8_t()
|
||||
{
|
||||
return reg_|0xff;
|
||||
}
|
||||
*/
|
||||
operator uint32_t()
|
||||
{
|
||||
return reg_|0xff;
|
||||
}
|
||||
|
||||
uint8_t reg_;
|
||||
};
|
||||
|
||||
class SPICtrlRegister : HWRegister
|
||||
{
|
||||
public:
|
||||
SPICtrlRegister( SimSPI& owner) : HWRegister( owner ) {}
|
||||
|
||||
void operator =(uint8_t value)
|
||||
{
|
||||
reg_ = value;
|
||||
}
|
||||
|
||||
void operator |=(uint8_t value)
|
||||
{
|
||||
reg_ |= value;
|
||||
}
|
||||
|
||||
void operator &=(uint8_t value)
|
||||
{
|
||||
reg_ &= value;
|
||||
}
|
||||
|
||||
|
||||
operator uint8_t()
|
||||
{
|
||||
return reg_;
|
||||
}
|
||||
|
||||
|
||||
uint8_t reg_;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,227 +1,227 @@
|
|||
/*
|
||||
WString.h - String library for Wiring & Arduino
|
||||
...mostly rewritten by Paul Stoffregen...
|
||||
Copyright (c) 2009-10 Hernando Barragan. All right reserved.
|
||||
Copyright 2011, Paul Stoffregen, paul@pjrc.com
|
||||
|
||||
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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef String_class_h
|
||||
#define String_class_h
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
//#include "avr_functions.h"
|
||||
|
||||
// Not needed here, but some libs assume WString.h or Print.h
|
||||
// gives them PROGMEM and other AVR stuff.
|
||||
//#include "avr/pgmspace.h"
|
||||
|
||||
// When compiling programs with this class, the following gcc parameters
|
||||
// dramatically increase performance and memory (RAM) efficiency, typically
|
||||
// with little or no increase in code size.
|
||||
// -felide-constructors
|
||||
// -std=c++0x
|
||||
|
||||
// Brian Cook's "no overhead" Flash String type (message on Dec 14, 2010)
|
||||
// modified by Mikal Hart for his FlashString library
|
||||
class __FlashStringHelper;
|
||||
#ifndef F
|
||||
#define F(string_literal) ((const __FlashStringHelper *)(string_literal))
|
||||
#endif
|
||||
|
||||
// An inherited class for holding the result of a concatenation. These
|
||||
// result objects are assumed to be writable by subsequent concatenations.
|
||||
class StringSumHelper;
|
||||
|
||||
// The string class
|
||||
class String
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
String(const char *cstr = (const char *)NULL);
|
||||
String(const __FlashStringHelper *pgmstr);
|
||||
String(const String &str);
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
String(String &&rval);
|
||||
String(StringSumHelper &&rval);
|
||||
#endif
|
||||
String(char c);
|
||||
String(unsigned char c);
|
||||
String(int, unsigned char base=10);
|
||||
String(unsigned int, unsigned char base=10);
|
||||
String(long, unsigned char base=10);
|
||||
String(unsigned long, unsigned char base=10);
|
||||
String(float num, unsigned char digits=2);
|
||||
String(double num, unsigned char digits=2) : String((float)num, digits) {}
|
||||
~String(void);
|
||||
|
||||
// memory management
|
||||
unsigned char reserve(unsigned int size);
|
||||
inline unsigned int length(void) const {return len;}
|
||||
|
||||
// copy and move
|
||||
String & copy(const char *cstr, unsigned int length);
|
||||
String & copy(const __FlashStringHelper *s) { return copy((const char *)s, strlen((const char *)s)); }
|
||||
void move(String &rhs);
|
||||
String & operator = (const String &rhs);
|
||||
String & operator = (const char *cstr);
|
||||
String & operator = (const __FlashStringHelper *pgmstr);
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
String & operator = (String &&rval);
|
||||
String & operator = (StringSumHelper &&rval);
|
||||
#endif
|
||||
String & operator = (char c);
|
||||
|
||||
// append
|
||||
String & append(const String &str);
|
||||
String & append(const char *cstr);
|
||||
String & append(const __FlashStringHelper *s) {return append((const char *)s, strlen((const char *)s)); }
|
||||
String & append(char c);
|
||||
String & append(unsigned char c) {return append((int)c);}
|
||||
String & append(int num);
|
||||
String & append(unsigned int num);
|
||||
String & append(long num);
|
||||
String & append(unsigned long num);
|
||||
String & append(float num);
|
||||
String & append(double num) {return append((float)num);}
|
||||
String & operator += (const String &rhs) {return append(rhs);}
|
||||
String & operator += (const char *cstr) {return append(cstr);}
|
||||
String & operator += (const __FlashStringHelper *pgmstr) {return append(pgmstr);}
|
||||
String & operator += (char c) {return append(c);}
|
||||
String & operator += (unsigned char c) {return append((int)c);}
|
||||
String & operator += (int num) {return append(num);}
|
||||
String & operator += (unsigned int num) {return append(num);}
|
||||
String & operator += (long num) {return append(num);}
|
||||
String & operator += (unsigned long num) {return append(num);}
|
||||
String & operator += (float num) {return append(num);}
|
||||
String & operator += (double num) {return append(num);}
|
||||
|
||||
// concatenate
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *pgmstr);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, char c);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char c);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, int num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, long num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, float num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, double num);
|
||||
String & concat(const String &str) {return append(str);}
|
||||
String & concat(const char *cstr) {return append(cstr);}
|
||||
String & concat(const __FlashStringHelper *pgmstr) {return append(pgmstr);}
|
||||
String & concat(char c) {return append(c);}
|
||||
String & concat(unsigned char c) {return append((int)c);}
|
||||
String & concat(int num) {return append(num);}
|
||||
String & concat(unsigned int num) {return append(num);}
|
||||
String & concat(long num) {return append(num);}
|
||||
String & concat(unsigned long num) {return append(num);}
|
||||
String & concat(float num) {return append(num);}
|
||||
String & concat(double num) {return append(num);}
|
||||
|
||||
// comparison
|
||||
int compareTo(const String &s) const;
|
||||
unsigned char equals(const String &s) const;
|
||||
unsigned char equals(const char *cstr) const;
|
||||
//unsigned char equals(const __FlashStringHelper *pgmstr) const;
|
||||
unsigned char operator == (const String &rhs) const {return equals(rhs);}
|
||||
unsigned char operator == (const char *cstr) const {return equals(cstr);}
|
||||
unsigned char operator == (const __FlashStringHelper *s) const {return equals((const char *)s);}
|
||||
unsigned char operator != (const String &rhs) const {return !equals(rhs);}
|
||||
unsigned char operator != (const char *cstr) const {return !equals(cstr);}
|
||||
unsigned char operator != (const __FlashStringHelper *s) const {return !equals(s);}
|
||||
unsigned char operator < (const String &rhs) const;
|
||||
unsigned char operator > (const String &rhs) const;
|
||||
unsigned char operator <= (const String &rhs) const;
|
||||
unsigned char operator >= (const String &rhs) const;
|
||||
unsigned char equalsIgnoreCase(const String &s) const;
|
||||
unsigned char startsWith( const String &prefix) const;
|
||||
unsigned char startsWith(const String &prefix, unsigned int offset) const;
|
||||
unsigned char endsWith(const String &suffix) const;
|
||||
|
||||
// character acccess
|
||||
char charAt(unsigned int index) const;
|
||||
void setCharAt(unsigned int index, char c);
|
||||
char operator [] (unsigned int index) const;
|
||||
char& operator [] (unsigned int index);
|
||||
void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const;
|
||||
void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const
|
||||
{getBytes((unsigned char *)buf, bufsize, index);}
|
||||
const char * c_str() const { return buffer; }
|
||||
|
||||
// search
|
||||
int indexOf( char ch ) const;
|
||||
int indexOf( char ch, unsigned int fromIndex ) const;
|
||||
int indexOf( const String &str ) const;
|
||||
int indexOf( const String &str, unsigned int fromIndex ) const;
|
||||
int lastIndexOf( char ch ) const;
|
||||
int lastIndexOf( char ch, unsigned int fromIndex ) const;
|
||||
int lastIndexOf( const String &str ) const;
|
||||
int lastIndexOf( const String &str, unsigned int fromIndex ) const;
|
||||
String substring( unsigned int beginIndex ) const;
|
||||
String substring( unsigned int beginIndex, unsigned int endIndex ) const;
|
||||
|
||||
// modification
|
||||
String & replace(char find, char replace);
|
||||
String & replace(const String& find, const String& replace);
|
||||
String & remove(unsigned int index);
|
||||
String & remove(unsigned int index, unsigned int count);
|
||||
String & toLowerCase(void);
|
||||
String & toUpperCase(void);
|
||||
String & trim(void);
|
||||
|
||||
// parsing/conversion
|
||||
long toInt(void) const;
|
||||
float toFloat(void) const;
|
||||
|
||||
protected:
|
||||
char *buffer; // the actual char array
|
||||
unsigned int capacity; // the array length minus one (for the '\0')
|
||||
unsigned int len; // the String length (not counting the '\0')
|
||||
unsigned char flags; // unused, for future features
|
||||
protected:
|
||||
void init(void);
|
||||
unsigned char changeBuffer(unsigned int maxStrLen);
|
||||
String & append(const char *cstr, unsigned int length);
|
||||
private:
|
||||
// allow for "if (s)" without the complications of an operator bool().
|
||||
// for more information http://www.artima.com/cppsource/safebool.html
|
||||
typedef void (String::*StringIfHelperType)() const;
|
||||
void StringIfHelper() const {}
|
||||
public:
|
||||
operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; }
|
||||
};
|
||||
|
||||
class StringSumHelper : public String
|
||||
{
|
||||
public:
|
||||
StringSumHelper(const String &s) : String(s) {}
|
||||
StringSumHelper(const char *p) : String(p) {}
|
||||
StringSumHelper(const __FlashStringHelper *pgmstr) : String(pgmstr) {}
|
||||
StringSumHelper(char c) : String(c) {}
|
||||
StringSumHelper(unsigned char c) : String(c) {}
|
||||
StringSumHelper(int num) : String(num, 10) {}
|
||||
StringSumHelper(unsigned int num) : String(num, 10) {}
|
||||
StringSumHelper(long num) : String(num, 10) {}
|
||||
StringSumHelper(unsigned long num) : String(num, 10) {}
|
||||
};
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // String_class_h
|
||||
/*
|
||||
WString.h - String library for Wiring & Arduino
|
||||
...mostly rewritten by Paul Stoffregen...
|
||||
Copyright (c) 2009-10 Hernando Barragan. All right reserved.
|
||||
Copyright 2011, Paul Stoffregen, paul@pjrc.com
|
||||
|
||||
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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef String_class_h
|
||||
#define String_class_h
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
//#include "avr_functions.h"
|
||||
|
||||
// Not needed here, but some libs assume WString.h or Print.h
|
||||
// gives them PROGMEM and other AVR stuff.
|
||||
//#include "avr/pgmspace.h"
|
||||
|
||||
// When compiling programs with this class, the following gcc parameters
|
||||
// dramatically increase performance and memory (RAM) efficiency, typically
|
||||
// with little or no increase in code size.
|
||||
// -felide-constructors
|
||||
// -std=c++0x
|
||||
|
||||
// Brian Cook's "no overhead" Flash String type (message on Dec 14, 2010)
|
||||
// modified by Mikal Hart for his FlashString library
|
||||
class __FlashStringHelper;
|
||||
#ifndef F
|
||||
#define F(string_literal) ((const __FlashStringHelper *)(string_literal))
|
||||
#endif
|
||||
|
||||
// An inherited class for holding the result of a concatenation. These
|
||||
// result objects are assumed to be writable by subsequent concatenations.
|
||||
class StringSumHelper;
|
||||
|
||||
// The string class
|
||||
class String
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
String(const char *cstr = (const char *)NULL);
|
||||
String(const __FlashStringHelper *pgmstr);
|
||||
String(const String &str);
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
String(String &&rval);
|
||||
String(StringSumHelper &&rval);
|
||||
#endif
|
||||
String(char c);
|
||||
String(unsigned char c);
|
||||
String(int, unsigned char base=10);
|
||||
String(unsigned int, unsigned char base=10);
|
||||
String(long, unsigned char base=10);
|
||||
String(unsigned long, unsigned char base=10);
|
||||
String(float num, unsigned char digits=2);
|
||||
String(double num, unsigned char digits=2) : String((float)num, digits) {}
|
||||
~String(void);
|
||||
|
||||
// memory management
|
||||
unsigned char reserve(unsigned int size);
|
||||
inline unsigned int length(void) const {return len;}
|
||||
|
||||
// copy and move
|
||||
String & copy(const char *cstr, unsigned int length);
|
||||
String & copy(const __FlashStringHelper *s) { return copy((const char *)s, strlen((const char *)s)); }
|
||||
void move(String &rhs);
|
||||
String & operator = (const String &rhs);
|
||||
String & operator = (const char *cstr);
|
||||
String & operator = (const __FlashStringHelper *pgmstr);
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
String & operator = (String &&rval);
|
||||
String & operator = (StringSumHelper &&rval);
|
||||
#endif
|
||||
String & operator = (char c);
|
||||
|
||||
// append
|
||||
String & append(const String &str);
|
||||
String & append(const char *cstr);
|
||||
String & append(const __FlashStringHelper *s) {return append((const char *)s, strlen((const char *)s)); }
|
||||
String & append(char c);
|
||||
String & append(unsigned char c) {return append((int)c);}
|
||||
String & append(int num);
|
||||
String & append(unsigned int num);
|
||||
String & append(long num);
|
||||
String & append(unsigned long num);
|
||||
String & append(float num);
|
||||
String & append(double num) {return append((float)num);}
|
||||
String & operator += (const String &rhs) {return append(rhs);}
|
||||
String & operator += (const char *cstr) {return append(cstr);}
|
||||
String & operator += (const __FlashStringHelper *pgmstr) {return append(pgmstr);}
|
||||
String & operator += (char c) {return append(c);}
|
||||
String & operator += (unsigned char c) {return append((int)c);}
|
||||
String & operator += (int num) {return append(num);}
|
||||
String & operator += (unsigned int num) {return append(num);}
|
||||
String & operator += (long num) {return append(num);}
|
||||
String & operator += (unsigned long num) {return append(num);}
|
||||
String & operator += (float num) {return append(num);}
|
||||
String & operator += (double num) {return append(num);}
|
||||
|
||||
// concatenate
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *pgmstr);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, char c);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char c);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, int num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, long num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, float num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, double num);
|
||||
String & concat(const String &str) {return append(str);}
|
||||
String & concat(const char *cstr) {return append(cstr);}
|
||||
String & concat(const __FlashStringHelper *pgmstr) {return append(pgmstr);}
|
||||
String & concat(char c) {return append(c);}
|
||||
String & concat(unsigned char c) {return append((int)c);}
|
||||
String & concat(int num) {return append(num);}
|
||||
String & concat(unsigned int num) {return append(num);}
|
||||
String & concat(long num) {return append(num);}
|
||||
String & concat(unsigned long num) {return append(num);}
|
||||
String & concat(float num) {return append(num);}
|
||||
String & concat(double num) {return append(num);}
|
||||
|
||||
// comparison
|
||||
int compareTo(const String &s) const;
|
||||
unsigned char equals(const String &s) const;
|
||||
unsigned char equals(const char *cstr) const;
|
||||
//unsigned char equals(const __FlashStringHelper *pgmstr) const;
|
||||
unsigned char operator == (const String &rhs) const {return equals(rhs);}
|
||||
unsigned char operator == (const char *cstr) const {return equals(cstr);}
|
||||
unsigned char operator == (const __FlashStringHelper *s) const {return equals((const char *)s);}
|
||||
unsigned char operator != (const String &rhs) const {return !equals(rhs);}
|
||||
unsigned char operator != (const char *cstr) const {return !equals(cstr);}
|
||||
unsigned char operator != (const __FlashStringHelper *s) const {return !equals(s);}
|
||||
unsigned char operator < (const String &rhs) const;
|
||||
unsigned char operator > (const String &rhs) const;
|
||||
unsigned char operator <= (const String &rhs) const;
|
||||
unsigned char operator >= (const String &rhs) const;
|
||||
unsigned char equalsIgnoreCase(const String &s) const;
|
||||
unsigned char startsWith( const String &prefix) const;
|
||||
unsigned char startsWith(const String &prefix, unsigned int offset) const;
|
||||
unsigned char endsWith(const String &suffix) const;
|
||||
|
||||
// character acccess
|
||||
char charAt(unsigned int index) const;
|
||||
void setCharAt(unsigned int index, char c);
|
||||
char operator [] (unsigned int index) const;
|
||||
char& operator [] (unsigned int index);
|
||||
void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const;
|
||||
void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const
|
||||
{getBytes((unsigned char *)buf, bufsize, index);}
|
||||
const char * c_str() const { return buffer; }
|
||||
|
||||
// search
|
||||
int indexOf( char ch ) const;
|
||||
int indexOf( char ch, unsigned int fromIndex ) const;
|
||||
int indexOf( const String &str ) const;
|
||||
int indexOf( const String &str, unsigned int fromIndex ) const;
|
||||
int lastIndexOf( char ch ) const;
|
||||
int lastIndexOf( char ch, unsigned int fromIndex ) const;
|
||||
int lastIndexOf( const String &str ) const;
|
||||
int lastIndexOf( const String &str, unsigned int fromIndex ) const;
|
||||
String substring( unsigned int beginIndex ) const;
|
||||
String substring( unsigned int beginIndex, unsigned int endIndex ) const;
|
||||
|
||||
// modification
|
||||
String & replace(char find, char replace);
|
||||
String & replace(const String& find, const String& replace);
|
||||
String & remove(unsigned int index);
|
||||
String & remove(unsigned int index, unsigned int count);
|
||||
String & toLowerCase(void);
|
||||
String & toUpperCase(void);
|
||||
String & trim(void);
|
||||
|
||||
// parsing/conversion
|
||||
long toInt(void) const;
|
||||
float toFloat(void) const;
|
||||
|
||||
protected:
|
||||
char *buffer; // the actual char array
|
||||
unsigned int capacity; // the array length minus one (for the '\0')
|
||||
unsigned int len; // the String length (not counting the '\0')
|
||||
unsigned char flags; // unused, for future features
|
||||
protected:
|
||||
void init(void);
|
||||
unsigned char changeBuffer(unsigned int maxStrLen);
|
||||
String & append(const char *cstr, unsigned int length);
|
||||
private:
|
||||
// allow for "if (s)" without the complications of an operator bool().
|
||||
// for more information http://www.artima.com/cppsource/safebool.html
|
||||
typedef void (String::*StringIfHelperType)() const;
|
||||
void StringIfHelper() const {}
|
||||
public:
|
||||
operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; }
|
||||
};
|
||||
|
||||
class StringSumHelper : public String
|
||||
{
|
||||
public:
|
||||
StringSumHelper(const String &s) : String(s) {}
|
||||
StringSumHelper(const char *p) : String(p) {}
|
||||
StringSumHelper(const __FlashStringHelper *pgmstr) : String(pgmstr) {}
|
||||
StringSumHelper(char c) : String(c) {}
|
||||
StringSumHelper(unsigned char c) : String(c) {}
|
||||
StringSumHelper(int num) : String(num, 10) {}
|
||||
StringSumHelper(unsigned int num) : String(num, 10) {}
|
||||
StringSumHelper(long num) : String(num, 10) {}
|
||||
StringSumHelper(unsigned long num) : String(num, 10) {}
|
||||
};
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // String_class_h
|
||||
|
|
|
|||
|
|
@ -1,38 +1,38 @@
|
|||
#ifndef __WIRE_H__
|
||||
#define __WIRE_H__
|
||||
|
||||
#include <cstdint>
|
||||
#define TwoWire SimWire
|
||||
|
||||
class SimWire
|
||||
{
|
||||
public:
|
||||
SimWire(bool verbose = false);
|
||||
|
||||
void begin();
|
||||
void begin( uint8_t address ); // For slaves.
|
||||
void end();
|
||||
void setClock(uint32_t);
|
||||
void beginTransmission(uint8_t address);
|
||||
void beginTransmission(int);
|
||||
uint8_t endTransmission();
|
||||
uint8_t endTransmission(uint8_t);
|
||||
uint8_t requestFrom(uint8_t address, uint8_t count);
|
||||
uint8_t requestFrom(uint8_t, uint8_t, uint8_t);
|
||||
uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t);
|
||||
size_t write(uint8_t);
|
||||
size_t write(const uint8_t *, size_t);
|
||||
int available();
|
||||
int read();
|
||||
int peek();
|
||||
void flush();
|
||||
void onReceive( void (*)(int) );
|
||||
void onRequest( void (*)(void) );
|
||||
private:
|
||||
bool verbose_;
|
||||
};
|
||||
|
||||
extern SimWire Wire;
|
||||
|
||||
|
||||
#endif
|
||||
#ifndef __WIRE_H__
|
||||
#define __WIRE_H__
|
||||
|
||||
#include <cstdint>
|
||||
#define TwoWire SimWire
|
||||
|
||||
class SimWire
|
||||
{
|
||||
public:
|
||||
SimWire(bool verbose = false);
|
||||
|
||||
void begin();
|
||||
void begin( uint8_t address ); // For slaves.
|
||||
void end();
|
||||
void setClock(uint32_t);
|
||||
void beginTransmission(uint8_t address);
|
||||
void beginTransmission(int);
|
||||
uint8_t endTransmission();
|
||||
uint8_t endTransmission(uint8_t);
|
||||
uint8_t requestFrom(uint8_t address, uint8_t count);
|
||||
uint8_t requestFrom(uint8_t, uint8_t, uint8_t);
|
||||
uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t);
|
||||
size_t write(uint8_t);
|
||||
size_t write(const uint8_t *, size_t);
|
||||
int available();
|
||||
int read();
|
||||
int peek();
|
||||
void flush();
|
||||
void onReceive( void (*)(int) );
|
||||
void onRequest( void (*)(void) );
|
||||
private:
|
||||
bool verbose_;
|
||||
};
|
||||
|
||||
extern SimWire Wire;
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
|||
// This header file is in the public domain.
|
||||
|
||||
#ifndef CORE_TEENSY
|
||||
#define CORE_TEENSY
|
||||
#endif
|
||||
// This header file is in the public domain.
|
||||
|
||||
#ifndef CORE_TEENSY
|
||||
#define CORE_TEENSY
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,29 +1,29 @@
|
|||
// Font structures for newer Adafruit_GFX (1.1 and later).
|
||||
// Example fonts are included in 'Fonts' directory.
|
||||
// To use a font in your Arduino sketch, #include the corresponding .h
|
||||
// file and pass address of GFXfont struct to setFont(). Pass NULL to
|
||||
// revert to 'classic' fixed-space bitmap font.
|
||||
|
||||
#ifndef _GFXFONT_H_
|
||||
#define _GFXFONT_H_
|
||||
|
||||
/// Font data stored PER GLYPH
|
||||
typedef struct {
|
||||
uint16_t bitmapOffset; ///< Pointer into GFXfont->bitmap
|
||||
uint8_t width; ///< Bitmap dimensions in pixels
|
||||
uint8_t height; ///< Bitmap dimensions in pixels
|
||||
uint8_t xAdvance; ///< Distance to advance cursor (x axis)
|
||||
int8_t xOffset; ///< X dist from cursor pos to UL corner
|
||||
int8_t yOffset; ///< Y dist from cursor pos to UL corner
|
||||
} GFXglyph;
|
||||
|
||||
/// Data stored for FONT AS A WHOLE
|
||||
typedef struct {
|
||||
uint8_t *bitmap; ///< Glyph bitmaps, concatenated
|
||||
GFXglyph *glyph; ///< Glyph array
|
||||
uint8_t first; ///< ASCII extents (first char)
|
||||
uint8_t last; ///< ASCII extents (last char)
|
||||
uint8_t yAdvance; ///< Newline distance (y axis)
|
||||
} GFXfont;
|
||||
|
||||
#endif // _GFXFONT_H_
|
||||
// Font structures for newer Adafruit_GFX (1.1 and later).
|
||||
// Example fonts are included in 'Fonts' directory.
|
||||
// To use a font in your Arduino sketch, #include the corresponding .h
|
||||
// file and pass address of GFXfont struct to setFont(). Pass NULL to
|
||||
// revert to 'classic' fixed-space bitmap font.
|
||||
|
||||
#ifndef _GFXFONT_H_
|
||||
#define _GFXFONT_H_
|
||||
|
||||
/// Font data stored PER GLYPH
|
||||
typedef struct {
|
||||
uint16_t bitmapOffset; ///< Pointer into GFXfont->bitmap
|
||||
uint8_t width; ///< Bitmap dimensions in pixels
|
||||
uint8_t height; ///< Bitmap dimensions in pixels
|
||||
uint8_t xAdvance; ///< Distance to advance cursor (x axis)
|
||||
int8_t xOffset; ///< X dist from cursor pos to UL corner
|
||||
int8_t yOffset; ///< Y dist from cursor pos to UL corner
|
||||
} GFXglyph;
|
||||
|
||||
/// Data stored for FONT AS A WHOLE
|
||||
typedef struct {
|
||||
uint8_t *bitmap; ///< Glyph bitmaps, concatenated
|
||||
GFXglyph *glyph; ///< Glyph array
|
||||
uint8_t first; ///< ASCII extents (first char)
|
||||
uint8_t last; ///< ASCII extents (last char)
|
||||
uint8_t yAdvance; ///< Newline distance (y axis)
|
||||
} GFXfont;
|
||||
|
||||
#endif // _GFXFONT_H_
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
#ifndef __INTERRUPTS_H
|
||||
#define __INTERRUPTS_H
|
||||
|
||||
//Dummy functions, used by macros for interrupts() / noInterrupts()
|
||||
void __enable_irq() {}
|
||||
void __disable_irq() {}
|
||||
|
||||
|
||||
struct IntervalTimer
|
||||
{
|
||||
public:
|
||||
IntervalTimer() {};
|
||||
bool begin(void (*funct)(), unsigned int microseconds) { };
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
#ifndef __INTERRUPTS_H
|
||||
#define __INTERRUPTS_H
|
||||
|
||||
//Dummy functions, used by macros for interrupts() / noInterrupts()
|
||||
void __enable_irq() {}
|
||||
void __disable_irq() {}
|
||||
|
||||
|
||||
struct IntervalTimer
|
||||
{
|
||||
public:
|
||||
IntervalTimer() {};
|
||||
bool begin(void (*funct)(), unsigned int microseconds) { };
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,283 +1,283 @@
|
|||
/* Teensyduino Core Library
|
||||
* http://www.pjrc.com/teensy/
|
||||
* Copyright (c) 2017 PJRC.COM, LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* 1. The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* 2. If the Software is incorporated into a build system that allows
|
||||
* selection among a list of target devices, then similar target
|
||||
* devices manufactured by PJRC.COM must be included in the list of
|
||||
* target devices and selectable in the same manner.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef pins_macros_for_arduino_compatibility_h
|
||||
#define pins_macros_for_arduino_compatibility_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// A0-A9 are always digital 14-23, for Arduino compatibility
|
||||
#define PIN_A0 (14)
|
||||
#define PIN_A1 (15)
|
||||
#define PIN_A2 (16)
|
||||
#define PIN_A3 (17)
|
||||
#define PIN_A4 (18)
|
||||
#define PIN_A5 (19)
|
||||
#define PIN_A6 (20)
|
||||
#define PIN_A7 (21)
|
||||
#define PIN_A8 (22)
|
||||
#define PIN_A9 (23)
|
||||
const static uint8_t A0 = PIN_A0;
|
||||
const static uint8_t A1 = PIN_A1;
|
||||
const static uint8_t A2 = PIN_A2;
|
||||
const static uint8_t A3 = PIN_A3;
|
||||
const static uint8_t A4 = PIN_A4;
|
||||
const static uint8_t A5 = PIN_A5;
|
||||
const static uint8_t A6 = PIN_A6;
|
||||
const static uint8_t A7 = PIN_A7;
|
||||
const static uint8_t A8 = PIN_A8;
|
||||
const static uint8_t A9 = PIN_A9;
|
||||
|
||||
#if defined(__MK20DX128__)
|
||||
#define PIN_A10 (34)
|
||||
#define PIN_A11 (35)
|
||||
#define PIN_A12 (36)
|
||||
#define PIN_A13 (37)
|
||||
const static uint8_t A10 = PIN_A10;
|
||||
const static uint8_t A11 = PIN_A11;
|
||||
const static uint8_t A12 = PIN_A12;
|
||||
const static uint8_t A13 = PIN_A13;
|
||||
|
||||
#elif defined(__MK20DX256__)
|
||||
#define PIN_A10 (34)
|
||||
#define PIN_A11 (35)
|
||||
#define PIN_A12 (36)
|
||||
#define PIN_A13 (37)
|
||||
#define PIN_A14 (40)
|
||||
#define PIN_A15 (26)
|
||||
#define PIN_A16 (27)
|
||||
#define PIN_A17 (28)
|
||||
#define PIN_A18 (29)
|
||||
#define PIN_A19 (30)
|
||||
#define PIN_A20 (31)
|
||||
const static uint8_t A10 = PIN_A10;
|
||||
const static uint8_t A11 = PIN_A11;
|
||||
const static uint8_t A12 = PIN_A12;
|
||||
const static uint8_t A13 = PIN_A13;
|
||||
const static uint8_t A14 = PIN_A14;
|
||||
const static uint8_t A15 = PIN_A15;
|
||||
const static uint8_t A16 = PIN_A16;
|
||||
const static uint8_t A17 = PIN_A17;
|
||||
const static uint8_t A18 = PIN_A18;
|
||||
const static uint8_t A19 = PIN_A19;
|
||||
const static uint8_t A20 = PIN_A20;
|
||||
|
||||
#elif defined(__MKL26Z64__)
|
||||
#define PIN_A10 (24)
|
||||
#define PIN_A11 (25)
|
||||
#define PIN_A12 (26)
|
||||
const static uint8_t A10 = PIN_A10;
|
||||
const static uint8_t A11 = PIN_A11;
|
||||
const static uint8_t A12 = PIN_A12;
|
||||
|
||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
#define PIN_A10 (64)
|
||||
#define PIN_A11 (65)
|
||||
#define PIN_A12 (31)
|
||||
#define PIN_A13 (32)
|
||||
#define PIN_A14 (33)
|
||||
#define PIN_A15 (34)
|
||||
#define PIN_A16 (35)
|
||||
#define PIN_A17 (36)
|
||||
#define PIN_A18 (37)
|
||||
#define PIN_A19 (38)
|
||||
#define PIN_A20 (39)
|
||||
#define PIN_A21 (66)
|
||||
#define PIN_A22 (67)
|
||||
#define PIN_A23 (49)
|
||||
#define PIN_A24 (50)
|
||||
#define PIN_A25 (68)
|
||||
#define PIN_A26 (69)
|
||||
const static uint8_t A10 = PIN_A10;
|
||||
const static uint8_t A11 = PIN_A11;
|
||||
const static uint8_t A12 = PIN_A12;
|
||||
const static uint8_t A13 = PIN_A13;
|
||||
const static uint8_t A14 = PIN_A14;
|
||||
const static uint8_t A15 = PIN_A15;
|
||||
const static uint8_t A16 = PIN_A16;
|
||||
const static uint8_t A17 = PIN_A17;
|
||||
const static uint8_t A18 = PIN_A18;
|
||||
const static uint8_t A19 = PIN_A19;
|
||||
const static uint8_t A20 = PIN_A20;
|
||||
const static uint8_t A21 = PIN_A21;
|
||||
const static uint8_t A22 = PIN_A22;
|
||||
const static uint8_t A23 = PIN_A23;
|
||||
const static uint8_t A24 = PIN_A24;
|
||||
const static uint8_t A25 = PIN_A25;
|
||||
const static uint8_t A26 = PIN_A26;
|
||||
#endif
|
||||
|
||||
#define LED_BUILTIN (13)
|
||||
|
||||
#define PIN_SPI_SS (10)
|
||||
#define PIN_SPI_MOSI (11)
|
||||
#define PIN_SPI_MISO (12)
|
||||
#define PIN_SPI_SCK (13)
|
||||
const static uint8_t SS = 10;
|
||||
const static uint8_t MOSI = 11;
|
||||
const static uint8_t MISO = 12;
|
||||
const static uint8_t SCK = 13;
|
||||
|
||||
#define PIN_WIRE_SDA (18)
|
||||
#define PIN_WIRE_SCL (19)
|
||||
const static uint8_t SDA = 18;
|
||||
const static uint8_t SCL = 19;
|
||||
|
||||
#define PIN_SERIAL_RX (0)
|
||||
#define PIN_SERIAL_TX (1)
|
||||
|
||||
|
||||
#define NUM_DIGITAL_PINS CORE_NUM_DIGITAL
|
||||
#define NUM_ANALOG_INPUTS CORE_NUM_ANALOG
|
||||
|
||||
|
||||
#define NOT_AN_INTERRUPT -1
|
||||
|
||||
|
||||
#if defined(__MK20DX128__)
|
||||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) <= 13) ? (p) + 24 : -1))
|
||||
#define digitalPinHasPWM(p) (((p) >= 3 && (p) <= 6) || (p) == 9 || (p) == 10 || ((p) >= 20 && (p) <= 23))
|
||||
#define digitalPinToInterrupt(p) ((p) < NUM_DIGITAL_PINS ? (p) : -1)
|
||||
#elif defined(__MK20DX256__)
|
||||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) <= 13) ? (p) + 24 : (((p) == 14) ? 40 : (((p) <= 20) ? (p) + 11 : -1))))
|
||||
#define digitalPinHasPWM(p) (((p) >= 3 && (p) <= 6) || (p) == 9 || (p) == 10 || ((p) >= 20 && (p) <= 23) || (p) == 25 || (p) == 32)
|
||||
#define digitalPinToInterrupt(p) ((p) < NUM_DIGITAL_PINS ? (p) : -1)
|
||||
#elif defined(__MKL26Z64__)
|
||||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) <= 12) ? (p) + 14 : -1))
|
||||
#define digitalPinHasPWM(p) ((p) == 3 || (p) == 4 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 16 || (p) == 17 || (p) == 20 || (p) == 22 || (p) == 23)
|
||||
#define digitalPinToInterrupt(p) ((((p) >= 2 && (p) <= 15) || ((p) >= 20 && (p) <= 23)) ? (p) : -1)
|
||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
// TODO analogInputToDigitalPin needs update...
|
||||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) >= 12 && (p) <= 20) ? (p) + 19 : -1))
|
||||
#define digitalPinHasPWM(p) (((p) >= 2 && (p) <= 10) || (p) == 14 || ((p) >= 20 && (p) <= 23) || (p) == 29 || (p) == 30 || ((p) >= 35 && (p) <= 38))
|
||||
#define digitalPinToInterrupt(p) ((p) < NUM_DIGITAL_PINS ? (p) : -1)
|
||||
#endif
|
||||
|
||||
#define digitalPinToPCICR(p) ((volatile uint8_t *)0)
|
||||
#define digitalPinToPCICRbit(p) (0)
|
||||
#define digitalPinToPCIFR(p) ((volatile uint8_t *)0)
|
||||
#define digitalPinToPCIFRbit(p) (0)
|
||||
#define digitalPinToPCMSK(p) ((volatile uint8_t *)0)
|
||||
#define digitalPinToPCMSKbit(p) (0)
|
||||
|
||||
|
||||
#if defined(KINETISK)
|
||||
struct digital_pin_bitband_and_config_table_struct {
|
||||
volatile uint32_t *reg;
|
||||
volatile uint32_t *config;
|
||||
};
|
||||
extern const struct digital_pin_bitband_and_config_table_struct digital_pin_to_info_PGM[];
|
||||
// compatibility macros
|
||||
#define digitalPinToPort(pin) (pin)
|
||||
#define digitalPinToBitMask(pin) (1)
|
||||
#define portOutputRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 0))
|
||||
#define portSetRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 32))
|
||||
#define portClearRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 64))
|
||||
#define portToggleRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 96))
|
||||
#define portInputRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 128))
|
||||
#define portModeRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 160))
|
||||
#define portConfigRegister(pin) ((volatile uint32_t *)(digital_pin_to_info_PGM[(pin)].config))
|
||||
#define digitalPinToPortReg(pin) (portOutputRegister(pin))
|
||||
#define digitalPinToBit(pin) (1)
|
||||
|
||||
#elif defined(KINETISL)
|
||||
struct digital_pin_bitband_and_config_table_struct {
|
||||
volatile uint8_t *reg;
|
||||
volatile uint32_t *config;
|
||||
uint8_t mask;
|
||||
};
|
||||
extern const struct digital_pin_bitband_and_config_table_struct digital_pin_to_info_PGM[];
|
||||
// compatibility macros
|
||||
#define digitalPinToPort(pin) (pin)
|
||||
#define digitalPinToBitMask(pin) (digital_pin_to_info_PGM[(pin)].mask)
|
||||
#define portOutputRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 0))
|
||||
#define portSetRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 4))
|
||||
#define portClearRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 8))
|
||||
#define portToggleRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 12))
|
||||
#define portInputRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 16))
|
||||
#define portModeRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 20))
|
||||
#define portConfigRegister(pin) ((digital_pin_to_info_PGM[(pin)].config))
|
||||
#define digitalPinToPortReg(pin) (portOutputRegister(pin))
|
||||
//#define digitalPinToBit(pin) (1)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define NOT_ON_TIMER 0
|
||||
static inline uint8_t digitalPinToTimer(uint8_t) __attribute__((always_inline, unused));
|
||||
static inline uint8_t digitalPinToTimer(uint8_t pin)
|
||||
{
|
||||
if (pin >= 3 && pin <= 6) return pin - 2;
|
||||
if (pin >= 9 && pin <= 10) return pin - 4;
|
||||
if (pin >= 20 && pin <= 23) return pin - 13;
|
||||
return NOT_ON_TIMER;
|
||||
}
|
||||
|
||||
// These serial port names are intended to allow libraries and architecture-neutral
|
||||
// sketches to automatically default to the correct port name for a particular type
|
||||
// of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN,
|
||||
// the first hardware serial port whose RX/TX pins are not dedicated to another use.
|
||||
//
|
||||
// SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor
|
||||
//
|
||||
// SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial
|
||||
//
|
||||
// SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library
|
||||
//
|
||||
// SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins.
|
||||
//
|
||||
// SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX
|
||||
// pins are NOT connected to anything by default.
|
||||
//
|
||||
#if F_CPU >= 20000000 && !defined(USB_DISABLED)
|
||||
#define SERIAL_PORT_MONITOR Serial
|
||||
#else
|
||||
#define SERIAL_PORT_MONITOR Serial1
|
||||
#endif
|
||||
#define SERIAL_PORT_USBVIRTUAL Serial
|
||||
#define SERIAL_PORT_HARDWARE Serial1
|
||||
#define SERIAL_PORT_HARDWARE1 Serial2
|
||||
#define SERIAL_PORT_HARDWARE2 Serial3
|
||||
#define SERIAL_PORT_HARDWARE_OPEN Serial1
|
||||
#define SERIAL_PORT_HARDWARE_OPEN1 Serial2
|
||||
#define SERIAL_PORT_HARDWARE_OPEN2 Serial3
|
||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
#define SERIAL_PORT_HARDWARE3 Serial4
|
||||
#define SERIAL_PORT_HARDWARE4 Serial5
|
||||
#define SERIAL_PORT_HARDWARE5 Serial6
|
||||
#define SERIAL_PORT_HARDWARE_OPEN3 Serial4
|
||||
#define SERIAL_PORT_HARDWARE_OPEN4 Serial5
|
||||
#define SERIAL_PORT_HARDWARE_OPEN5 Serial6
|
||||
#endif
|
||||
|
||||
#define SerialUSB Serial
|
||||
|
||||
#endif
|
||||
/* Teensyduino Core Library
|
||||
* http://www.pjrc.com/teensy/
|
||||
* Copyright (c) 2017 PJRC.COM, LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* 1. The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* 2. If the Software is incorporated into a build system that allows
|
||||
* selection among a list of target devices, then similar target
|
||||
* devices manufactured by PJRC.COM must be included in the list of
|
||||
* target devices and selectable in the same manner.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef pins_macros_for_arduino_compatibility_h
|
||||
#define pins_macros_for_arduino_compatibility_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// A0-A9 are always digital 14-23, for Arduino compatibility
|
||||
#define PIN_A0 (14)
|
||||
#define PIN_A1 (15)
|
||||
#define PIN_A2 (16)
|
||||
#define PIN_A3 (17)
|
||||
#define PIN_A4 (18)
|
||||
#define PIN_A5 (19)
|
||||
#define PIN_A6 (20)
|
||||
#define PIN_A7 (21)
|
||||
#define PIN_A8 (22)
|
||||
#define PIN_A9 (23)
|
||||
const static uint8_t A0 = PIN_A0;
|
||||
const static uint8_t A1 = PIN_A1;
|
||||
const static uint8_t A2 = PIN_A2;
|
||||
const static uint8_t A3 = PIN_A3;
|
||||
const static uint8_t A4 = PIN_A4;
|
||||
const static uint8_t A5 = PIN_A5;
|
||||
const static uint8_t A6 = PIN_A6;
|
||||
const static uint8_t A7 = PIN_A7;
|
||||
const static uint8_t A8 = PIN_A8;
|
||||
const static uint8_t A9 = PIN_A9;
|
||||
|
||||
#if defined(__MK20DX128__)
|
||||
#define PIN_A10 (34)
|
||||
#define PIN_A11 (35)
|
||||
#define PIN_A12 (36)
|
||||
#define PIN_A13 (37)
|
||||
const static uint8_t A10 = PIN_A10;
|
||||
const static uint8_t A11 = PIN_A11;
|
||||
const static uint8_t A12 = PIN_A12;
|
||||
const static uint8_t A13 = PIN_A13;
|
||||
|
||||
#elif defined(__MK20DX256__)
|
||||
#define PIN_A10 (34)
|
||||
#define PIN_A11 (35)
|
||||
#define PIN_A12 (36)
|
||||
#define PIN_A13 (37)
|
||||
#define PIN_A14 (40)
|
||||
#define PIN_A15 (26)
|
||||
#define PIN_A16 (27)
|
||||
#define PIN_A17 (28)
|
||||
#define PIN_A18 (29)
|
||||
#define PIN_A19 (30)
|
||||
#define PIN_A20 (31)
|
||||
const static uint8_t A10 = PIN_A10;
|
||||
const static uint8_t A11 = PIN_A11;
|
||||
const static uint8_t A12 = PIN_A12;
|
||||
const static uint8_t A13 = PIN_A13;
|
||||
const static uint8_t A14 = PIN_A14;
|
||||
const static uint8_t A15 = PIN_A15;
|
||||
const static uint8_t A16 = PIN_A16;
|
||||
const static uint8_t A17 = PIN_A17;
|
||||
const static uint8_t A18 = PIN_A18;
|
||||
const static uint8_t A19 = PIN_A19;
|
||||
const static uint8_t A20 = PIN_A20;
|
||||
|
||||
#elif defined(__MKL26Z64__)
|
||||
#define PIN_A10 (24)
|
||||
#define PIN_A11 (25)
|
||||
#define PIN_A12 (26)
|
||||
const static uint8_t A10 = PIN_A10;
|
||||
const static uint8_t A11 = PIN_A11;
|
||||
const static uint8_t A12 = PIN_A12;
|
||||
|
||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
#define PIN_A10 (64)
|
||||
#define PIN_A11 (65)
|
||||
#define PIN_A12 (31)
|
||||
#define PIN_A13 (32)
|
||||
#define PIN_A14 (33)
|
||||
#define PIN_A15 (34)
|
||||
#define PIN_A16 (35)
|
||||
#define PIN_A17 (36)
|
||||
#define PIN_A18 (37)
|
||||
#define PIN_A19 (38)
|
||||
#define PIN_A20 (39)
|
||||
#define PIN_A21 (66)
|
||||
#define PIN_A22 (67)
|
||||
#define PIN_A23 (49)
|
||||
#define PIN_A24 (50)
|
||||
#define PIN_A25 (68)
|
||||
#define PIN_A26 (69)
|
||||
const static uint8_t A10 = PIN_A10;
|
||||
const static uint8_t A11 = PIN_A11;
|
||||
const static uint8_t A12 = PIN_A12;
|
||||
const static uint8_t A13 = PIN_A13;
|
||||
const static uint8_t A14 = PIN_A14;
|
||||
const static uint8_t A15 = PIN_A15;
|
||||
const static uint8_t A16 = PIN_A16;
|
||||
const static uint8_t A17 = PIN_A17;
|
||||
const static uint8_t A18 = PIN_A18;
|
||||
const static uint8_t A19 = PIN_A19;
|
||||
const static uint8_t A20 = PIN_A20;
|
||||
const static uint8_t A21 = PIN_A21;
|
||||
const static uint8_t A22 = PIN_A22;
|
||||
const static uint8_t A23 = PIN_A23;
|
||||
const static uint8_t A24 = PIN_A24;
|
||||
const static uint8_t A25 = PIN_A25;
|
||||
const static uint8_t A26 = PIN_A26;
|
||||
#endif
|
||||
|
||||
#define LED_BUILTIN (13)
|
||||
|
||||
#define PIN_SPI_SS (10)
|
||||
#define PIN_SPI_MOSI (11)
|
||||
#define PIN_SPI_MISO (12)
|
||||
#define PIN_SPI_SCK (13)
|
||||
const static uint8_t SS = 10;
|
||||
const static uint8_t MOSI = 11;
|
||||
const static uint8_t MISO = 12;
|
||||
const static uint8_t SCK = 13;
|
||||
|
||||
#define PIN_WIRE_SDA (18)
|
||||
#define PIN_WIRE_SCL (19)
|
||||
const static uint8_t SDA = 18;
|
||||
const static uint8_t SCL = 19;
|
||||
|
||||
#define PIN_SERIAL_RX (0)
|
||||
#define PIN_SERIAL_TX (1)
|
||||
|
||||
|
||||
#define NUM_DIGITAL_PINS CORE_NUM_DIGITAL
|
||||
#define NUM_ANALOG_INPUTS CORE_NUM_ANALOG
|
||||
|
||||
|
||||
#define NOT_AN_INTERRUPT -1
|
||||
|
||||
|
||||
#if defined(__MK20DX128__)
|
||||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) <= 13) ? (p) + 24 : -1))
|
||||
#define digitalPinHasPWM(p) (((p) >= 3 && (p) <= 6) || (p) == 9 || (p) == 10 || ((p) >= 20 && (p) <= 23))
|
||||
#define digitalPinToInterrupt(p) ((p) < NUM_DIGITAL_PINS ? (p) : -1)
|
||||
#elif defined(__MK20DX256__)
|
||||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) <= 13) ? (p) + 24 : (((p) == 14) ? 40 : (((p) <= 20) ? (p) + 11 : -1))))
|
||||
#define digitalPinHasPWM(p) (((p) >= 3 && (p) <= 6) || (p) == 9 || (p) == 10 || ((p) >= 20 && (p) <= 23) || (p) == 25 || (p) == 32)
|
||||
#define digitalPinToInterrupt(p) ((p) < NUM_DIGITAL_PINS ? (p) : -1)
|
||||
#elif defined(__MKL26Z64__)
|
||||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) <= 12) ? (p) + 14 : -1))
|
||||
#define digitalPinHasPWM(p) ((p) == 3 || (p) == 4 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 16 || (p) == 17 || (p) == 20 || (p) == 22 || (p) == 23)
|
||||
#define digitalPinToInterrupt(p) ((((p) >= 2 && (p) <= 15) || ((p) >= 20 && (p) <= 23)) ? (p) : -1)
|
||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
// TODO analogInputToDigitalPin needs update...
|
||||
#define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) >= 12 && (p) <= 20) ? (p) + 19 : -1))
|
||||
#define digitalPinHasPWM(p) (((p) >= 2 && (p) <= 10) || (p) == 14 || ((p) >= 20 && (p) <= 23) || (p) == 29 || (p) == 30 || ((p) >= 35 && (p) <= 38))
|
||||
#define digitalPinToInterrupt(p) ((p) < NUM_DIGITAL_PINS ? (p) : -1)
|
||||
#endif
|
||||
|
||||
#define digitalPinToPCICR(p) ((volatile uint8_t *)0)
|
||||
#define digitalPinToPCICRbit(p) (0)
|
||||
#define digitalPinToPCIFR(p) ((volatile uint8_t *)0)
|
||||
#define digitalPinToPCIFRbit(p) (0)
|
||||
#define digitalPinToPCMSK(p) ((volatile uint8_t *)0)
|
||||
#define digitalPinToPCMSKbit(p) (0)
|
||||
|
||||
|
||||
#if defined(KINETISK)
|
||||
struct digital_pin_bitband_and_config_table_struct {
|
||||
volatile uint32_t *reg;
|
||||
volatile uint32_t *config;
|
||||
};
|
||||
extern const struct digital_pin_bitband_and_config_table_struct digital_pin_to_info_PGM[];
|
||||
// compatibility macros
|
||||
#define digitalPinToPort(pin) (pin)
|
||||
#define digitalPinToBitMask(pin) (1)
|
||||
#define portOutputRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 0))
|
||||
#define portSetRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 32))
|
||||
#define portClearRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 64))
|
||||
#define portToggleRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 96))
|
||||
#define portInputRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 128))
|
||||
#define portModeRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 160))
|
||||
#define portConfigRegister(pin) ((volatile uint32_t *)(digital_pin_to_info_PGM[(pin)].config))
|
||||
#define digitalPinToPortReg(pin) (portOutputRegister(pin))
|
||||
#define digitalPinToBit(pin) (1)
|
||||
|
||||
#elif defined(KINETISL)
|
||||
struct digital_pin_bitband_and_config_table_struct {
|
||||
volatile uint8_t *reg;
|
||||
volatile uint32_t *config;
|
||||
uint8_t mask;
|
||||
};
|
||||
extern const struct digital_pin_bitband_and_config_table_struct digital_pin_to_info_PGM[];
|
||||
// compatibility macros
|
||||
#define digitalPinToPort(pin) (pin)
|
||||
#define digitalPinToBitMask(pin) (digital_pin_to_info_PGM[(pin)].mask)
|
||||
#define portOutputRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 0))
|
||||
#define portSetRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 4))
|
||||
#define portClearRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 8))
|
||||
#define portToggleRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 12))
|
||||
#define portInputRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 16))
|
||||
#define portModeRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 20))
|
||||
#define portConfigRegister(pin) ((digital_pin_to_info_PGM[(pin)].config))
|
||||
#define digitalPinToPortReg(pin) (portOutputRegister(pin))
|
||||
//#define digitalPinToBit(pin) (1)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define NOT_ON_TIMER 0
|
||||
static inline uint8_t digitalPinToTimer(uint8_t) __attribute__((always_inline, unused));
|
||||
static inline uint8_t digitalPinToTimer(uint8_t pin)
|
||||
{
|
||||
if (pin >= 3 && pin <= 6) return pin - 2;
|
||||
if (pin >= 9 && pin <= 10) return pin - 4;
|
||||
if (pin >= 20 && pin <= 23) return pin - 13;
|
||||
return NOT_ON_TIMER;
|
||||
}
|
||||
|
||||
// These serial port names are intended to allow libraries and architecture-neutral
|
||||
// sketches to automatically default to the correct port name for a particular type
|
||||
// of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN,
|
||||
// the first hardware serial port whose RX/TX pins are not dedicated to another use.
|
||||
//
|
||||
// SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor
|
||||
//
|
||||
// SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial
|
||||
//
|
||||
// SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library
|
||||
//
|
||||
// SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins.
|
||||
//
|
||||
// SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX
|
||||
// pins are NOT connected to anything by default.
|
||||
//
|
||||
#if F_CPU >= 20000000 && !defined(USB_DISABLED)
|
||||
#define SERIAL_PORT_MONITOR Serial
|
||||
#else
|
||||
#define SERIAL_PORT_MONITOR Serial1
|
||||
#endif
|
||||
#define SERIAL_PORT_USBVIRTUAL Serial
|
||||
#define SERIAL_PORT_HARDWARE Serial1
|
||||
#define SERIAL_PORT_HARDWARE1 Serial2
|
||||
#define SERIAL_PORT_HARDWARE2 Serial3
|
||||
#define SERIAL_PORT_HARDWARE_OPEN Serial1
|
||||
#define SERIAL_PORT_HARDWARE_OPEN1 Serial2
|
||||
#define SERIAL_PORT_HARDWARE_OPEN2 Serial3
|
||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
#define SERIAL_PORT_HARDWARE3 Serial4
|
||||
#define SERIAL_PORT_HARDWARE4 Serial5
|
||||
#define SERIAL_PORT_HARDWARE5 Serial6
|
||||
#define SERIAL_PORT_HARDWARE_OPEN3 Serial4
|
||||
#define SERIAL_PORT_HARDWARE_OPEN4 Serial5
|
||||
#define SERIAL_PORT_HARDWARE_OPEN5 Serial6
|
||||
#endif
|
||||
|
||||
#define SerialUSB Serial
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,35 +1,35 @@
|
|||
#ifndef __SIMUSBMIDI_H__
|
||||
#define __SIMUSBMIDI_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
class SimUsbMidi
|
||||
{
|
||||
public:
|
||||
void sendNoteOff(uint8_t note, uint8_t velocity, uint8_t channel, uint8_t cable=0);
|
||||
void sendNoteOn(uint8_t note, uint8_t velocity, uint8_t channel, uint8_t cable=0);
|
||||
void sendPolyPressure(uint8_t note, uint8_t pressure, uint8_t channel, uint8_t cable=0);
|
||||
void sendAfterTouchPoly(uint8_t note, uint8_t pressure, uint8_t channel, uint8_t cable=0);
|
||||
void sendControlChange(uint8_t control, uint8_t value, uint8_t channel, uint8_t cable=0);
|
||||
void sendProgramChange(uint8_t program, uint8_t channel, uint8_t cable=0);
|
||||
void sendAfterTouch(uint8_t pressure, uint8_t channel, uint8_t cable=0);
|
||||
void sendPitchBend(int value, uint8_t channel, uint8_t cable=0);
|
||||
void sendSysEx(uint16_t length, const uint8_t *data, bool hasTerm=false, uint8_t cable=0);
|
||||
bool read(uint8_t channel=0);
|
||||
void setHandleSystemExclusive(void (*fptr) (const uint8_t *array, unsigned int size));
|
||||
void setHandleSystemExclusive(void (*fptr) (const uint8_t *data, uint16_t length, bool complete));
|
||||
|
||||
//Things not part of Teensy USBMidi, but used to simulate sending data to it
|
||||
void receiveMidiData(const uint8_t *data, const uint16_t length); //Send midi data "into simulator"
|
||||
void setMidiFile(std::string filename); //MIDI data to send to device
|
||||
void triggerMidi(); //"Arm" so data is sent to device next time it tries to read anything
|
||||
private:
|
||||
//Handlers registered to receive MIDI
|
||||
void (*usb_midi_handleSysExPartial)(const uint8_t *data, uint16_t length, uint8_t complete);
|
||||
void (*usb_midi_handleSysExComplete)(const uint8_t *data, unsigned int size);
|
||||
std::string midiFile;
|
||||
bool sendMidi;
|
||||
};
|
||||
|
||||
|
||||
#ifndef __SIMUSBMIDI_H__
|
||||
#define __SIMUSBMIDI_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
class SimUsbMidi
|
||||
{
|
||||
public:
|
||||
void sendNoteOff(uint8_t note, uint8_t velocity, uint8_t channel, uint8_t cable=0);
|
||||
void sendNoteOn(uint8_t note, uint8_t velocity, uint8_t channel, uint8_t cable=0);
|
||||
void sendPolyPressure(uint8_t note, uint8_t pressure, uint8_t channel, uint8_t cable=0);
|
||||
void sendAfterTouchPoly(uint8_t note, uint8_t pressure, uint8_t channel, uint8_t cable=0);
|
||||
void sendControlChange(uint8_t control, uint8_t value, uint8_t channel, uint8_t cable=0);
|
||||
void sendProgramChange(uint8_t program, uint8_t channel, uint8_t cable=0);
|
||||
void sendAfterTouch(uint8_t pressure, uint8_t channel, uint8_t cable=0);
|
||||
void sendPitchBend(int value, uint8_t channel, uint8_t cable=0);
|
||||
void sendSysEx(uint16_t length, const uint8_t *data, bool hasTerm=false, uint8_t cable=0);
|
||||
bool read(uint8_t channel=0);
|
||||
void setHandleSystemExclusive(void (*fptr) (const uint8_t *array, unsigned int size));
|
||||
void setHandleSystemExclusive(void (*fptr) (const uint8_t *data, uint16_t length, bool complete));
|
||||
|
||||
//Things not part of Teensy USBMidi, but used to simulate sending data to it
|
||||
void receiveMidiData(const uint8_t *data, const uint16_t length); //Send midi data "into simulator"
|
||||
void setMidiFile(std::string filename); //MIDI data to send to device
|
||||
void triggerMidi(); //"Arm" so data is sent to device next time it tries to read anything
|
||||
private:
|
||||
//Handlers registered to receive MIDI
|
||||
void (*usb_midi_handleSysExPartial)(const uint8_t *data, uint16_t length, uint8_t complete);
|
||||
void (*usb_midi_handleSysExComplete)(const uint8_t *data, unsigned int size);
|
||||
std::string midiFile;
|
||||
bool sendMidi;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,197 +1,197 @@
|
|||
/* Teensyduino Core Library
|
||||
* http://www.pjrc.com/teensy/
|
||||
* Copyright (c) 2017 PJRC.COM, LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* 1. The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* 2. If the Software is incorporated into a build system that allows
|
||||
* selection among a list of target devices, then similar target
|
||||
* devices manufactured by PJRC.COM must be included in the list of
|
||||
* target devices and selectable in the same manner.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef Wiring_h
|
||||
#define Wiring_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
// #include "binary.h"
|
||||
#include "core_id.h"
|
||||
// #include "core_pins.h"
|
||||
|
||||
// type_traits interferes with min() and other defines
|
||||
// include it early, so we can define these later
|
||||
// for Arduino compatibility
|
||||
#ifdef __cplusplus
|
||||
#include <type_traits>
|
||||
// when the input number is an integer type, do all math as 32 bit signed long
|
||||
template <class T, class A, class B, class C, class D>
|
||||
long map(T _x, A _in_min, B _in_max, C _out_min, D _out_max, typename std::enable_if<std::is_integral<T>::value >::type* = 0)
|
||||
{
|
||||
long x = _x, in_min = _in_min, in_max = _in_max, out_min = _out_min, out_max = _out_max;
|
||||
// Arduino's traditional algorithm
|
||||
//return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
// st42's suggestion: https://github.com/arduino/Arduino/issues/2466#issuecomment-69873889
|
||||
// more conversation:
|
||||
// https://forum.pjrc.com/threads/44503-map()-function-improvements
|
||||
if ((in_max - in_min) > (out_max - out_min)) {
|
||||
return (x - in_min) * (out_max - out_min+1) / (in_max - in_min+1) + out_min;
|
||||
} else {
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
}
|
||||
// when the input is a float or double, do all math using the input's type
|
||||
template <class T, class A, class B, class C, class D>
|
||||
T map(T x, A in_min, B in_max, C out_min, D out_max, typename std::enable_if<std::is_floating_point<T>::value >::type* = 0)
|
||||
{
|
||||
return (x - (T)in_min) * ((T)out_max - (T)out_min) / ((T)in_max - (T)in_min) + (T)out_min;
|
||||
}
|
||||
//#include <algorithm> // this isn't really needed, is it? (slows down compiling)
|
||||
#include <utility>
|
||||
// https://forum.pjrc.com/threads/44596-Teensyduino-1-37-Beta-2-(Arduino-1-8-3-support)?p=145150&viewfull=1#post145150
|
||||
template<class A, class B>
|
||||
constexpr auto min(A&& a, B&& b) -> decltype(a < b ? std::forward<A>(a) : std::forward<B>(b)) {
|
||||
return a < b ? std::forward<A>(a) : std::forward<B>(b);
|
||||
}
|
||||
template<class A, class B>
|
||||
constexpr auto max(A&& a, B&& b) -> decltype(a < b ? std::forward<A>(a) : std::forward<B>(b)) {
|
||||
return a >= b ? std::forward<A>(a) : std::forward<B>(b);
|
||||
}
|
||||
#else // not C++
|
||||
#define min(a, b) ({ \
|
||||
typeof(a) _a = (a); \
|
||||
typeof(b) _b = (b); \
|
||||
(_a < _b) ? _a : _b; \
|
||||
})
|
||||
#define max(a, b) ({ \
|
||||
typeof(a) _a = (a); \
|
||||
typeof(b) _b = (b); \
|
||||
(_a > _b) ? _a : _b; \
|
||||
})
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PI
|
||||
#undef PI
|
||||
#endif
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define HALF_PI 1.5707963267948966192313216916398
|
||||
#define TWO_PI 6.283185307179586476925286766559
|
||||
#define DEG_TO_RAD 0.017453292519943295769236907684886
|
||||
#define RAD_TO_DEG 57.295779513082320876798154814105
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433832795
|
||||
#endif
|
||||
#ifndef M_SQRT2
|
||||
#define M_SQRT2 1.4142135623730950488016887
|
||||
#endif
|
||||
|
||||
#define SERIAL 0
|
||||
#define DISPLAY 1
|
||||
|
||||
// undefine stdlib's abs if encountered
|
||||
#ifdef abs
|
||||
#undef abs
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201103L && defined(__STRICT_ANSI__)
|
||||
#define typeof(a) decltype(a)
|
||||
#endif
|
||||
|
||||
#define abs(x) ({ \
|
||||
typeof(x) _x = (x); \
|
||||
(_x > 0) ? _x : -_x; \
|
||||
})
|
||||
#define constrain(amt, low, high) ({ \
|
||||
typeof(amt) _amt = (amt); \
|
||||
typeof(low) _low = (low); \
|
||||
typeof(high) _high = (high); \
|
||||
(_amt < _low) ? _low : ((_amt > _high) ? _high : _amt); \
|
||||
})
|
||||
#define round(x) ({ \
|
||||
typeof(x) _x = (x); \
|
||||
(_x>=0) ? (long)(_x+0.5) : (long)(_x-0.5); \
|
||||
})
|
||||
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||
#define sq(x) ({ \
|
||||
typeof(x) _x = (x); \
|
||||
_x * _x; \
|
||||
})
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
extern double exp10(double x);
|
||||
extern float exp10f(float x);
|
||||
extern long double exp10l(long double x);
|
||||
extern double pow10(double x);
|
||||
extern float pow10f(float x);
|
||||
extern long double pow10l(long double x);
|
||||
|
||||
#define stricmp(a, b) strcasecmp(a, b)
|
||||
|
||||
#define sei() __enable_irq()
|
||||
#define cli() __disable_irq()
|
||||
#define interrupts() __enable_irq()
|
||||
#define noInterrupts() __disable_irq()
|
||||
|
||||
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
|
||||
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
|
||||
#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
|
||||
|
||||
#define lowByte(w) ((uint8_t)((w) & 0xFF))
|
||||
#define highByte(w) ((uint8_t)((w) >> 8))
|
||||
|
||||
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
|
||||
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
|
||||
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
|
||||
#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet((value), (bit)) : bitClear((value), (bit)))
|
||||
|
||||
typedef unsigned int word;
|
||||
|
||||
#define bit(b) (1UL << (b))
|
||||
|
||||
typedef uint8_t byte;
|
||||
|
||||
uint32_t pulseIn(uint8_t pin, uint8_t state, uint32_t timeout);
|
||||
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, byte val);
|
||||
|
||||
void setup(void);
|
||||
void loop(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
// fix C++ boolean issue
|
||||
// https://github.com/arduino/Arduino/pull/2151
|
||||
#ifdef __cplusplus
|
||||
typedef bool boolean;
|
||||
#else
|
||||
typedef uint8_t boolean;
|
||||
#define false 0
|
||||
#define true (!false)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* Teensyduino Core Library
|
||||
* http://www.pjrc.com/teensy/
|
||||
* Copyright (c) 2017 PJRC.COM, LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* 1. The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* 2. If the Software is incorporated into a build system that allows
|
||||
* selection among a list of target devices, then similar target
|
||||
* devices manufactured by PJRC.COM must be included in the list of
|
||||
* target devices and selectable in the same manner.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef Wiring_h
|
||||
#define Wiring_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
// #include "binary.h"
|
||||
#include "core_id.h"
|
||||
// #include "core_pins.h"
|
||||
|
||||
// type_traits interferes with min() and other defines
|
||||
// include it early, so we can define these later
|
||||
// for Arduino compatibility
|
||||
#ifdef __cplusplus
|
||||
#include <type_traits>
|
||||
// when the input number is an integer type, do all math as 32 bit signed long
|
||||
template <class T, class A, class B, class C, class D>
|
||||
long map(T _x, A _in_min, B _in_max, C _out_min, D _out_max, typename std::enable_if<std::is_integral<T>::value >::type* = 0)
|
||||
{
|
||||
long x = _x, in_min = _in_min, in_max = _in_max, out_min = _out_min, out_max = _out_max;
|
||||
// Arduino's traditional algorithm
|
||||
//return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
// st42's suggestion: https://github.com/arduino/Arduino/issues/2466#issuecomment-69873889
|
||||
// more conversation:
|
||||
// https://forum.pjrc.com/threads/44503-map()-function-improvements
|
||||
if ((in_max - in_min) > (out_max - out_min)) {
|
||||
return (x - in_min) * (out_max - out_min+1) / (in_max - in_min+1) + out_min;
|
||||
} else {
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
}
|
||||
// when the input is a float or double, do all math using the input's type
|
||||
template <class T, class A, class B, class C, class D>
|
||||
T map(T x, A in_min, B in_max, C out_min, D out_max, typename std::enable_if<std::is_floating_point<T>::value >::type* = 0)
|
||||
{
|
||||
return (x - (T)in_min) * ((T)out_max - (T)out_min) / ((T)in_max - (T)in_min) + (T)out_min;
|
||||
}
|
||||
//#include <algorithm> // this isn't really needed, is it? (slows down compiling)
|
||||
#include <utility>
|
||||
// https://forum.pjrc.com/threads/44596-Teensyduino-1-37-Beta-2-(Arduino-1-8-3-support)?p=145150&viewfull=1#post145150
|
||||
template<class A, class B>
|
||||
constexpr auto min(A&& a, B&& b) -> decltype(a < b ? std::forward<A>(a) : std::forward<B>(b)) {
|
||||
return a < b ? std::forward<A>(a) : std::forward<B>(b);
|
||||
}
|
||||
template<class A, class B>
|
||||
constexpr auto max(A&& a, B&& b) -> decltype(a < b ? std::forward<A>(a) : std::forward<B>(b)) {
|
||||
return a >= b ? std::forward<A>(a) : std::forward<B>(b);
|
||||
}
|
||||
#else // not C++
|
||||
#define min(a, b) ({ \
|
||||
typeof(a) _a = (a); \
|
||||
typeof(b) _b = (b); \
|
||||
(_a < _b) ? _a : _b; \
|
||||
})
|
||||
#define max(a, b) ({ \
|
||||
typeof(a) _a = (a); \
|
||||
typeof(b) _b = (b); \
|
||||
(_a > _b) ? _a : _b; \
|
||||
})
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PI
|
||||
#undef PI
|
||||
#endif
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define HALF_PI 1.5707963267948966192313216916398
|
||||
#define TWO_PI 6.283185307179586476925286766559
|
||||
#define DEG_TO_RAD 0.017453292519943295769236907684886
|
||||
#define RAD_TO_DEG 57.295779513082320876798154814105
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433832795
|
||||
#endif
|
||||
#ifndef M_SQRT2
|
||||
#define M_SQRT2 1.4142135623730950488016887
|
||||
#endif
|
||||
|
||||
#define SERIAL 0
|
||||
#define DISPLAY 1
|
||||
|
||||
// undefine stdlib's abs if encountered
|
||||
#ifdef abs
|
||||
#undef abs
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201103L && defined(__STRICT_ANSI__)
|
||||
#define typeof(a) decltype(a)
|
||||
#endif
|
||||
|
||||
#define abs(x) ({ \
|
||||
typeof(x) _x = (x); \
|
||||
(_x > 0) ? _x : -_x; \
|
||||
})
|
||||
#define constrain(amt, low, high) ({ \
|
||||
typeof(amt) _amt = (amt); \
|
||||
typeof(low) _low = (low); \
|
||||
typeof(high) _high = (high); \
|
||||
(_amt < _low) ? _low : ((_amt > _high) ? _high : _amt); \
|
||||
})
|
||||
#define round(x) ({ \
|
||||
typeof(x) _x = (x); \
|
||||
(_x>=0) ? (long)(_x+0.5) : (long)(_x-0.5); \
|
||||
})
|
||||
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||
#define sq(x) ({ \
|
||||
typeof(x) _x = (x); \
|
||||
_x * _x; \
|
||||
})
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
extern double exp10(double x);
|
||||
extern float exp10f(float x);
|
||||
extern long double exp10l(long double x);
|
||||
extern double pow10(double x);
|
||||
extern float pow10f(float x);
|
||||
extern long double pow10l(long double x);
|
||||
|
||||
#define stricmp(a, b) strcasecmp(a, b)
|
||||
|
||||
#define sei() __enable_irq()
|
||||
#define cli() __disable_irq()
|
||||
#define interrupts() __enable_irq()
|
||||
#define noInterrupts() __disable_irq()
|
||||
|
||||
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
|
||||
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
|
||||
#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
|
||||
|
||||
#define lowByte(w) ((uint8_t)((w) & 0xFF))
|
||||
#define highByte(w) ((uint8_t)((w) >> 8))
|
||||
|
||||
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
|
||||
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
|
||||
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
|
||||
#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet((value), (bit)) : bitClear((value), (bit)))
|
||||
|
||||
typedef unsigned int word;
|
||||
|
||||
#define bit(b) (1UL << (b))
|
||||
|
||||
typedef uint8_t byte;
|
||||
|
||||
uint32_t pulseIn(uint8_t pin, uint8_t state, uint32_t timeout);
|
||||
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, byte val);
|
||||
|
||||
void setup(void);
|
||||
void loop(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
// fix C++ boolean issue
|
||||
// https://github.com/arduino/Arduino/pull/2151
|
||||
#ifdef __cplusplus
|
||||
typedef bool boolean;
|
||||
#else
|
||||
typedef uint8_t boolean;
|
||||
#define false 0
|
||||
#define true (!false)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,22 +1,22 @@
|
|||
# Simulator for NuEVI
|
||||
|
||||
This is a simple SDL2 based simulator that runs the NuEVI firmware compiled for MacOS. This is for testing the menu and is not supposed to produce any midi events.
|
||||
|
||||
## Requirements
|
||||
|
||||
* The Filters library must be installed in ~/Documents/Arduino/libraries/Filters.
|
||||
* [SDL2.framework](https://www.libsdl.org/download-2.0.php) must be installed on your machine in /Library/Frameworks/ (or ~/Library/Frameworks/).
|
||||
* You probably need to have XCode and XCodes command line tools installed as well, but using brew to install make and clang might be enough.
|
||||
|
||||
[Dear Imgui](https://github.com/ocornut/imgui) is pulled in as an git submodule. Run `git submodule init` and `git submodule update` to get the code. The code is tested with tag v1.70 of ImGui, so if you run into problems make sure that is the checked out version.
|
||||
|
||||
## Know limitations
|
||||
|
||||
Currently only some input is simulated, and the default values are not based on real hardware. There is also a limitation on some keyboards on how many buttons can be pressed at the same time. This means that all menu functions cannot be tested.
|
||||
|
||||
## Future plans
|
||||
|
||||
* Add simulation for all inputs
|
||||
* Show MIDI status in UI
|
||||
* Add in-app log window
|
||||
* Fake real breath input by keypress
|
||||
# Simulator for NuEVI
|
||||
|
||||
This is a simple SDL2 based simulator that runs the NuEVI firmware compiled for MacOS. This is for testing the menu and is not supposed to produce any midi events.
|
||||
|
||||
## Requirements
|
||||
|
||||
* The Filters library must be installed in ~/Documents/Arduino/libraries/Filters.
|
||||
* [SDL2.framework](https://www.libsdl.org/download-2.0.php) must be installed on your machine in /Library/Frameworks/ (or ~/Library/Frameworks/).
|
||||
* You probably need to have XCode and XCodes command line tools installed as well, but using brew to install make and clang might be enough.
|
||||
|
||||
[Dear Imgui](https://github.com/ocornut/imgui) is pulled in as an git submodule. Run `git submodule init` and `git submodule update` to get the code. The code is tested with tag v1.70 of ImGui, so if you run into problems make sure that is the checked out version.
|
||||
|
||||
## Know limitations
|
||||
|
||||
Currently only some input is simulated, and the default values are not based on real hardware. There is also a limitation on some keyboards on how many buttons can be pressed at the same time. This means that all menu functions cannot be tested.
|
||||
|
||||
## Future plans
|
||||
|
||||
* Add simulation for all inputs
|
||||
* Show MIDI status in UI
|
||||
* Add in-app log window
|
||||
* Fake real breath input by keypress
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,170 +1,170 @@
|
|||
/*!
|
||||
* @file Adafruit_MPR121.cpp
|
||||
*
|
||||
* @mainpage Adafruit MPR121 arduino driver
|
||||
*
|
||||
* @section intro_sec Introduction
|
||||
*
|
||||
This is a library for the MPR121 I2C 12-chan Capacitive Sensor
|
||||
|
||||
Designed specifically to work with the MPR121 sensor from Adafruit
|
||||
----> https://www.adafruit.com/products/1982
|
||||
|
||||
These sensors use I2C to communicate, 2+ pins are required to
|
||||
interface
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
*
|
||||
* @section author Author
|
||||
*
|
||||
* Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
*
|
||||
* @section license License
|
||||
*
|
||||
* BSD license, all text here must be included in any redistribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Adafruit_MPR121.h"
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Default constructor
|
||||
****************************************************************************************/
|
||||
Adafruit_MPR121::Adafruit_MPR121() {
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Begin an MPR121 object on a given I2C bus. This function resets the
|
||||
* device and writes the default settings.
|
||||
*
|
||||
* @param i2caddr the i2c address the device can be found on. Defaults to 0x5A.
|
||||
* @returns true on success, false otherwise
|
||||
****************************************************************************************/
|
||||
boolean Adafruit_MPR121::begin(uint8_t i2caddr) {
|
||||
_i2caddr = i2caddr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief DEPRECATED. Use Adafruit_MPR121::setThresholds(uint8_t touch, uint8_t release) instead.
|
||||
*
|
||||
* @param touch see Adafruit_MPR121::setThresholds(uint8_t touch, uint8_t release)
|
||||
* @param release see Adafruit_MPR121::setThresholds(uint8_t touch, uint8_t release)
|
||||
****************************************************************************************/
|
||||
void Adafruit_MPR121::setThreshholds(uint8_t __attribute__((unused)) touch, uint8_t __attribute__((unused)) release) {
|
||||
// setThresholds(touch, release);
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Set the touch and release thresholds for all 13 channels on the device to the
|
||||
* passed values. The threshold is defined as a deviation value from the baseline value,
|
||||
* so it remains constant even baseline value changes. Typically the touch
|
||||
* threshold is a little bigger than the release threshold to touch debounce and hysteresis.
|
||||
*
|
||||
* For typical touch application, the value can be in range 0x05~0x30 for example. The setting
|
||||
* of the threshold is depended on the actual application. For the operation details and how to set the threshold refer to
|
||||
* application note AN3892 and MPR121 design guidelines.
|
||||
*
|
||||
* @param touch the touch threshold value from 0 to 255.
|
||||
* @param release the release threshold from 0 to 255.
|
||||
****************************************************************************************/
|
||||
void Adafruit_MPR121::setThresholds(uint8_t __attribute__((unused)) touch, __attribute__((unused)) uint8_t release) {
|
||||
// for (uint8_t i=0; i<12; i++) {
|
||||
// writeRegister(MPR121_TOUCHTH_0 + 2*i, touch);
|
||||
// writeRegister(MPR121_RELEASETH_0 + 2*i, release);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Read the filtered data from channel t. The ADC raw data outputs run through 3
|
||||
* levels of digital filtering to filter out the high frequency and low frequency noise
|
||||
* encountered. For detailed information on this filtering see page 6 of the device datasheet.
|
||||
*
|
||||
* @param t the channel to read
|
||||
* @returns the filtered reading as a 10 bit unsigned value
|
||||
****************************************************************************************/
|
||||
uint16_t Adafruit_MPR121::filteredData(uint8_t t) {
|
||||
if (t > 12) return 0;
|
||||
return readRegister16(MPR121_FILTDATA_0L + t*2);
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Read the baseline value for the channel. The 3rd level filtered result is internally 10bit
|
||||
* but only high 8 bits are readable from registers 0x1E~0x2A as the baseline value output for each channel.
|
||||
*
|
||||
* @param t the channel to read.
|
||||
* @returns the baseline data that was read
|
||||
****************************************************************************************/
|
||||
uint16_t Adafruit_MPR121::baselineData(uint8_t t) {
|
||||
if (t > 12) return 0;
|
||||
uint16_t bl = readRegister8(MPR121_BASELINE_0 + t);
|
||||
return (bl << 2);
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Read the touch status of all 13 channels as bit values in a 12 bit integer.
|
||||
*
|
||||
* @returns a 12 bit integer with each bit corresponding to the touch status of a sensor.
|
||||
* For example, if bit 0 is set then channel 0 of the device is currently deemed to be touched.
|
||||
****************************************************************************************/
|
||||
uint16_t Adafruit_MPR121::touched(void) {
|
||||
uint16_t t = readRegister16(MPR121_TOUCHSTATUS_L);
|
||||
return t & 0x0FFF;
|
||||
}
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Read the contents of an 8 bit device register.
|
||||
*
|
||||
* @param reg the register address to read from
|
||||
* @returns the 8 bit value that was read.
|
||||
****************************************************************************************/
|
||||
uint8_t Adafruit_MPR121::readRegister8(uint8_t reg) {
|
||||
return this->_registers[reg];
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Read the contents of a 16 bit device register.
|
||||
*
|
||||
* @param reg the register address to read from
|
||||
* @returns the 16 bit value that was read.
|
||||
****************************************************************************************/
|
||||
uint16_t Adafruit_MPR121::readRegister16(uint8_t reg) {
|
||||
return _registers[reg] | (_registers[reg+1] << 8);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Writes 8-bits to the specified destination register
|
||||
|
||||
@param reg the register address to write to
|
||||
@param value the value to write
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_MPR121::writeRegister(uint8_t reg, uint8_t value) {
|
||||
|
||||
_registers[reg] = value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Simulator specifics code..
|
||||
*/
|
||||
|
||||
|
||||
void Adafruit_MPR121::mockFilteredData(int reg, uint16_t value) {
|
||||
_registers[MPR121_FILTDATA_0L + reg*2] = value & 0xffu;
|
||||
_registers[MPR121_FILTDATA_0L + reg*2+1] = (value>>8) & 0xffu;
|
||||
}
|
||||
/*!
|
||||
* @file Adafruit_MPR121.cpp
|
||||
*
|
||||
* @mainpage Adafruit MPR121 arduino driver
|
||||
*
|
||||
* @section intro_sec Introduction
|
||||
*
|
||||
This is a library for the MPR121 I2C 12-chan Capacitive Sensor
|
||||
|
||||
Designed specifically to work with the MPR121 sensor from Adafruit
|
||||
----> https://www.adafruit.com/products/1982
|
||||
|
||||
These sensors use I2C to communicate, 2+ pins are required to
|
||||
interface
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
*
|
||||
* @section author Author
|
||||
*
|
||||
* Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
*
|
||||
* @section license License
|
||||
*
|
||||
* BSD license, all text here must be included in any redistribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Adafruit_MPR121.h"
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Default constructor
|
||||
****************************************************************************************/
|
||||
Adafruit_MPR121::Adafruit_MPR121() {
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Begin an MPR121 object on a given I2C bus. This function resets the
|
||||
* device and writes the default settings.
|
||||
*
|
||||
* @param i2caddr the i2c address the device can be found on. Defaults to 0x5A.
|
||||
* @returns true on success, false otherwise
|
||||
****************************************************************************************/
|
||||
boolean Adafruit_MPR121::begin(uint8_t i2caddr) {
|
||||
_i2caddr = i2caddr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief DEPRECATED. Use Adafruit_MPR121::setThresholds(uint8_t touch, uint8_t release) instead.
|
||||
*
|
||||
* @param touch see Adafruit_MPR121::setThresholds(uint8_t touch, uint8_t release)
|
||||
* @param release see Adafruit_MPR121::setThresholds(uint8_t touch, uint8_t release)
|
||||
****************************************************************************************/
|
||||
void Adafruit_MPR121::setThreshholds(uint8_t __attribute__((unused)) touch, uint8_t __attribute__((unused)) release) {
|
||||
// setThresholds(touch, release);
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Set the touch and release thresholds for all 13 channels on the device to the
|
||||
* passed values. The threshold is defined as a deviation value from the baseline value,
|
||||
* so it remains constant even baseline value changes. Typically the touch
|
||||
* threshold is a little bigger than the release threshold to touch debounce and hysteresis.
|
||||
*
|
||||
* For typical touch application, the value can be in range 0x05~0x30 for example. The setting
|
||||
* of the threshold is depended on the actual application. For the operation details and how to set the threshold refer to
|
||||
* application note AN3892 and MPR121 design guidelines.
|
||||
*
|
||||
* @param touch the touch threshold value from 0 to 255.
|
||||
* @param release the release threshold from 0 to 255.
|
||||
****************************************************************************************/
|
||||
void Adafruit_MPR121::setThresholds(uint8_t __attribute__((unused)) touch, __attribute__((unused)) uint8_t release) {
|
||||
// for (uint8_t i=0; i<12; i++) {
|
||||
// writeRegister(MPR121_TOUCHTH_0 + 2*i, touch);
|
||||
// writeRegister(MPR121_RELEASETH_0 + 2*i, release);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Read the filtered data from channel t. The ADC raw data outputs run through 3
|
||||
* levels of digital filtering to filter out the high frequency and low frequency noise
|
||||
* encountered. For detailed information on this filtering see page 6 of the device datasheet.
|
||||
*
|
||||
* @param t the channel to read
|
||||
* @returns the filtered reading as a 10 bit unsigned value
|
||||
****************************************************************************************/
|
||||
uint16_t Adafruit_MPR121::filteredData(uint8_t t) {
|
||||
if (t > 12) return 0;
|
||||
return readRegister16(MPR121_FILTDATA_0L + t*2);
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Read the baseline value for the channel. The 3rd level filtered result is internally 10bit
|
||||
* but only high 8 bits are readable from registers 0x1E~0x2A as the baseline value output for each channel.
|
||||
*
|
||||
* @param t the channel to read.
|
||||
* @returns the baseline data that was read
|
||||
****************************************************************************************/
|
||||
uint16_t Adafruit_MPR121::baselineData(uint8_t t) {
|
||||
if (t > 12) return 0;
|
||||
uint16_t bl = readRegister8(MPR121_BASELINE_0 + t);
|
||||
return (bl << 2);
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Read the touch status of all 13 channels as bit values in a 12 bit integer.
|
||||
*
|
||||
* @returns a 12 bit integer with each bit corresponding to the touch status of a sensor.
|
||||
* For example, if bit 0 is set then channel 0 of the device is currently deemed to be touched.
|
||||
****************************************************************************************/
|
||||
uint16_t Adafruit_MPR121::touched(void) {
|
||||
uint16_t t = readRegister16(MPR121_TOUCHSTATUS_L);
|
||||
return t & 0x0FFF;
|
||||
}
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Read the contents of an 8 bit device register.
|
||||
*
|
||||
* @param reg the register address to read from
|
||||
* @returns the 8 bit value that was read.
|
||||
****************************************************************************************/
|
||||
uint8_t Adafruit_MPR121::readRegister8(uint8_t reg) {
|
||||
return this->_registers[reg];
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************************
|
||||
* @brief Read the contents of a 16 bit device register.
|
||||
*
|
||||
* @param reg the register address to read from
|
||||
* @returns the 16 bit value that was read.
|
||||
****************************************************************************************/
|
||||
uint16_t Adafruit_MPR121::readRegister16(uint8_t reg) {
|
||||
return _registers[reg] | (_registers[reg+1] << 8);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Writes 8-bits to the specified destination register
|
||||
|
||||
@param reg the register address to write to
|
||||
@param value the value to write
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_MPR121::writeRegister(uint8_t reg, uint8_t value) {
|
||||
|
||||
_registers[reg] = value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Simulator specifics code..
|
||||
*/
|
||||
|
||||
|
||||
void Adafruit_MPR121::mockFilteredData(int reg, uint16_t value) {
|
||||
_registers[MPR121_FILTDATA_0L + reg*2] = value & 0xffu;
|
||||
_registers[MPR121_FILTDATA_0L + reg*2+1] = (value>>8) & 0xffu;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,337 +1,337 @@
|
|||
/* Teensyduino Core Library
|
||||
* http://www.pjrc.com/teensy/
|
||||
* Copyright (c) 2017 PJRC.COM, LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* 1. The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* 2. If the Software is incorporated into a build system that allows
|
||||
* selection among a list of target devices, then similar target
|
||||
* devices manufactured by PJRC.COM must be included in the list of
|
||||
* target devices and selectable in the same manner.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
// Long ago this file contained code from Arduino.cc, which was
|
||||
// Copyright (c) 2008 David A. Mellis. No substantial portion of
|
||||
// Arduino's original code remains. In fact, several improvements
|
||||
// developed for Teensyduino have made their way back into
|
||||
// Arduino's code base. :-)
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "Print.h"
|
||||
|
||||
|
||||
size_t Print::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
size_t count = 0;
|
||||
while (size--) count += write(*buffer++);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
// size_t Print::print(const String &s)
|
||||
// {
|
||||
// uint8_t buffer[33];
|
||||
// size_t count = 0;
|
||||
// unsigned int index = 0;
|
||||
// unsigned int len = s.length();
|
||||
// while (len > 0) {
|
||||
// s.getBytes(buffer, sizeof(buffer), index);
|
||||
// unsigned int nbytes = len;
|
||||
// if (nbytes > sizeof(buffer)-1) nbytes = sizeof(buffer)-1;
|
||||
// index += nbytes;
|
||||
// len -= nbytes;
|
||||
// count += write(buffer, nbytes);
|
||||
// }
|
||||
// return count;
|
||||
// }
|
||||
|
||||
|
||||
size_t Print::print(long n)
|
||||
{
|
||||
uint8_t sign=0;
|
||||
|
||||
if (n < 0) {
|
||||
sign = '-';
|
||||
n = -n;
|
||||
}
|
||||
return printNumber(n, 10, sign);
|
||||
}
|
||||
|
||||
|
||||
size_t Print::println(void)
|
||||
{
|
||||
uint8_t buf[2]={'\r', '\n'};
|
||||
return write(buf, 2);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
__attribute__((weak))
|
||||
int _write(long file, char *ptr, int len)
|
||||
{
|
||||
((class Print *)file)->write((uint8_t *)ptr, len);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
int Print::printf(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
#ifdef __STRICT_ANSI__
|
||||
return 0; // TODO: make this work with -std=c++0x
|
||||
#else
|
||||
return vdprintf((int)this, format, ap);
|
||||
#endif
|
||||
}
|
||||
|
||||
int Print::printf(const __FlashStringHelper *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
#ifdef __STRICT_ANSI__
|
||||
return 0;
|
||||
#else
|
||||
return vdprintf((int)this, (const char *)format, ap);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __MKL26Z64__
|
||||
|
||||
// optimized code inspired by Stimmer's optimization
|
||||
// obviously a dit different, adapted to 32 bit Cortex-M0+
|
||||
// http://forum.arduino.cc/index.php?topic=167414.msg1293679#msg1293679
|
||||
// http://forum.arduino.cc/index.php?topic=167414.msg1309482#msg1309482
|
||||
// equivelant code:
|
||||
// mod = div % 10;
|
||||
// div = div / 10;
|
||||
// tmp1 = {random};
|
||||
// tmp2 = 10;
|
||||
#if 1
|
||||
// https://forum.pjrc.com/threads/28932-LC-is-10-9-times-slower-than-T3-1?p=76072&viewfull=1#post76072
|
||||
void inline divmod10_v2(uint32_t n,uint32_t *div,uint32_t *mod) {
|
||||
uint32_t p,q;
|
||||
/* Using 32.16 fixed point representation p.q */
|
||||
/* p.q = (n+1)/512 */
|
||||
q = (n&0xFFFF) + 1;
|
||||
p = (n>>16);
|
||||
/* p.q = 51*(n+1)/512 */
|
||||
q = 13107*q;
|
||||
p = 13107*p;
|
||||
/* p.q = (1+1/2^8+1/2^16+1/2^24)*51*(n+1)/512 */
|
||||
q = q + (q>>16) + (p&0xFFFF);
|
||||
p = p + (p>>16) + (q>>16);
|
||||
/* divide by 2 */
|
||||
p = p>>1;
|
||||
*div = p;
|
||||
*mod = n-10*p;
|
||||
}
|
||||
#define divmod10_asm(div, mod, tmp1, tmp2, const3333) \
|
||||
divmod10_v2(div, &div, &mod);
|
||||
/*
|
||||
#define divmod10_asm(div, mod, tmp1, tmp2, const3333) \
|
||||
asm ( \
|
||||
" lsr %2, %0, #16" "\n\t" \
|
||||
" mul %2, %4" "\n\t" \
|
||||
" uxth %1, %0" "\n\t" \
|
||||
" mul %1, %4" "\n\t" \
|
||||
" add %1, #1" "\n\t" \
|
||||
" lsr %0, %2, #16" "\n\t" \
|
||||
" lsl %2, %2, #16" "\n\t" \
|
||||
" add %1, %2" "\n\t" \
|
||||
" mov %3, #0" "\n\t" \
|
||||
" adc %0, %3" "\n\t" \
|
||||
" lsl %0, %0, #15" "\n\t" \
|
||||
" lsr %2, %1, #17" "\n\t" \
|
||||
" orr %0, %2" "\n\t" \
|
||||
" lsl %1, %1, #15" "\n\t" \
|
||||
" lsr %2, %1, #16" "\n\t" \
|
||||
" lsl %3, %0, #16" "\n\t" \
|
||||
" orr %2, %3" "\n\t" \
|
||||
" lsr %3, %0, #16" "\n\t" \
|
||||
" add %1, %0" "\n\t" \
|
||||
" adc %0, %1" "\n\t" \
|
||||
" sub %0, %1" "\n\t" \
|
||||
" add %1, %2" "\n\t" \
|
||||
" adc %0, %3" "\n\t" \
|
||||
" lsr %1, %1, #4" "\n\t" \
|
||||
" mov %3, #10" "\n\t" \
|
||||
" mul %1, %3" "\n\t" \
|
||||
" lsr %1, %1, #28" "\n\t" \
|
||||
: "+l" (div), \
|
||||
"=&l" (mod), \
|
||||
"=&l" (tmp1), \
|
||||
"=&l" (tmp2) \
|
||||
: "l" (const3333) \
|
||||
: \
|
||||
)
|
||||
*/
|
||||
#else
|
||||
#define divmod10_asm(_div, _mod, _tmp1, _tmp2, _const3333) \
|
||||
({ _tmp1 = _div; _div = _div / 10; _mod = _tmp1 - _div * 10; })
|
||||
// ({_mod = _div % 10, _div = _div / 10; })
|
||||
#endif
|
||||
|
||||
|
||||
size_t Print::printNumberDec(unsigned long n, uint8_t sign)
|
||||
{
|
||||
uint8_t buf[11], *p;
|
||||
uint32_t digit;
|
||||
//uint32_t t1, t2, c3333=0x3333;
|
||||
|
||||
p = buf + (sizeof(buf));
|
||||
do {
|
||||
uint32_t div;
|
||||
divmod10_v2(n, &div, &digit);
|
||||
n = div;
|
||||
//divmod10_asm(n, digit, t1, t2, c3333);
|
||||
*--p = digit + '0';
|
||||
} while (n);
|
||||
if (sign) *--p = '-';
|
||||
return write(p, sizeof(buf) - (p - buf));
|
||||
}
|
||||
|
||||
size_t Print::printNumberHex(unsigned long n)
|
||||
{
|
||||
uint8_t digit, buf[8], *p;
|
||||
|
||||
p = buf + (sizeof(buf));
|
||||
do {
|
||||
digit = n & 15;
|
||||
*--p = (digit < 10) ? '0' + digit : 'A' + digit - 10;
|
||||
n >>= 4;
|
||||
} while (n);
|
||||
return write(p, sizeof(buf) - (p - buf));
|
||||
}
|
||||
|
||||
size_t Print::printNumberBin(unsigned long n)
|
||||
{
|
||||
uint8_t buf[32], *p;
|
||||
|
||||
p = buf + (sizeof(buf));
|
||||
do {
|
||||
*--p = '0' + ((uint8_t)n & 1);
|
||||
n >>= 1;
|
||||
} while (n);
|
||||
return write(p, sizeof(buf) - (p - buf));
|
||||
}
|
||||
|
||||
size_t Print::printNumberAny(unsigned long n, uint8_t base)
|
||||
{
|
||||
uint8_t digit, buf[21], *p;
|
||||
uint32_t tmp;
|
||||
|
||||
p = buf + sizeof(buf);
|
||||
do {
|
||||
tmp = n;
|
||||
n = n / base;
|
||||
digit = tmp - n * base;
|
||||
*--p = (digit < 10) ? '0' + digit : 'A' + digit - 10;
|
||||
} while (n);
|
||||
return write(p, sizeof(buf) - (p - buf));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
size_t Print::printNumber(unsigned long n, uint8_t base, uint8_t sign)
|
||||
{
|
||||
uint8_t buf[34];
|
||||
uint8_t digit, i;
|
||||
|
||||
// TODO: make these checks as inline, since base is
|
||||
// almost always a constant. base = 0 (BYTE) should
|
||||
// inline as a call directly to write()
|
||||
if (base == 0) {
|
||||
return write((uint8_t)n);
|
||||
} else if (base == 1) {
|
||||
base = 10;
|
||||
}
|
||||
|
||||
|
||||
if (n == 0) {
|
||||
buf[sizeof(buf) - 1] = '0';
|
||||
i = sizeof(buf) - 1;
|
||||
} else {
|
||||
i = sizeof(buf) - 1;
|
||||
while (1) {
|
||||
digit = n % base;
|
||||
buf[i] = ((digit < 10) ? '0' + digit : 'A' + digit - 10);
|
||||
n /= base;
|
||||
if (n == 0) break;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if (sign) {
|
||||
i--;
|
||||
buf[i] = '-';
|
||||
}
|
||||
return write(buf + i, sizeof(buf) - i);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
size_t Print::printFloat(double number, uint8_t digits)
|
||||
{
|
||||
uint8_t sign=0;
|
||||
size_t count=0;
|
||||
|
||||
if (isnan(number)) return print("nan");
|
||||
if (isinf(number)) return print("inf");
|
||||
if (number > 4294967040.0f) return print("ovf"); // constant determined empirically
|
||||
if (number <-4294967040.0f) return print("ovf"); // constant determined empirically
|
||||
|
||||
// Handle negative numbers
|
||||
if (number < 0.0) {
|
||||
sign = 1;
|
||||
number = -number;
|
||||
}
|
||||
|
||||
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||
double rounding = 0.5;
|
||||
for (uint8_t i=0; i<digits; ++i) {
|
||||
rounding *= 0.1;
|
||||
}
|
||||
number += rounding;
|
||||
|
||||
// Extract the integer part of the number and print it
|
||||
unsigned long int_part = (unsigned long)number;
|
||||
double remainder = number - (double)int_part;
|
||||
count += printNumber(int_part, 10, sign);
|
||||
|
||||
// Print the decimal point, but only if there are digits beyond
|
||||
if (digits > 0) {
|
||||
uint8_t n, buf[16], count=1;
|
||||
buf[0] = '.';
|
||||
|
||||
// Extract digits from the remainder one at a time
|
||||
if (digits > sizeof(buf) - 1) digits = sizeof(buf) - 1;
|
||||
|
||||
while (digits-- > 0) {
|
||||
remainder *= 10.0;
|
||||
n = (uint8_t)(remainder);
|
||||
buf[count++] = '0' + n;
|
||||
remainder -= n;
|
||||
}
|
||||
count += write(buf, count);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/* Teensyduino Core Library
|
||||
* http://www.pjrc.com/teensy/
|
||||
* Copyright (c) 2017 PJRC.COM, LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* 1. The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* 2. If the Software is incorporated into a build system that allows
|
||||
* selection among a list of target devices, then similar target
|
||||
* devices manufactured by PJRC.COM must be included in the list of
|
||||
* target devices and selectable in the same manner.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
// Long ago this file contained code from Arduino.cc, which was
|
||||
// Copyright (c) 2008 David A. Mellis. No substantial portion of
|
||||
// Arduino's original code remains. In fact, several improvements
|
||||
// developed for Teensyduino have made their way back into
|
||||
// Arduino's code base. :-)
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "Print.h"
|
||||
|
||||
|
||||
size_t Print::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
size_t count = 0;
|
||||
while (size--) count += write(*buffer++);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
// size_t Print::print(const String &s)
|
||||
// {
|
||||
// uint8_t buffer[33];
|
||||
// size_t count = 0;
|
||||
// unsigned int index = 0;
|
||||
// unsigned int len = s.length();
|
||||
// while (len > 0) {
|
||||
// s.getBytes(buffer, sizeof(buffer), index);
|
||||
// unsigned int nbytes = len;
|
||||
// if (nbytes > sizeof(buffer)-1) nbytes = sizeof(buffer)-1;
|
||||
// index += nbytes;
|
||||
// len -= nbytes;
|
||||
// count += write(buffer, nbytes);
|
||||
// }
|
||||
// return count;
|
||||
// }
|
||||
|
||||
|
||||
size_t Print::print(long n)
|
||||
{
|
||||
uint8_t sign=0;
|
||||
|
||||
if (n < 0) {
|
||||
sign = '-';
|
||||
n = -n;
|
||||
}
|
||||
return printNumber(n, 10, sign);
|
||||
}
|
||||
|
||||
|
||||
size_t Print::println(void)
|
||||
{
|
||||
uint8_t buf[2]={'\r', '\n'};
|
||||
return write(buf, 2);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
__attribute__((weak))
|
||||
int _write(long file, char *ptr, int len)
|
||||
{
|
||||
((class Print *)file)->write((uint8_t *)ptr, len);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
int Print::printf(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
#ifdef __STRICT_ANSI__
|
||||
return 0; // TODO: make this work with -std=c++0x
|
||||
#else
|
||||
return vdprintf((int)this, format, ap);
|
||||
#endif
|
||||
}
|
||||
|
||||
int Print::printf(const __FlashStringHelper *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
#ifdef __STRICT_ANSI__
|
||||
return 0;
|
||||
#else
|
||||
return vdprintf((int)this, (const char *)format, ap);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __MKL26Z64__
|
||||
|
||||
// optimized code inspired by Stimmer's optimization
|
||||
// obviously a dit different, adapted to 32 bit Cortex-M0+
|
||||
// http://forum.arduino.cc/index.php?topic=167414.msg1293679#msg1293679
|
||||
// http://forum.arduino.cc/index.php?topic=167414.msg1309482#msg1309482
|
||||
// equivelant code:
|
||||
// mod = div % 10;
|
||||
// div = div / 10;
|
||||
// tmp1 = {random};
|
||||
// tmp2 = 10;
|
||||
#if 1
|
||||
// https://forum.pjrc.com/threads/28932-LC-is-10-9-times-slower-than-T3-1?p=76072&viewfull=1#post76072
|
||||
void inline divmod10_v2(uint32_t n,uint32_t *div,uint32_t *mod) {
|
||||
uint32_t p,q;
|
||||
/* Using 32.16 fixed point representation p.q */
|
||||
/* p.q = (n+1)/512 */
|
||||
q = (n&0xFFFF) + 1;
|
||||
p = (n>>16);
|
||||
/* p.q = 51*(n+1)/512 */
|
||||
q = 13107*q;
|
||||
p = 13107*p;
|
||||
/* p.q = (1+1/2^8+1/2^16+1/2^24)*51*(n+1)/512 */
|
||||
q = q + (q>>16) + (p&0xFFFF);
|
||||
p = p + (p>>16) + (q>>16);
|
||||
/* divide by 2 */
|
||||
p = p>>1;
|
||||
*div = p;
|
||||
*mod = n-10*p;
|
||||
}
|
||||
#define divmod10_asm(div, mod, tmp1, tmp2, const3333) \
|
||||
divmod10_v2(div, &div, &mod);
|
||||
/*
|
||||
#define divmod10_asm(div, mod, tmp1, tmp2, const3333) \
|
||||
asm ( \
|
||||
" lsr %2, %0, #16" "\n\t" \
|
||||
" mul %2, %4" "\n\t" \
|
||||
" uxth %1, %0" "\n\t" \
|
||||
" mul %1, %4" "\n\t" \
|
||||
" add %1, #1" "\n\t" \
|
||||
" lsr %0, %2, #16" "\n\t" \
|
||||
" lsl %2, %2, #16" "\n\t" \
|
||||
" add %1, %2" "\n\t" \
|
||||
" mov %3, #0" "\n\t" \
|
||||
" adc %0, %3" "\n\t" \
|
||||
" lsl %0, %0, #15" "\n\t" \
|
||||
" lsr %2, %1, #17" "\n\t" \
|
||||
" orr %0, %2" "\n\t" \
|
||||
" lsl %1, %1, #15" "\n\t" \
|
||||
" lsr %2, %1, #16" "\n\t" \
|
||||
" lsl %3, %0, #16" "\n\t" \
|
||||
" orr %2, %3" "\n\t" \
|
||||
" lsr %3, %0, #16" "\n\t" \
|
||||
" add %1, %0" "\n\t" \
|
||||
" adc %0, %1" "\n\t" \
|
||||
" sub %0, %1" "\n\t" \
|
||||
" add %1, %2" "\n\t" \
|
||||
" adc %0, %3" "\n\t" \
|
||||
" lsr %1, %1, #4" "\n\t" \
|
||||
" mov %3, #10" "\n\t" \
|
||||
" mul %1, %3" "\n\t" \
|
||||
" lsr %1, %1, #28" "\n\t" \
|
||||
: "+l" (div), \
|
||||
"=&l" (mod), \
|
||||
"=&l" (tmp1), \
|
||||
"=&l" (tmp2) \
|
||||
: "l" (const3333) \
|
||||
: \
|
||||
)
|
||||
*/
|
||||
#else
|
||||
#define divmod10_asm(_div, _mod, _tmp1, _tmp2, _const3333) \
|
||||
({ _tmp1 = _div; _div = _div / 10; _mod = _tmp1 - _div * 10; })
|
||||
// ({_mod = _div % 10, _div = _div / 10; })
|
||||
#endif
|
||||
|
||||
|
||||
size_t Print::printNumberDec(unsigned long n, uint8_t sign)
|
||||
{
|
||||
uint8_t buf[11], *p;
|
||||
uint32_t digit;
|
||||
//uint32_t t1, t2, c3333=0x3333;
|
||||
|
||||
p = buf + (sizeof(buf));
|
||||
do {
|
||||
uint32_t div;
|
||||
divmod10_v2(n, &div, &digit);
|
||||
n = div;
|
||||
//divmod10_asm(n, digit, t1, t2, c3333);
|
||||
*--p = digit + '0';
|
||||
} while (n);
|
||||
if (sign) *--p = '-';
|
||||
return write(p, sizeof(buf) - (p - buf));
|
||||
}
|
||||
|
||||
size_t Print::printNumberHex(unsigned long n)
|
||||
{
|
||||
uint8_t digit, buf[8], *p;
|
||||
|
||||
p = buf + (sizeof(buf));
|
||||
do {
|
||||
digit = n & 15;
|
||||
*--p = (digit < 10) ? '0' + digit : 'A' + digit - 10;
|
||||
n >>= 4;
|
||||
} while (n);
|
||||
return write(p, sizeof(buf) - (p - buf));
|
||||
}
|
||||
|
||||
size_t Print::printNumberBin(unsigned long n)
|
||||
{
|
||||
uint8_t buf[32], *p;
|
||||
|
||||
p = buf + (sizeof(buf));
|
||||
do {
|
||||
*--p = '0' + ((uint8_t)n & 1);
|
||||
n >>= 1;
|
||||
} while (n);
|
||||
return write(p, sizeof(buf) - (p - buf));
|
||||
}
|
||||
|
||||
size_t Print::printNumberAny(unsigned long n, uint8_t base)
|
||||
{
|
||||
uint8_t digit, buf[21], *p;
|
||||
uint32_t tmp;
|
||||
|
||||
p = buf + sizeof(buf);
|
||||
do {
|
||||
tmp = n;
|
||||
n = n / base;
|
||||
digit = tmp - n * base;
|
||||
*--p = (digit < 10) ? '0' + digit : 'A' + digit - 10;
|
||||
} while (n);
|
||||
return write(p, sizeof(buf) - (p - buf));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
size_t Print::printNumber(unsigned long n, uint8_t base, uint8_t sign)
|
||||
{
|
||||
uint8_t buf[34];
|
||||
uint8_t digit, i;
|
||||
|
||||
// TODO: make these checks as inline, since base is
|
||||
// almost always a constant. base = 0 (BYTE) should
|
||||
// inline as a call directly to write()
|
||||
if (base == 0) {
|
||||
return write((uint8_t)n);
|
||||
} else if (base == 1) {
|
||||
base = 10;
|
||||
}
|
||||
|
||||
|
||||
if (n == 0) {
|
||||
buf[sizeof(buf) - 1] = '0';
|
||||
i = sizeof(buf) - 1;
|
||||
} else {
|
||||
i = sizeof(buf) - 1;
|
||||
while (1) {
|
||||
digit = n % base;
|
||||
buf[i] = ((digit < 10) ? '0' + digit : 'A' + digit - 10);
|
||||
n /= base;
|
||||
if (n == 0) break;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if (sign) {
|
||||
i--;
|
||||
buf[i] = '-';
|
||||
}
|
||||
return write(buf + i, sizeof(buf) - i);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
size_t Print::printFloat(double number, uint8_t digits)
|
||||
{
|
||||
uint8_t sign=0;
|
||||
size_t count=0;
|
||||
|
||||
if (isnan(number)) return print("nan");
|
||||
if (isinf(number)) return print("inf");
|
||||
if (number > 4294967040.0f) return print("ovf"); // constant determined empirically
|
||||
if (number <-4294967040.0f) return print("ovf"); // constant determined empirically
|
||||
|
||||
// Handle negative numbers
|
||||
if (number < 0.0) {
|
||||
sign = 1;
|
||||
number = -number;
|
||||
}
|
||||
|
||||
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||
double rounding = 0.5;
|
||||
for (uint8_t i=0; i<digits; ++i) {
|
||||
rounding *= 0.1;
|
||||
}
|
||||
number += rounding;
|
||||
|
||||
// Extract the integer part of the number and print it
|
||||
unsigned long int_part = (unsigned long)number;
|
||||
double remainder = number - (double)int_part;
|
||||
count += printNumber(int_part, 10, sign);
|
||||
|
||||
// Print the decimal point, but only if there are digits beyond
|
||||
if (digits > 0) {
|
||||
uint8_t n, buf[16], count=1;
|
||||
buf[0] = '.';
|
||||
|
||||
// Extract digits from the remainder one at a time
|
||||
if (digits > sizeof(buf) - 1) digits = sizeof(buf) - 1;
|
||||
|
||||
while (digits-- > 0) {
|
||||
remainder *= 10.0;
|
||||
n = (uint8_t)(remainder);
|
||||
buf[count++] = '0' + n;
|
||||
remainder -= n;
|
||||
}
|
||||
count += write(buf, count);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,3 +1,3 @@
|
|||
#include <cmath>
|
||||
|
||||
#include "FilterOnePole.cpp"
|
||||
#include <cmath>
|
||||
|
||||
#include "FilterOnePole.cpp"
|
||||
|
|
|
|||
|
|
@ -1,276 +1,276 @@
|
|||
// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0.
|
||||
// See gfxfont.h for newer custom bitmap font info.
|
||||
|
||||
#ifndef FONT5X7_H
|
||||
#define FONT5X7_H
|
||||
|
||||
#ifdef __AVR__
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#elif defined(ESP8266)
|
||||
#include <pgmspace.h>
|
||||
#else
|
||||
#define PROGMEM
|
||||
#endif
|
||||
|
||||
// Standard ASCII 5x7 font
|
||||
|
||||
static const unsigned char font[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x3E, 0x5B, 0x4F, 0x5B, 0x3E,
|
||||
0x3E, 0x6B, 0x4F, 0x6B, 0x3E,
|
||||
0x1C, 0x3E, 0x7C, 0x3E, 0x1C,
|
||||
0x18, 0x3C, 0x7E, 0x3C, 0x18,
|
||||
0x1C, 0x57, 0x7D, 0x57, 0x1C,
|
||||
0x1C, 0x5E, 0x7F, 0x5E, 0x1C,
|
||||
0x00, 0x18, 0x3C, 0x18, 0x00,
|
||||
0xFF, 0xE7, 0xC3, 0xE7, 0xFF,
|
||||
0x00, 0x18, 0x24, 0x18, 0x00,
|
||||
0xFF, 0xE7, 0xDB, 0xE7, 0xFF,
|
||||
0x30, 0x48, 0x3A, 0x06, 0x0E,
|
||||
0x26, 0x29, 0x79, 0x29, 0x26,
|
||||
0x40, 0x7F, 0x05, 0x05, 0x07,
|
||||
0x40, 0x7F, 0x05, 0x25, 0x3F,
|
||||
0x5A, 0x3C, 0xE7, 0x3C, 0x5A,
|
||||
0x7F, 0x3E, 0x1C, 0x1C, 0x08,
|
||||
0x08, 0x1C, 0x1C, 0x3E, 0x7F,
|
||||
0x14, 0x22, 0x7F, 0x22, 0x14,
|
||||
0x5F, 0x5F, 0x00, 0x5F, 0x5F,
|
||||
0x06, 0x09, 0x7F, 0x01, 0x7F,
|
||||
0x00, 0x66, 0x89, 0x95, 0x6A,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60,
|
||||
0x94, 0xA2, 0xFF, 0xA2, 0x94,
|
||||
0x08, 0x04, 0x7E, 0x04, 0x08,
|
||||
0x10, 0x20, 0x7E, 0x20, 0x10,
|
||||
0x08, 0x08, 0x2A, 0x1C, 0x08,
|
||||
0x08, 0x1C, 0x2A, 0x08, 0x08,
|
||||
0x1E, 0x10, 0x10, 0x10, 0x10,
|
||||
0x0C, 0x1E, 0x0C, 0x1E, 0x0C,
|
||||
0x30, 0x38, 0x3E, 0x38, 0x30,
|
||||
0x06, 0x0E, 0x3E, 0x0E, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x5F, 0x00, 0x00,
|
||||
0x00, 0x07, 0x00, 0x07, 0x00,
|
||||
0x14, 0x7F, 0x14, 0x7F, 0x14,
|
||||
0x24, 0x2A, 0x7F, 0x2A, 0x12,
|
||||
0x23, 0x13, 0x08, 0x64, 0x62,
|
||||
0x36, 0x49, 0x56, 0x20, 0x50,
|
||||
0x00, 0x08, 0x07, 0x03, 0x00,
|
||||
0x00, 0x1C, 0x22, 0x41, 0x00,
|
||||
0x00, 0x41, 0x22, 0x1C, 0x00,
|
||||
0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
|
||||
0x08, 0x08, 0x3E, 0x08, 0x08,
|
||||
0x00, 0x80, 0x70, 0x30, 0x00,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x00, 0x00, 0x60, 0x60, 0x00,
|
||||
0x20, 0x10, 0x08, 0x04, 0x02,
|
||||
0x3E, 0x51, 0x49, 0x45, 0x3E,
|
||||
0x00, 0x42, 0x7F, 0x40, 0x00,
|
||||
0x72, 0x49, 0x49, 0x49, 0x46,
|
||||
0x21, 0x41, 0x49, 0x4D, 0x33,
|
||||
0x18, 0x14, 0x12, 0x7F, 0x10,
|
||||
0x27, 0x45, 0x45, 0x45, 0x39,
|
||||
0x3C, 0x4A, 0x49, 0x49, 0x31,
|
||||
0x41, 0x21, 0x11, 0x09, 0x07,
|
||||
0x36, 0x49, 0x49, 0x49, 0x36,
|
||||
0x46, 0x49, 0x49, 0x29, 0x1E,
|
||||
0x00, 0x00, 0x14, 0x00, 0x00,
|
||||
0x00, 0x40, 0x34, 0x00, 0x00,
|
||||
0x00, 0x08, 0x14, 0x22, 0x41,
|
||||
0x14, 0x14, 0x14, 0x14, 0x14,
|
||||
0x00, 0x41, 0x22, 0x14, 0x08,
|
||||
0x02, 0x01, 0x59, 0x09, 0x06,
|
||||
0x3E, 0x41, 0x5D, 0x59, 0x4E,
|
||||
0x7C, 0x12, 0x11, 0x12, 0x7C,
|
||||
0x7F, 0x49, 0x49, 0x49, 0x36,
|
||||
0x3E, 0x41, 0x41, 0x41, 0x22,
|
||||
0x7F, 0x41, 0x41, 0x41, 0x3E,
|
||||
0x7F, 0x49, 0x49, 0x49, 0x41,
|
||||
0x7F, 0x09, 0x09, 0x09, 0x01,
|
||||
0x3E, 0x41, 0x41, 0x51, 0x73,
|
||||
0x7F, 0x08, 0x08, 0x08, 0x7F,
|
||||
0x00, 0x41, 0x7F, 0x41, 0x00,
|
||||
0x20, 0x40, 0x41, 0x3F, 0x01,
|
||||
0x7F, 0x08, 0x14, 0x22, 0x41,
|
||||
0x7F, 0x40, 0x40, 0x40, 0x40,
|
||||
0x7F, 0x02, 0x1C, 0x02, 0x7F,
|
||||
0x7F, 0x04, 0x08, 0x10, 0x7F,
|
||||
0x3E, 0x41, 0x41, 0x41, 0x3E,
|
||||
0x7F, 0x09, 0x09, 0x09, 0x06,
|
||||
0x3E, 0x41, 0x51, 0x21, 0x5E,
|
||||
0x7F, 0x09, 0x19, 0x29, 0x46,
|
||||
0x26, 0x49, 0x49, 0x49, 0x32,
|
||||
0x03, 0x01, 0x7F, 0x01, 0x03,
|
||||
0x3F, 0x40, 0x40, 0x40, 0x3F,
|
||||
0x1F, 0x20, 0x40, 0x20, 0x1F,
|
||||
0x3F, 0x40, 0x38, 0x40, 0x3F,
|
||||
0x63, 0x14, 0x08, 0x14, 0x63,
|
||||
0x03, 0x04, 0x78, 0x04, 0x03,
|
||||
0x61, 0x59, 0x49, 0x4D, 0x43,
|
||||
0x00, 0x7F, 0x41, 0x41, 0x41,
|
||||
0x02, 0x04, 0x08, 0x10, 0x20,
|
||||
0x00, 0x41, 0x41, 0x41, 0x7F,
|
||||
0x04, 0x02, 0x01, 0x02, 0x04,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40,
|
||||
0x00, 0x03, 0x07, 0x08, 0x00,
|
||||
0x20, 0x54, 0x54, 0x78, 0x40,
|
||||
0x7F, 0x28, 0x44, 0x44, 0x38,
|
||||
0x38, 0x44, 0x44, 0x44, 0x28,
|
||||
0x38, 0x44, 0x44, 0x28, 0x7F,
|
||||
0x38, 0x54, 0x54, 0x54, 0x18,
|
||||
0x00, 0x08, 0x7E, 0x09, 0x02,
|
||||
0x18, 0xA4, 0xA4, 0x9C, 0x78,
|
||||
0x7F, 0x08, 0x04, 0x04, 0x78,
|
||||
0x00, 0x44, 0x7D, 0x40, 0x00,
|
||||
0x20, 0x40, 0x40, 0x3D, 0x00,
|
||||
0x7F, 0x10, 0x28, 0x44, 0x00,
|
||||
0x00, 0x41, 0x7F, 0x40, 0x00,
|
||||
0x7C, 0x04, 0x78, 0x04, 0x78,
|
||||
0x7C, 0x08, 0x04, 0x04, 0x78,
|
||||
0x38, 0x44, 0x44, 0x44, 0x38,
|
||||
0xFC, 0x18, 0x24, 0x24, 0x18,
|
||||
0x18, 0x24, 0x24, 0x18, 0xFC,
|
||||
0x7C, 0x08, 0x04, 0x04, 0x08,
|
||||
0x48, 0x54, 0x54, 0x54, 0x24,
|
||||
0x04, 0x04, 0x3F, 0x44, 0x24,
|
||||
0x3C, 0x40, 0x40, 0x20, 0x7C,
|
||||
0x1C, 0x20, 0x40, 0x20, 0x1C,
|
||||
0x3C, 0x40, 0x30, 0x40, 0x3C,
|
||||
0x44, 0x28, 0x10, 0x28, 0x44,
|
||||
0x4C, 0x90, 0x90, 0x90, 0x7C,
|
||||
0x44, 0x64, 0x54, 0x4C, 0x44,
|
||||
0x00, 0x08, 0x36, 0x41, 0x00,
|
||||
0x00, 0x00, 0x77, 0x00, 0x00,
|
||||
0x00, 0x41, 0x36, 0x08, 0x00,
|
||||
0x02, 0x01, 0x02, 0x04, 0x02,
|
||||
0x3C, 0x26, 0x23, 0x26, 0x3C,
|
||||
0x1E, 0xA1, 0xA1, 0x61, 0x12,
|
||||
0x3A, 0x40, 0x40, 0x20, 0x7A,
|
||||
0x38, 0x54, 0x54, 0x55, 0x59,
|
||||
0x21, 0x55, 0x55, 0x79, 0x41,
|
||||
0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut
|
||||
0x21, 0x55, 0x54, 0x78, 0x40,
|
||||
0x20, 0x54, 0x55, 0x79, 0x40,
|
||||
0x0C, 0x1E, 0x52, 0x72, 0x12,
|
||||
0x39, 0x55, 0x55, 0x55, 0x59,
|
||||
0x39, 0x54, 0x54, 0x54, 0x59,
|
||||
0x39, 0x55, 0x54, 0x54, 0x58,
|
||||
0x00, 0x00, 0x45, 0x7C, 0x41,
|
||||
0x00, 0x02, 0x45, 0x7D, 0x42,
|
||||
0x00, 0x01, 0x45, 0x7C, 0x40,
|
||||
0x7D, 0x12, 0x11, 0x12, 0x7D, // A-umlaut
|
||||
0xF0, 0x28, 0x25, 0x28, 0xF0,
|
||||
0x7C, 0x54, 0x55, 0x45, 0x00,
|
||||
0x20, 0x54, 0x54, 0x7C, 0x54,
|
||||
0x7C, 0x0A, 0x09, 0x7F, 0x49,
|
||||
0x32, 0x49, 0x49, 0x49, 0x32,
|
||||
0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut
|
||||
0x32, 0x4A, 0x48, 0x48, 0x30,
|
||||
0x3A, 0x41, 0x41, 0x21, 0x7A,
|
||||
0x3A, 0x42, 0x40, 0x20, 0x78,
|
||||
0x00, 0x9D, 0xA0, 0xA0, 0x7D,
|
||||
0x3D, 0x42, 0x42, 0x42, 0x3D, // O-umlaut
|
||||
0x3D, 0x40, 0x40, 0x40, 0x3D,
|
||||
0x3C, 0x24, 0xFF, 0x24, 0x24,
|
||||
0x48, 0x7E, 0x49, 0x43, 0x66,
|
||||
0x2B, 0x2F, 0xFC, 0x2F, 0x2B,
|
||||
0xFF, 0x09, 0x29, 0xF6, 0x20,
|
||||
0xC0, 0x88, 0x7E, 0x09, 0x03,
|
||||
0x20, 0x54, 0x54, 0x79, 0x41,
|
||||
0x00, 0x00, 0x44, 0x7D, 0x41,
|
||||
0x30, 0x48, 0x48, 0x4A, 0x32,
|
||||
0x38, 0x40, 0x40, 0x22, 0x7A,
|
||||
0x00, 0x7A, 0x0A, 0x0A, 0x72,
|
||||
0x7D, 0x0D, 0x19, 0x31, 0x7D,
|
||||
0x26, 0x29, 0x29, 0x2F, 0x28,
|
||||
0x26, 0x29, 0x29, 0x29, 0x26,
|
||||
0x30, 0x48, 0x4D, 0x40, 0x20,
|
||||
0x38, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x38,
|
||||
0x2F, 0x10, 0xC8, 0xAC, 0xBA,
|
||||
0x2F, 0x10, 0x28, 0x34, 0xFA,
|
||||
0x00, 0x00, 0x7B, 0x00, 0x00,
|
||||
0x08, 0x14, 0x2A, 0x14, 0x22,
|
||||
0x22, 0x14, 0x2A, 0x14, 0x08,
|
||||
0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code
|
||||
0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block
|
||||
0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00,
|
||||
0x10, 0x10, 0x10, 0xFF, 0x00,
|
||||
0x14, 0x14, 0x14, 0xFF, 0x00,
|
||||
0x10, 0x10, 0xFF, 0x00, 0xFF,
|
||||
0x10, 0x10, 0xF0, 0x10, 0xF0,
|
||||
0x14, 0x14, 0x14, 0xFC, 0x00,
|
||||
0x14, 0x14, 0xF7, 0x00, 0xFF,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x14, 0x14, 0xF4, 0x04, 0xFC,
|
||||
0x14, 0x14, 0x17, 0x10, 0x1F,
|
||||
0x10, 0x10, 0x1F, 0x10, 0x1F,
|
||||
0x14, 0x14, 0x14, 0x1F, 0x00,
|
||||
0x10, 0x10, 0x10, 0xF0, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x10,
|
||||
0x10, 0x10, 0x10, 0x1F, 0x10,
|
||||
0x10, 0x10, 0x10, 0xF0, 0x10,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0xFF, 0x10,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x14,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x1F, 0x10, 0x17,
|
||||
0x00, 0x00, 0xFC, 0x04, 0xF4,
|
||||
0x14, 0x14, 0x17, 0x10, 0x17,
|
||||
0x14, 0x14, 0xF4, 0x04, 0xF4,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xF7,
|
||||
0x14, 0x14, 0x14, 0x14, 0x14,
|
||||
0x14, 0x14, 0xF7, 0x00, 0xF7,
|
||||
0x14, 0x14, 0x14, 0x17, 0x14,
|
||||
0x10, 0x10, 0x1F, 0x10, 0x1F,
|
||||
0x14, 0x14, 0x14, 0xF4, 0x14,
|
||||
0x10, 0x10, 0xF0, 0x10, 0xF0,
|
||||
0x00, 0x00, 0x1F, 0x10, 0x1F,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x14,
|
||||
0x00, 0x00, 0x00, 0xFC, 0x14,
|
||||
0x00, 0x00, 0xF0, 0x10, 0xF0,
|
||||
0x10, 0x10, 0xFF, 0x10, 0xFF,
|
||||
0x14, 0x14, 0x14, 0xFF, 0x14,
|
||||
0x10, 0x10, 0x10, 0x1F, 0x00,
|
||||
0x00, 0x00, 0x00, 0xF0, 0x10,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
|
||||
0x38, 0x44, 0x44, 0x38, 0x44,
|
||||
0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta
|
||||
0x7E, 0x02, 0x02, 0x06, 0x06,
|
||||
0x02, 0x7E, 0x02, 0x7E, 0x02,
|
||||
0x63, 0x55, 0x49, 0x41, 0x63,
|
||||
0x38, 0x44, 0x44, 0x3C, 0x04,
|
||||
0x40, 0x7E, 0x20, 0x1E, 0x20,
|
||||
0x06, 0x02, 0x7E, 0x02, 0x02,
|
||||
0x99, 0xA5, 0xE7, 0xA5, 0x99,
|
||||
0x1C, 0x2A, 0x49, 0x2A, 0x1C,
|
||||
0x4C, 0x72, 0x01, 0x72, 0x4C,
|
||||
0x30, 0x4A, 0x4D, 0x4D, 0x30,
|
||||
0x30, 0x48, 0x78, 0x48, 0x30,
|
||||
0xBC, 0x62, 0x5A, 0x46, 0x3D,
|
||||
0x3E, 0x49, 0x49, 0x49, 0x00,
|
||||
0x7E, 0x01, 0x01, 0x01, 0x7E,
|
||||
0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
|
||||
0x44, 0x44, 0x5F, 0x44, 0x44,
|
||||
0x40, 0x51, 0x4A, 0x44, 0x40,
|
||||
0x40, 0x44, 0x4A, 0x51, 0x40,
|
||||
0x00, 0x00, 0xFF, 0x01, 0x03,
|
||||
0xE0, 0x80, 0xFF, 0x00, 0x00,
|
||||
0x08, 0x08, 0x6B, 0x6B, 0x08,
|
||||
0x36, 0x12, 0x36, 0x24, 0x36,
|
||||
0x06, 0x0F, 0x09, 0x0F, 0x06,
|
||||
0x00, 0x00, 0x18, 0x18, 0x00,
|
||||
0x00, 0x00, 0x10, 0x10, 0x00,
|
||||
0x30, 0x40, 0xFF, 0x01, 0x01,
|
||||
0x00, 0x1F, 0x01, 0x01, 0x1E,
|
||||
0x00, 0x19, 0x1D, 0x17, 0x12,
|
||||
0x00, 0x3C, 0x3C, 0x3C, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP
|
||||
};
|
||||
#endif // FONT5X7_H
|
||||
// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0.
|
||||
// See gfxfont.h for newer custom bitmap font info.
|
||||
|
||||
#ifndef FONT5X7_H
|
||||
#define FONT5X7_H
|
||||
|
||||
#ifdef __AVR__
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#elif defined(ESP8266)
|
||||
#include <pgmspace.h>
|
||||
#else
|
||||
#define PROGMEM
|
||||
#endif
|
||||
|
||||
// Standard ASCII 5x7 font
|
||||
|
||||
static const unsigned char font[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x3E, 0x5B, 0x4F, 0x5B, 0x3E,
|
||||
0x3E, 0x6B, 0x4F, 0x6B, 0x3E,
|
||||
0x1C, 0x3E, 0x7C, 0x3E, 0x1C,
|
||||
0x18, 0x3C, 0x7E, 0x3C, 0x18,
|
||||
0x1C, 0x57, 0x7D, 0x57, 0x1C,
|
||||
0x1C, 0x5E, 0x7F, 0x5E, 0x1C,
|
||||
0x00, 0x18, 0x3C, 0x18, 0x00,
|
||||
0xFF, 0xE7, 0xC3, 0xE7, 0xFF,
|
||||
0x00, 0x18, 0x24, 0x18, 0x00,
|
||||
0xFF, 0xE7, 0xDB, 0xE7, 0xFF,
|
||||
0x30, 0x48, 0x3A, 0x06, 0x0E,
|
||||
0x26, 0x29, 0x79, 0x29, 0x26,
|
||||
0x40, 0x7F, 0x05, 0x05, 0x07,
|
||||
0x40, 0x7F, 0x05, 0x25, 0x3F,
|
||||
0x5A, 0x3C, 0xE7, 0x3C, 0x5A,
|
||||
0x7F, 0x3E, 0x1C, 0x1C, 0x08,
|
||||
0x08, 0x1C, 0x1C, 0x3E, 0x7F,
|
||||
0x14, 0x22, 0x7F, 0x22, 0x14,
|
||||
0x5F, 0x5F, 0x00, 0x5F, 0x5F,
|
||||
0x06, 0x09, 0x7F, 0x01, 0x7F,
|
||||
0x00, 0x66, 0x89, 0x95, 0x6A,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60,
|
||||
0x94, 0xA2, 0xFF, 0xA2, 0x94,
|
||||
0x08, 0x04, 0x7E, 0x04, 0x08,
|
||||
0x10, 0x20, 0x7E, 0x20, 0x10,
|
||||
0x08, 0x08, 0x2A, 0x1C, 0x08,
|
||||
0x08, 0x1C, 0x2A, 0x08, 0x08,
|
||||
0x1E, 0x10, 0x10, 0x10, 0x10,
|
||||
0x0C, 0x1E, 0x0C, 0x1E, 0x0C,
|
||||
0x30, 0x38, 0x3E, 0x38, 0x30,
|
||||
0x06, 0x0E, 0x3E, 0x0E, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x5F, 0x00, 0x00,
|
||||
0x00, 0x07, 0x00, 0x07, 0x00,
|
||||
0x14, 0x7F, 0x14, 0x7F, 0x14,
|
||||
0x24, 0x2A, 0x7F, 0x2A, 0x12,
|
||||
0x23, 0x13, 0x08, 0x64, 0x62,
|
||||
0x36, 0x49, 0x56, 0x20, 0x50,
|
||||
0x00, 0x08, 0x07, 0x03, 0x00,
|
||||
0x00, 0x1C, 0x22, 0x41, 0x00,
|
||||
0x00, 0x41, 0x22, 0x1C, 0x00,
|
||||
0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
|
||||
0x08, 0x08, 0x3E, 0x08, 0x08,
|
||||
0x00, 0x80, 0x70, 0x30, 0x00,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x00, 0x00, 0x60, 0x60, 0x00,
|
||||
0x20, 0x10, 0x08, 0x04, 0x02,
|
||||
0x3E, 0x51, 0x49, 0x45, 0x3E,
|
||||
0x00, 0x42, 0x7F, 0x40, 0x00,
|
||||
0x72, 0x49, 0x49, 0x49, 0x46,
|
||||
0x21, 0x41, 0x49, 0x4D, 0x33,
|
||||
0x18, 0x14, 0x12, 0x7F, 0x10,
|
||||
0x27, 0x45, 0x45, 0x45, 0x39,
|
||||
0x3C, 0x4A, 0x49, 0x49, 0x31,
|
||||
0x41, 0x21, 0x11, 0x09, 0x07,
|
||||
0x36, 0x49, 0x49, 0x49, 0x36,
|
||||
0x46, 0x49, 0x49, 0x29, 0x1E,
|
||||
0x00, 0x00, 0x14, 0x00, 0x00,
|
||||
0x00, 0x40, 0x34, 0x00, 0x00,
|
||||
0x00, 0x08, 0x14, 0x22, 0x41,
|
||||
0x14, 0x14, 0x14, 0x14, 0x14,
|
||||
0x00, 0x41, 0x22, 0x14, 0x08,
|
||||
0x02, 0x01, 0x59, 0x09, 0x06,
|
||||
0x3E, 0x41, 0x5D, 0x59, 0x4E,
|
||||
0x7C, 0x12, 0x11, 0x12, 0x7C,
|
||||
0x7F, 0x49, 0x49, 0x49, 0x36,
|
||||
0x3E, 0x41, 0x41, 0x41, 0x22,
|
||||
0x7F, 0x41, 0x41, 0x41, 0x3E,
|
||||
0x7F, 0x49, 0x49, 0x49, 0x41,
|
||||
0x7F, 0x09, 0x09, 0x09, 0x01,
|
||||
0x3E, 0x41, 0x41, 0x51, 0x73,
|
||||
0x7F, 0x08, 0x08, 0x08, 0x7F,
|
||||
0x00, 0x41, 0x7F, 0x41, 0x00,
|
||||
0x20, 0x40, 0x41, 0x3F, 0x01,
|
||||
0x7F, 0x08, 0x14, 0x22, 0x41,
|
||||
0x7F, 0x40, 0x40, 0x40, 0x40,
|
||||
0x7F, 0x02, 0x1C, 0x02, 0x7F,
|
||||
0x7F, 0x04, 0x08, 0x10, 0x7F,
|
||||
0x3E, 0x41, 0x41, 0x41, 0x3E,
|
||||
0x7F, 0x09, 0x09, 0x09, 0x06,
|
||||
0x3E, 0x41, 0x51, 0x21, 0x5E,
|
||||
0x7F, 0x09, 0x19, 0x29, 0x46,
|
||||
0x26, 0x49, 0x49, 0x49, 0x32,
|
||||
0x03, 0x01, 0x7F, 0x01, 0x03,
|
||||
0x3F, 0x40, 0x40, 0x40, 0x3F,
|
||||
0x1F, 0x20, 0x40, 0x20, 0x1F,
|
||||
0x3F, 0x40, 0x38, 0x40, 0x3F,
|
||||
0x63, 0x14, 0x08, 0x14, 0x63,
|
||||
0x03, 0x04, 0x78, 0x04, 0x03,
|
||||
0x61, 0x59, 0x49, 0x4D, 0x43,
|
||||
0x00, 0x7F, 0x41, 0x41, 0x41,
|
||||
0x02, 0x04, 0x08, 0x10, 0x20,
|
||||
0x00, 0x41, 0x41, 0x41, 0x7F,
|
||||
0x04, 0x02, 0x01, 0x02, 0x04,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40,
|
||||
0x00, 0x03, 0x07, 0x08, 0x00,
|
||||
0x20, 0x54, 0x54, 0x78, 0x40,
|
||||
0x7F, 0x28, 0x44, 0x44, 0x38,
|
||||
0x38, 0x44, 0x44, 0x44, 0x28,
|
||||
0x38, 0x44, 0x44, 0x28, 0x7F,
|
||||
0x38, 0x54, 0x54, 0x54, 0x18,
|
||||
0x00, 0x08, 0x7E, 0x09, 0x02,
|
||||
0x18, 0xA4, 0xA4, 0x9C, 0x78,
|
||||
0x7F, 0x08, 0x04, 0x04, 0x78,
|
||||
0x00, 0x44, 0x7D, 0x40, 0x00,
|
||||
0x20, 0x40, 0x40, 0x3D, 0x00,
|
||||
0x7F, 0x10, 0x28, 0x44, 0x00,
|
||||
0x00, 0x41, 0x7F, 0x40, 0x00,
|
||||
0x7C, 0x04, 0x78, 0x04, 0x78,
|
||||
0x7C, 0x08, 0x04, 0x04, 0x78,
|
||||
0x38, 0x44, 0x44, 0x44, 0x38,
|
||||
0xFC, 0x18, 0x24, 0x24, 0x18,
|
||||
0x18, 0x24, 0x24, 0x18, 0xFC,
|
||||
0x7C, 0x08, 0x04, 0x04, 0x08,
|
||||
0x48, 0x54, 0x54, 0x54, 0x24,
|
||||
0x04, 0x04, 0x3F, 0x44, 0x24,
|
||||
0x3C, 0x40, 0x40, 0x20, 0x7C,
|
||||
0x1C, 0x20, 0x40, 0x20, 0x1C,
|
||||
0x3C, 0x40, 0x30, 0x40, 0x3C,
|
||||
0x44, 0x28, 0x10, 0x28, 0x44,
|
||||
0x4C, 0x90, 0x90, 0x90, 0x7C,
|
||||
0x44, 0x64, 0x54, 0x4C, 0x44,
|
||||
0x00, 0x08, 0x36, 0x41, 0x00,
|
||||
0x00, 0x00, 0x77, 0x00, 0x00,
|
||||
0x00, 0x41, 0x36, 0x08, 0x00,
|
||||
0x02, 0x01, 0x02, 0x04, 0x02,
|
||||
0x3C, 0x26, 0x23, 0x26, 0x3C,
|
||||
0x1E, 0xA1, 0xA1, 0x61, 0x12,
|
||||
0x3A, 0x40, 0x40, 0x20, 0x7A,
|
||||
0x38, 0x54, 0x54, 0x55, 0x59,
|
||||
0x21, 0x55, 0x55, 0x79, 0x41,
|
||||
0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut
|
||||
0x21, 0x55, 0x54, 0x78, 0x40,
|
||||
0x20, 0x54, 0x55, 0x79, 0x40,
|
||||
0x0C, 0x1E, 0x52, 0x72, 0x12,
|
||||
0x39, 0x55, 0x55, 0x55, 0x59,
|
||||
0x39, 0x54, 0x54, 0x54, 0x59,
|
||||
0x39, 0x55, 0x54, 0x54, 0x58,
|
||||
0x00, 0x00, 0x45, 0x7C, 0x41,
|
||||
0x00, 0x02, 0x45, 0x7D, 0x42,
|
||||
0x00, 0x01, 0x45, 0x7C, 0x40,
|
||||
0x7D, 0x12, 0x11, 0x12, 0x7D, // A-umlaut
|
||||
0xF0, 0x28, 0x25, 0x28, 0xF0,
|
||||
0x7C, 0x54, 0x55, 0x45, 0x00,
|
||||
0x20, 0x54, 0x54, 0x7C, 0x54,
|
||||
0x7C, 0x0A, 0x09, 0x7F, 0x49,
|
||||
0x32, 0x49, 0x49, 0x49, 0x32,
|
||||
0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut
|
||||
0x32, 0x4A, 0x48, 0x48, 0x30,
|
||||
0x3A, 0x41, 0x41, 0x21, 0x7A,
|
||||
0x3A, 0x42, 0x40, 0x20, 0x78,
|
||||
0x00, 0x9D, 0xA0, 0xA0, 0x7D,
|
||||
0x3D, 0x42, 0x42, 0x42, 0x3D, // O-umlaut
|
||||
0x3D, 0x40, 0x40, 0x40, 0x3D,
|
||||
0x3C, 0x24, 0xFF, 0x24, 0x24,
|
||||
0x48, 0x7E, 0x49, 0x43, 0x66,
|
||||
0x2B, 0x2F, 0xFC, 0x2F, 0x2B,
|
||||
0xFF, 0x09, 0x29, 0xF6, 0x20,
|
||||
0xC0, 0x88, 0x7E, 0x09, 0x03,
|
||||
0x20, 0x54, 0x54, 0x79, 0x41,
|
||||
0x00, 0x00, 0x44, 0x7D, 0x41,
|
||||
0x30, 0x48, 0x48, 0x4A, 0x32,
|
||||
0x38, 0x40, 0x40, 0x22, 0x7A,
|
||||
0x00, 0x7A, 0x0A, 0x0A, 0x72,
|
||||
0x7D, 0x0D, 0x19, 0x31, 0x7D,
|
||||
0x26, 0x29, 0x29, 0x2F, 0x28,
|
||||
0x26, 0x29, 0x29, 0x29, 0x26,
|
||||
0x30, 0x48, 0x4D, 0x40, 0x20,
|
||||
0x38, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x38,
|
||||
0x2F, 0x10, 0xC8, 0xAC, 0xBA,
|
||||
0x2F, 0x10, 0x28, 0x34, 0xFA,
|
||||
0x00, 0x00, 0x7B, 0x00, 0x00,
|
||||
0x08, 0x14, 0x2A, 0x14, 0x22,
|
||||
0x22, 0x14, 0x2A, 0x14, 0x08,
|
||||
0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code
|
||||
0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block
|
||||
0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00,
|
||||
0x10, 0x10, 0x10, 0xFF, 0x00,
|
||||
0x14, 0x14, 0x14, 0xFF, 0x00,
|
||||
0x10, 0x10, 0xFF, 0x00, 0xFF,
|
||||
0x10, 0x10, 0xF0, 0x10, 0xF0,
|
||||
0x14, 0x14, 0x14, 0xFC, 0x00,
|
||||
0x14, 0x14, 0xF7, 0x00, 0xFF,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x14, 0x14, 0xF4, 0x04, 0xFC,
|
||||
0x14, 0x14, 0x17, 0x10, 0x1F,
|
||||
0x10, 0x10, 0x1F, 0x10, 0x1F,
|
||||
0x14, 0x14, 0x14, 0x1F, 0x00,
|
||||
0x10, 0x10, 0x10, 0xF0, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x10,
|
||||
0x10, 0x10, 0x10, 0x1F, 0x10,
|
||||
0x10, 0x10, 0x10, 0xF0, 0x10,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0xFF, 0x10,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x14,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x1F, 0x10, 0x17,
|
||||
0x00, 0x00, 0xFC, 0x04, 0xF4,
|
||||
0x14, 0x14, 0x17, 0x10, 0x17,
|
||||
0x14, 0x14, 0xF4, 0x04, 0xF4,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xF7,
|
||||
0x14, 0x14, 0x14, 0x14, 0x14,
|
||||
0x14, 0x14, 0xF7, 0x00, 0xF7,
|
||||
0x14, 0x14, 0x14, 0x17, 0x14,
|
||||
0x10, 0x10, 0x1F, 0x10, 0x1F,
|
||||
0x14, 0x14, 0x14, 0xF4, 0x14,
|
||||
0x10, 0x10, 0xF0, 0x10, 0xF0,
|
||||
0x00, 0x00, 0x1F, 0x10, 0x1F,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x14,
|
||||
0x00, 0x00, 0x00, 0xFC, 0x14,
|
||||
0x00, 0x00, 0xF0, 0x10, 0xF0,
|
||||
0x10, 0x10, 0xFF, 0x10, 0xFF,
|
||||
0x14, 0x14, 0x14, 0xFF, 0x14,
|
||||
0x10, 0x10, 0x10, 0x1F, 0x00,
|
||||
0x00, 0x00, 0x00, 0xF0, 0x10,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
|
||||
0x38, 0x44, 0x44, 0x38, 0x44,
|
||||
0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta
|
||||
0x7E, 0x02, 0x02, 0x06, 0x06,
|
||||
0x02, 0x7E, 0x02, 0x7E, 0x02,
|
||||
0x63, 0x55, 0x49, 0x41, 0x63,
|
||||
0x38, 0x44, 0x44, 0x3C, 0x04,
|
||||
0x40, 0x7E, 0x20, 0x1E, 0x20,
|
||||
0x06, 0x02, 0x7E, 0x02, 0x02,
|
||||
0x99, 0xA5, 0xE7, 0xA5, 0x99,
|
||||
0x1C, 0x2A, 0x49, 0x2A, 0x1C,
|
||||
0x4C, 0x72, 0x01, 0x72, 0x4C,
|
||||
0x30, 0x4A, 0x4D, 0x4D, 0x30,
|
||||
0x30, 0x48, 0x78, 0x48, 0x30,
|
||||
0xBC, 0x62, 0x5A, 0x46, 0x3D,
|
||||
0x3E, 0x49, 0x49, 0x49, 0x00,
|
||||
0x7E, 0x01, 0x01, 0x01, 0x7E,
|
||||
0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
|
||||
0x44, 0x44, 0x5F, 0x44, 0x44,
|
||||
0x40, 0x51, 0x4A, 0x44, 0x40,
|
||||
0x40, 0x44, 0x4A, 0x51, 0x40,
|
||||
0x00, 0x00, 0xFF, 0x01, 0x03,
|
||||
0xE0, 0x80, 0xFF, 0x00, 0x00,
|
||||
0x08, 0x08, 0x6B, 0x6B, 0x08,
|
||||
0x36, 0x12, 0x36, 0x24, 0x36,
|
||||
0x06, 0x0F, 0x09, 0x0F, 0x06,
|
||||
0x00, 0x00, 0x18, 0x18, 0x00,
|
||||
0x00, 0x00, 0x10, 0x10, 0x00,
|
||||
0x30, 0x40, 0xFF, 0x01, 0x01,
|
||||
0x00, 0x1F, 0x01, 0x01, 0x1E,
|
||||
0x00, 0x19, 0x1D, 0x17, 0x12,
|
||||
0x00, 0x3C, 0x3C, 0x3C, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP
|
||||
};
|
||||
#endif // FONT5X7_H
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,124 +1,124 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include "EEPROM.h"
|
||||
|
||||
// TODO: Fake eeprom a bit better, maybe even save to file.
|
||||
|
||||
EEPROMClass::EEPROMClass() {
|
||||
memset(someFakeEEPROM_memory, 0xff, sizeof(someFakeEEPROM_memory));
|
||||
storage = NULL;
|
||||
autoUpdate = false;
|
||||
}
|
||||
|
||||
|
||||
uint8_t EEPROMClass::read( int idx )
|
||||
{
|
||||
printf("Reading EEPROM address %u: %u\n", idx, 0xff&someFakeEEPROM_memory[idx]);
|
||||
return someFakeEEPROM_memory[idx];
|
||||
}
|
||||
|
||||
|
||||
void EEPROMClass::write( int idx, uint8_t val )
|
||||
{
|
||||
printf("Writing to EEPROM address %u = %u\n", idx, val);
|
||||
|
||||
if(val == someFakeEEPROM_memory[idx])
|
||||
{
|
||||
//Value unchanged, do nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
someFakeEEPROM_memory[idx] = val;
|
||||
|
||||
if(autoUpdate && storage)
|
||||
{
|
||||
fseek(storage, idx, SEEK_SET);
|
||||
fputc(val, storage);
|
||||
fflush(storage);
|
||||
}
|
||||
}
|
||||
|
||||
void EEPROMClass::update( int idx, uint8_t val )
|
||||
{
|
||||
write(idx, val);
|
||||
}
|
||||
|
||||
uint16_t EEPROMClass::length()
|
||||
{
|
||||
return sizeof(someFakeEEPROM_memory);
|
||||
}
|
||||
|
||||
int16_t EEPROMClass::setStorage(const char* filename, bool write)
|
||||
{
|
||||
|
||||
//Close any open storage file
|
||||
if(storage)
|
||||
{
|
||||
fclose(storage);
|
||||
storage = NULL;
|
||||
}
|
||||
|
||||
autoUpdate = write;
|
||||
|
||||
storage = fopen(filename, "rb");
|
||||
|
||||
|
||||
//If only reading, fail if file does not exist (makes no sense otherwise)
|
||||
if(!storage && !autoUpdate) {
|
||||
printf("Could not open EEPROM storage file: '%s'\n", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(storage)
|
||||
{
|
||||
printf("Reading EEPROM storage file: '%s'\n", filename);
|
||||
rewind(storage);
|
||||
fread(someFakeEEPROM_memory, sizeof(someFakeEEPROM_memory), 1, storage);
|
||||
}
|
||||
|
||||
if(!autoUpdate)
|
||||
{
|
||||
//No need for the file anymore, close it
|
||||
fclose(storage);
|
||||
storage = NULL;
|
||||
}
|
||||
|
||||
//Create file if it doesn't exist (so we can write to it)
|
||||
if(!storage && autoUpdate)
|
||||
{
|
||||
storage = fopen(filename, "wb");
|
||||
if(!storage)
|
||||
{
|
||||
printf("Could not create EEPROM storage file: '%s'\n", filename);
|
||||
autoUpdate = false;
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
if(storage && autoUpdate)
|
||||
{
|
||||
//Reopen file for writing without overwriting it
|
||||
storage = freopen(filename, "r+b", storage);
|
||||
|
||||
if(!storage)
|
||||
{
|
||||
printf("Could not access EEPROM storage file for writing: '%s'\n", filename);
|
||||
autoUpdate = false;
|
||||
return -3;
|
||||
}
|
||||
|
||||
printf("Writing any EEPROM changes to '%s'\n", filename);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EEPROMClass::closeStorage() {
|
||||
if(storage!=NULL)
|
||||
{
|
||||
fclose(storage);
|
||||
storage=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include "EEPROM.h"
|
||||
|
||||
// TODO: Fake eeprom a bit better, maybe even save to file.
|
||||
|
||||
EEPROMClass::EEPROMClass() {
|
||||
memset(someFakeEEPROM_memory, 0xff, sizeof(someFakeEEPROM_memory));
|
||||
storage = NULL;
|
||||
autoUpdate = false;
|
||||
}
|
||||
|
||||
|
||||
uint8_t EEPROMClass::read( int idx )
|
||||
{
|
||||
printf("Reading EEPROM address %u: %u\n", idx, 0xff&someFakeEEPROM_memory[idx]);
|
||||
return someFakeEEPROM_memory[idx];
|
||||
}
|
||||
|
||||
|
||||
void EEPROMClass::write( int idx, uint8_t val )
|
||||
{
|
||||
printf("Writing to EEPROM address %u = %u\n", idx, val);
|
||||
|
||||
if(val == someFakeEEPROM_memory[idx])
|
||||
{
|
||||
//Value unchanged, do nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
someFakeEEPROM_memory[idx] = val;
|
||||
|
||||
if(autoUpdate && storage)
|
||||
{
|
||||
fseek(storage, idx, SEEK_SET);
|
||||
fputc(val, storage);
|
||||
fflush(storage);
|
||||
}
|
||||
}
|
||||
|
||||
void EEPROMClass::update( int idx, uint8_t val )
|
||||
{
|
||||
write(idx, val);
|
||||
}
|
||||
|
||||
uint16_t EEPROMClass::length()
|
||||
{
|
||||
return sizeof(someFakeEEPROM_memory);
|
||||
}
|
||||
|
||||
int16_t EEPROMClass::setStorage(const char* filename, bool write)
|
||||
{
|
||||
|
||||
//Close any open storage file
|
||||
if(storage)
|
||||
{
|
||||
fclose(storage);
|
||||
storage = NULL;
|
||||
}
|
||||
|
||||
autoUpdate = write;
|
||||
|
||||
storage = fopen(filename, "rb");
|
||||
|
||||
|
||||
//If only reading, fail if file does not exist (makes no sense otherwise)
|
||||
if(!storage && !autoUpdate) {
|
||||
printf("Could not open EEPROM storage file: '%s'\n", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(storage)
|
||||
{
|
||||
printf("Reading EEPROM storage file: '%s'\n", filename);
|
||||
rewind(storage);
|
||||
fread(someFakeEEPROM_memory, sizeof(someFakeEEPROM_memory), 1, storage);
|
||||
}
|
||||
|
||||
if(!autoUpdate)
|
||||
{
|
||||
//No need for the file anymore, close it
|
||||
fclose(storage);
|
||||
storage = NULL;
|
||||
}
|
||||
|
||||
//Create file if it doesn't exist (so we can write to it)
|
||||
if(!storage && autoUpdate)
|
||||
{
|
||||
storage = fopen(filename, "wb");
|
||||
if(!storage)
|
||||
{
|
||||
printf("Could not create EEPROM storage file: '%s'\n", filename);
|
||||
autoUpdate = false;
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
if(storage && autoUpdate)
|
||||
{
|
||||
//Reopen file for writing without overwriting it
|
||||
storage = freopen(filename, "r+b", storage);
|
||||
|
||||
if(!storage)
|
||||
{
|
||||
printf("Could not access EEPROM storage file for writing: '%s'\n", filename);
|
||||
autoUpdate = false;
|
||||
return -3;
|
||||
}
|
||||
|
||||
printf("Writing any EEPROM changes to '%s'\n", filename);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EEPROMClass::closeStorage() {
|
||||
if(storage!=NULL)
|
||||
{
|
||||
fclose(storage);
|
||||
storage=NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,55 +1,55 @@
|
|||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
/********************************
|
||||
*
|
||||
*/
|
||||
void SimSerial::begin(uint32_t)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SimSerial::print(const char* str)
|
||||
{
|
||||
printf( "[Serial::print] %s\n", str );
|
||||
}
|
||||
|
||||
|
||||
void SimSerial::print(uint32_t intValue)
|
||||
{
|
||||
printf( "[Serial::print] %d\n", intValue );
|
||||
}
|
||||
|
||||
void SimSerial::println()
|
||||
{
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
void SimSerial::println(uint32_t intValue)
|
||||
{
|
||||
printf( "[Serial::println] %d\n", intValue );
|
||||
}
|
||||
|
||||
|
||||
void SimSerial::println(const char *str)
|
||||
{
|
||||
printf( "[Serial::println] %s\n", str );
|
||||
}
|
||||
|
||||
//Used to send serial midi
|
||||
void SimSerial::write(const uint8_t __unused str)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SimSerial::flush()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
/********************************
|
||||
*
|
||||
*/
|
||||
void SimSerial::begin(uint32_t)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SimSerial::print(const char* str)
|
||||
{
|
||||
printf( "[Serial::print] %s\n", str );
|
||||
}
|
||||
|
||||
|
||||
void SimSerial::print(uint32_t intValue)
|
||||
{
|
||||
printf( "[Serial::print] %d\n", intValue );
|
||||
}
|
||||
|
||||
void SimSerial::println()
|
||||
{
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
void SimSerial::println(uint32_t intValue)
|
||||
{
|
||||
printf( "[Serial::println] %d\n", intValue );
|
||||
}
|
||||
|
||||
|
||||
void SimSerial::println(const char *str)
|
||||
{
|
||||
printf( "[Serial::println] %s\n", str );
|
||||
}
|
||||
|
||||
//Used to send serial midi
|
||||
void SimSerial::write(const uint8_t __unused str)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SimSerial::flush()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,145 +1,145 @@
|
|||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
#include "simusbmidi.h"
|
||||
|
||||
/*************************************
|
||||
* Stub simulation of Teensy usbMidi
|
||||
*/
|
||||
|
||||
void SimUsbMidi::sendNoteOff(uint8_t note, uint8_t velocity, uint8_t channel, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::noteOff] note %03d vel %03d ch %02d\n", note, velocity, channel);
|
||||
}
|
||||
|
||||
void SimUsbMidi::sendNoteOn(uint8_t note, uint8_t velocity, uint8_t channel, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::noteOn] note %03d vel %03d ch %02d\n", note, velocity, channel);
|
||||
}
|
||||
|
||||
void SimUsbMidi::sendPolyPressure(uint8_t note, uint8_t pressure, uint8_t channel, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::polyPressure] note %03d p %03d ch %02d\n", note, pressure, channel);
|
||||
}
|
||||
|
||||
void SimUsbMidi::sendAfterTouchPoly(uint8_t note, uint8_t pressure, uint8_t channel, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::afterTouchPoly] note %03d p %03d ch %02d\n", note, pressure, channel);
|
||||
}
|
||||
|
||||
void SimUsbMidi::sendControlChange(uint8_t control, uint8_t value, uint8_t channel, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::controlChange] cc %03d val %03d ch %02d\n", control, value, channel);
|
||||
}
|
||||
|
||||
void SimUsbMidi::sendProgramChange(uint8_t program, uint8_t channel, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::programChange] prg %03d ch %02d\n", program, channel);
|
||||
}
|
||||
|
||||
void SimUsbMidi::sendAfterTouch(uint8_t pressure, uint8_t channel, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::afterTouch] p %03d ch %02d\n", pressure, channel);
|
||||
}
|
||||
|
||||
void SimUsbMidi::sendPitchBend(int value, uint8_t channel, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::pitchBend] pb %05d ch %02d\n", value, channel);
|
||||
}
|
||||
|
||||
void SimUsbMidi::sendSysEx(uint16_t length, const uint8_t *data, bool __unused hasTerm, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::sysEx] Sending %d bytes\n", length);
|
||||
for(int i=0; i<length; i++) {
|
||||
printf("%02x%c", data[i], (i==length-1)?'\n':':');
|
||||
}
|
||||
}
|
||||
|
||||
//Set a low chunk size on purpose just to let the receiver work for it
|
||||
#define MIDI_SYSEX_CHUNK_SIZE 32
|
||||
|
||||
bool SimUsbMidi::read(uint8_t __unused channel) {
|
||||
if(this->sendMidi) {
|
||||
|
||||
printf("[SimUsbMidi::read] Attempting to send midi data\n");
|
||||
|
||||
std::ifstream file(this->midiFile, std::ios::binary | std::ios::ate);
|
||||
std::streamsize size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
uint8_t *buffer = (uint8_t*)malloc(size);
|
||||
|
||||
if (file.read((char*)buffer, size))
|
||||
{
|
||||
printf("[SimUsbMidi::read] Sending %lu bytes.\n", size);
|
||||
|
||||
this->receiveMidiData(buffer, size);
|
||||
|
||||
}
|
||||
free(buffer);
|
||||
|
||||
this->sendMidi = false;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//Provide midi data for simulation to receive
|
||||
void SimUsbMidi::receiveMidiData(const uint8_t *data, const uint16_t length) {
|
||||
if(length==0) return; //There is no data, what's even the point
|
||||
uint8_t midi_message = data[0]; //First byte of data
|
||||
|
||||
if(midi_message != 0xF0) return; //Only sysex data supported (no other handlers available)
|
||||
|
||||
if(this->usb_midi_handleSysExPartial) {
|
||||
//Chunked sysex receiver set, use that.
|
||||
if(length<=MIDI_SYSEX_CHUNK_SIZE) {
|
||||
//Send all in one go
|
||||
printf( "[SimUsbMidi::receiveMidiData] usb_midi_handleSysExPartial(complete) %d B\n", length);
|
||||
(this->usb_midi_handleSysExPartial)(data, length, true);
|
||||
} else {
|
||||
uint8_t* buf = (uint8_t*)malloc(MIDI_SYSEX_CHUNK_SIZE);
|
||||
int pos=0;
|
||||
while(pos<length) {
|
||||
int remaining = length-pos;
|
||||
int bytesToSend = std::min(remaining, MIDI_SYSEX_CHUNK_SIZE);
|
||||
bool complete = (bytesToSend == remaining);
|
||||
|
||||
memcpy(buf, data+pos, bytesToSend);
|
||||
printf( "[SimUsbMidi::receiveMidiData] usb_midi_handleSysExPartial(complete: %d) %d B\n", complete, bytesToSend);
|
||||
(this->usb_midi_handleSysExPartial)(buf, bytesToSend, complete);
|
||||
pos=pos+bytesToSend;
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
} else if(this->usb_midi_handleSysExComplete) {
|
||||
printf( "[SimUsbMidi::receiveMidiData] usb_midi_handleSysExComplete() %d B\n", length);
|
||||
(this->usb_midi_handleSysExComplete)(data, length);
|
||||
} else {
|
||||
//Nobody listening
|
||||
}
|
||||
}
|
||||
|
||||
//MIDI SysEx handlers. Choice of data types is a bit odd, but done to match Arduino/Teensy libraries
|
||||
void SimUsbMidi::setHandleSystemExclusive(void (*fptr) (const uint8_t *array, unsigned int size)) {
|
||||
this->usb_midi_handleSysExComplete = fptr;
|
||||
}
|
||||
|
||||
//"Chunked" sysex handler (teensy extension), for large messages
|
||||
void SimUsbMidi::setHandleSystemExclusive(void (*fptr) (const uint8_t *array, uint16_t size, bool last)) {
|
||||
this->usb_midi_handleSysExPartial = (void (*)(const uint8_t *, uint16_t, uint8_t))fptr;
|
||||
}
|
||||
|
||||
void SimUsbMidi::setMidiFile(std::string filename) {
|
||||
this->midiFile = filename;
|
||||
}
|
||||
|
||||
void SimUsbMidi::triggerMidi() {
|
||||
this->sendMidi = true;
|
||||
}
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
#include "simusbmidi.h"
|
||||
|
||||
/*************************************
|
||||
* Stub simulation of Teensy usbMidi
|
||||
*/
|
||||
|
||||
void SimUsbMidi::sendNoteOff(uint8_t note, uint8_t velocity, uint8_t channel, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::noteOff] note %03d vel %03d ch %02d\n", note, velocity, channel);
|
||||
}
|
||||
|
||||
void SimUsbMidi::sendNoteOn(uint8_t note, uint8_t velocity, uint8_t channel, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::noteOn] note %03d vel %03d ch %02d\n", note, velocity, channel);
|
||||
}
|
||||
|
||||
void SimUsbMidi::sendPolyPressure(uint8_t note, uint8_t pressure, uint8_t channel, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::polyPressure] note %03d p %03d ch %02d\n", note, pressure, channel);
|
||||
}
|
||||
|
||||
void SimUsbMidi::sendAfterTouchPoly(uint8_t note, uint8_t pressure, uint8_t channel, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::afterTouchPoly] note %03d p %03d ch %02d\n", note, pressure, channel);
|
||||
}
|
||||
|
||||
void SimUsbMidi::sendControlChange(uint8_t control, uint8_t value, uint8_t channel, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::controlChange] cc %03d val %03d ch %02d\n", control, value, channel);
|
||||
}
|
||||
|
||||
void SimUsbMidi::sendProgramChange(uint8_t program, uint8_t channel, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::programChange] prg %03d ch %02d\n", program, channel);
|
||||
}
|
||||
|
||||
void SimUsbMidi::sendAfterTouch(uint8_t pressure, uint8_t channel, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::afterTouch] p %03d ch %02d\n", pressure, channel);
|
||||
}
|
||||
|
||||
void SimUsbMidi::sendPitchBend(int value, uint8_t channel, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::pitchBend] pb %05d ch %02d\n", value, channel);
|
||||
}
|
||||
|
||||
void SimUsbMidi::sendSysEx(uint16_t length, const uint8_t *data, bool __unused hasTerm, uint8_t __unused cable)
|
||||
{
|
||||
printf( "[usbMIDI::sysEx] Sending %d bytes\n", length);
|
||||
for(int i=0; i<length; i++) {
|
||||
printf("%02x%c", data[i], (i==length-1)?'\n':':');
|
||||
}
|
||||
}
|
||||
|
||||
//Set a low chunk size on purpose just to let the receiver work for it
|
||||
#define MIDI_SYSEX_CHUNK_SIZE 32
|
||||
|
||||
bool SimUsbMidi::read(uint8_t __unused channel) {
|
||||
if(this->sendMidi) {
|
||||
|
||||
printf("[SimUsbMidi::read] Attempting to send midi data\n");
|
||||
|
||||
std::ifstream file(this->midiFile, std::ios::binary | std::ios::ate);
|
||||
std::streamsize size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
uint8_t *buffer = (uint8_t*)malloc(size);
|
||||
|
||||
if (file.read((char*)buffer, size))
|
||||
{
|
||||
printf("[SimUsbMidi::read] Sending %lu bytes.\n", size);
|
||||
|
||||
this->receiveMidiData(buffer, size);
|
||||
|
||||
}
|
||||
free(buffer);
|
||||
|
||||
this->sendMidi = false;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//Provide midi data for simulation to receive
|
||||
void SimUsbMidi::receiveMidiData(const uint8_t *data, const uint16_t length) {
|
||||
if(length==0) return; //There is no data, what's even the point
|
||||
uint8_t midi_message = data[0]; //First byte of data
|
||||
|
||||
if(midi_message != 0xF0) return; //Only sysex data supported (no other handlers available)
|
||||
|
||||
if(this->usb_midi_handleSysExPartial) {
|
||||
//Chunked sysex receiver set, use that.
|
||||
if(length<=MIDI_SYSEX_CHUNK_SIZE) {
|
||||
//Send all in one go
|
||||
printf( "[SimUsbMidi::receiveMidiData] usb_midi_handleSysExPartial(complete) %d B\n", length);
|
||||
(this->usb_midi_handleSysExPartial)(data, length, true);
|
||||
} else {
|
||||
uint8_t* buf = (uint8_t*)malloc(MIDI_SYSEX_CHUNK_SIZE);
|
||||
int pos=0;
|
||||
while(pos<length) {
|
||||
int remaining = length-pos;
|
||||
int bytesToSend = std::min(remaining, MIDI_SYSEX_CHUNK_SIZE);
|
||||
bool complete = (bytesToSend == remaining);
|
||||
|
||||
memcpy(buf, data+pos, bytesToSend);
|
||||
printf( "[SimUsbMidi::receiveMidiData] usb_midi_handleSysExPartial(complete: %d) %d B\n", complete, bytesToSend);
|
||||
(this->usb_midi_handleSysExPartial)(buf, bytesToSend, complete);
|
||||
pos=pos+bytesToSend;
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
} else if(this->usb_midi_handleSysExComplete) {
|
||||
printf( "[SimUsbMidi::receiveMidiData] usb_midi_handleSysExComplete() %d B\n", length);
|
||||
(this->usb_midi_handleSysExComplete)(data, length);
|
||||
} else {
|
||||
//Nobody listening
|
||||
}
|
||||
}
|
||||
|
||||
//MIDI SysEx handlers. Choice of data types is a bit odd, but done to match Arduino/Teensy libraries
|
||||
void SimUsbMidi::setHandleSystemExclusive(void (*fptr) (const uint8_t *array, unsigned int size)) {
|
||||
this->usb_midi_handleSysExComplete = fptr;
|
||||
}
|
||||
|
||||
//"Chunked" sysex handler (teensy extension), for large messages
|
||||
void SimUsbMidi::setHandleSystemExclusive(void (*fptr) (const uint8_t *array, uint16_t size, bool last)) {
|
||||
this->usb_midi_handleSysExPartial = (void (*)(const uint8_t *, uint16_t, uint8_t))fptr;
|
||||
}
|
||||
|
||||
void SimUsbMidi::setMidiFile(std::string filename) {
|
||||
this->midiFile = filename;
|
||||
}
|
||||
|
||||
void SimUsbMidi::triggerMidi() {
|
||||
this->sendMidi = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,94 +1,94 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Wire.h"
|
||||
|
||||
/********************************
|
||||
*
|
||||
*/
|
||||
|
||||
SimWire::SimWire( bool verbose )
|
||||
: verbose_( verbose )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SimWire::setClock(uint32_t)
|
||||
{
|
||||
// Ignore.. lol
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SimWire::begin()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SimWire::beginTransmission(uint8_t address)
|
||||
{
|
||||
if( verbose_ )
|
||||
printf("[SimWire::beginTransmission] $%02x\n", address);
|
||||
}
|
||||
|
||||
|
||||
void SimWire::beginTransmission(int address)
|
||||
{
|
||||
beginTransmission((uint8_t)address);
|
||||
}
|
||||
|
||||
|
||||
uint8_t SimWire::endTransmission()
|
||||
{
|
||||
if( verbose_ )
|
||||
printf("[SimWire::endTransmission]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t SimWire::endTransmission(uint8_t what)
|
||||
{
|
||||
if( verbose_ )
|
||||
printf("[SimWire::endTransmission %d]\n", what);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t SimWire::requestFrom(uint8_t address, uint8_t count)
|
||||
{
|
||||
if( verbose_ )
|
||||
printf("[SimWire::requestFrom] $%02x for %d bytes\n", address, count);
|
||||
|
||||
// TODO: We must check if there is an actual slave for that address.
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SimWire::read()
|
||||
{
|
||||
// TODO: Verify that bus is in read mode.
|
||||
// if( current_slave_ != NULL ) {
|
||||
// return current_slave_->i2cReadData( );
|
||||
// } else {
|
||||
printf("No slave selected, returning ones\n");
|
||||
return 0xffu;
|
||||
// }
|
||||
}
|
||||
|
||||
int SimWire::available()
|
||||
{
|
||||
// TODO: This needs to be implemented!!
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
size_t SimWire::write(uint8_t __attribute__((unused)) data)
|
||||
{
|
||||
// // TODO: Verify that bus is in write mode.
|
||||
// if( current_slave_ != NULL ) {
|
||||
// current_slave_->i2cWriteData( data );
|
||||
// } else {
|
||||
printf("No slave selected i2c writes to the void.\n");
|
||||
// }
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Wire.h"
|
||||
|
||||
/********************************
|
||||
*
|
||||
*/
|
||||
|
||||
SimWire::SimWire( bool verbose )
|
||||
: verbose_( verbose )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SimWire::setClock(uint32_t)
|
||||
{
|
||||
// Ignore.. lol
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SimWire::begin()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SimWire::beginTransmission(uint8_t address)
|
||||
{
|
||||
if( verbose_ )
|
||||
printf("[SimWire::beginTransmission] $%02x\n", address);
|
||||
}
|
||||
|
||||
|
||||
void SimWire::beginTransmission(int address)
|
||||
{
|
||||
beginTransmission((uint8_t)address);
|
||||
}
|
||||
|
||||
|
||||
uint8_t SimWire::endTransmission()
|
||||
{
|
||||
if( verbose_ )
|
||||
printf("[SimWire::endTransmission]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t SimWire::endTransmission(uint8_t what)
|
||||
{
|
||||
if( verbose_ )
|
||||
printf("[SimWire::endTransmission %d]\n", what);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t SimWire::requestFrom(uint8_t address, uint8_t count)
|
||||
{
|
||||
if( verbose_ )
|
||||
printf("[SimWire::requestFrom] $%02x for %d bytes\n", address, count);
|
||||
|
||||
// TODO: We must check if there is an actual slave for that address.
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SimWire::read()
|
||||
{
|
||||
// TODO: Verify that bus is in read mode.
|
||||
// if( current_slave_ != NULL ) {
|
||||
// return current_slave_->i2cReadData( );
|
||||
// } else {
|
||||
printf("No slave selected, returning ones\n");
|
||||
return 0xffu;
|
||||
// }
|
||||
}
|
||||
|
||||
int SimWire::available()
|
||||
{
|
||||
// TODO: This needs to be implemented!!
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
size_t SimWire::write(uint8_t __attribute__((unused)) data)
|
||||
{
|
||||
// // TODO: Verify that bus is in write mode.
|
||||
// if( current_slave_ != NULL ) {
|
||||
// current_slave_->i2cWriteData( data );
|
||||
// } else {
|
||||
printf("No slave selected i2c writes to the void.\n");
|
||||
// }
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,73 +1,73 @@
|
|||
NuEVI and NuRAD Firmware 1.5b8 Notes
|
||||
|
||||
1.5b1:
|
||||
|
||||
* Improved polyphonic play functions. Rotator menu is now replaced with a Poly Play menu where you find a variety of harmonization options, including three rotator setups. (Se separate manual page).
|
||||
|
||||
* Automatic sensor calibration when performing factory restore (so do mind that you don’t touch sensors when you do the reset).
|
||||
|
||||
* I2C communications speed issue solved.
|
||||
|
||||
* Adjustable MIDI CC time intervals for the breath messages, from 3ms to 15ms. For wireless play, lower setting than the default 6ms is not recommended. (BR INTERV setting in SETUP BR menu).
|
||||
|
||||
* Improved touch sensor reading equalization for NuRAD, for more coherent sensitivity between keys.
|
||||
|
||||
* Minor fix for NuRAD SAX fingering (LH2+RH2 now plays Bb).
|
||||
|
||||
* Gate hold function now works on NuRAD too.
|
||||
|
||||
1.5b2:
|
||||
|
||||
* Adjustment setting for thumb lever (for optimizing thumb portamento control). By setting THR (level of push force to activate) and MAX (level of push force to achieve maximum set portamento) values close to eachother at the desired point of activation, the new glide limit setting to desired rate will create a switching type set rate controller (similar to Crumar EVI glide key). With THR and MAX setup with separation to taste, a continous control up to level set by glide limit is achieved.
|
||||
|
||||
* Glide setting SWO, SWitching Only, sending only Glide on/off (CC#65) for use with synths where glide rate CC#5 is used in non standard ways, for example some DSI/Sequential synths like the Prophet REV2 or Prophet 12 where glide rates are set individually for each oscillator.
|
||||
|
||||
* Glide limit setting for portamento. Doubles as setting for portamento level sent using pinky key/mod key in GLD mode. (Can be changed both in menu and in GLD mode.)
|
||||
|
||||
* Setting of level for LVL, LVP and GLD now reqires touching both pinky/mod and third trill/RHp3 for setting mode activation, this to avoid accidental change of setting when pinky/mod key is touched.
|
||||
|
||||
* Rate of setting movement up and down for LVL, LVP and GLD has been adjusted. Became very much too fast after the timing issues were solved in 1.5b1
|
||||
|
||||
* A short delay before note offs in legato transitions is added to make playback of recorded midi behave correctly (keeping note on and note off from being registered on the same timestamp).
|
||||
|
||||
1.5b3:
|
||||
|
||||
* AUTOCAL is available for each ADJUST menu page. With cursor on THR or MAX bar, press UP and DOWN buttons at the same time (and keep off the sensors being calibrated). AUTOCAL will be displayed for two seconds, then updated settings will be shown.
|
||||
|
||||
1.5b4:
|
||||
|
||||
* Changed the destination setup for bite and lever to be less confusing and more powerful (custom CCs now possible). The VIB CTL item in the VIBRATO menu is now removed, and in SETUP CTL menu you will find BITE CTL, BITE CC, LEVER CTL and LEVER CC.
|
||||
|
||||
BITE CTL and LEVER CTL can both be set to any of these destinations:
|
||||
OFF - no destination active for this controller
|
||||
VIB - vibrato
|
||||
GLD - glide/portamento (defined by GLIDE MOD and GLIDE LMT settings)
|
||||
CC - custom CC output (defined in GLIDE CC and LEVER CC settings)
|
||||
|
||||
Settings in GLIDE CC and LEVER CC are only used when corresponding control is set to CC in its CTL setting as described above.
|
||||
|
||||
1.5b5:
|
||||
|
||||
* Changed names for ADJUST page titles (to shorten) and added numerical value readouts for THR and MAX settings.
|
||||
|
||||
* Corrected start position for rotators and added reset to first position when activated and on roller release (from top five octaves like for the otf key change).
|
||||
|
||||
1.5b6
|
||||
|
||||
* Added EVR to NuEVI fingering menu, for reversed roller action.
|
||||
|
||||
* Rebooting to program mode now possible when stuck at boot due to wrong version of firmware installed (NuEVI vs NuRAD version).
|
||||
|
||||
* Removed possibility to change portamento limit using pinky/mod key when in GLD setting (it was always getting altered in play or handling). This might come back if I find a better way to do it.
|
||||
|
||||
* Support for a CME WIDI Master Bluetooth MIDI board connected to Teensy underside pads. With this mod, if present it will be powered up by touching pinky/mod key and pressing enter in MIDI meny (what previously controlled the "slow midi" function that now is replaced by the CC interval menu item). "WIDI" will be indicated in the display below the MIDI channel number and the WIDI board will be powered up. Teensy pad connections: GND to GND (blue) of WIDI, 31 (TX2) via 47 ohm resistor to signal (green) of WIDI, 33 via 47 ohm resistor to power (red) of WIDI. 27 and 28 jumpered to indicate that the WIDI is connected.
|
||||
|
||||
1.5b7:
|
||||
|
||||
* Added three new settings in EXTRAS MENU – CV TUNE, CV SCALE and CV EC LFO. The first two allow for software tuning of the CV output for 1V/Oct when using NuEVI CV, NuEVI Plus or NuEVI/NuRAD with external CV box or module. Also makes more simple versions of the CV boards possible (no potentiometers for adjustment). The CV EC LFO setting controls a new CV LFO vibrato function for the extra controller (lip sensor). It can be set to OFF (no extra controller LFO vibrato) or values 1 through 8, which represent vibrato freq from 4.5Hz to 8Hz. Default value is 3 (5.5Hz).
|
||||
|
||||
1.5b8:
|
||||
|
||||
* New quarter tone setting for Pinky Key (NuEVI) and Mod Key (NuRAD) – QTN. This makes the Pinky/Mod key a key for playing one quarter tone down using pitchbend (MIDI) or directly affecting the built in note CV output (using CV module or NuEVI CV/Plus). Pitch bend range for MIDI synth needs to be two semitones up/dn (or compensated for in pitch bend divider setting in the controller to make the resulting range two semitones up/dn). On NuRAD, it is recommended to set the 3rd LH Pinky key (EXTRA PKEY setting) to mirror MOD key for playablility.
|
||||
|
||||
NuEVI and NuRAD Firmware 1.5b8 Notes
|
||||
|
||||
1.5b1:
|
||||
|
||||
* Improved polyphonic play functions. Rotator menu is now replaced with a Poly Play menu where you find a variety of harmonization options, including three rotator setups. (Se separate manual page).
|
||||
|
||||
* Automatic sensor calibration when performing factory restore (so do mind that you don’t touch sensors when you do the reset).
|
||||
|
||||
* I2C communications speed issue solved.
|
||||
|
||||
* Adjustable MIDI CC time intervals for the breath messages, from 3ms to 15ms. For wireless play, lower setting than the default 6ms is not recommended. (BR INTERV setting in SETUP BR menu).
|
||||
|
||||
* Improved touch sensor reading equalization for NuRAD, for more coherent sensitivity between keys.
|
||||
|
||||
* Minor fix for NuRAD SAX fingering (LH2+RH2 now plays Bb).
|
||||
|
||||
* Gate hold function now works on NuRAD too.
|
||||
|
||||
1.5b2:
|
||||
|
||||
* Adjustment setting for thumb lever (for optimizing thumb portamento control). By setting THR (level of push force to activate) and MAX (level of push force to achieve maximum set portamento) values close to eachother at the desired point of activation, the new glide limit setting to desired rate will create a switching type set rate controller (similar to Crumar EVI glide key). With THR and MAX setup with separation to taste, a continous control up to level set by glide limit is achieved.
|
||||
|
||||
* Glide setting SWO, SWitching Only, sending only Glide on/off (CC#65) for use with synths where glide rate CC#5 is used in non standard ways, for example some DSI/Sequential synths like the Prophet REV2 or Prophet 12 where glide rates are set individually for each oscillator.
|
||||
|
||||
* Glide limit setting for portamento. Doubles as setting for portamento level sent using pinky key/mod key in GLD mode. (Can be changed both in menu and in GLD mode.)
|
||||
|
||||
* Setting of level for LVL, LVP and GLD now reqires touching both pinky/mod and third trill/RHp3 for setting mode activation, this to avoid accidental change of setting when pinky/mod key is touched.
|
||||
|
||||
* Rate of setting movement up and down for LVL, LVP and GLD has been adjusted. Became very much too fast after the timing issues were solved in 1.5b1
|
||||
|
||||
* A short delay before note offs in legato transitions is added to make playback of recorded midi behave correctly (keeping note on and note off from being registered on the same timestamp).
|
||||
|
||||
1.5b3:
|
||||
|
||||
* AUTOCAL is available for each ADJUST menu page. With cursor on THR or MAX bar, press UP and DOWN buttons at the same time (and keep off the sensors being calibrated). AUTOCAL will be displayed for two seconds, then updated settings will be shown.
|
||||
|
||||
1.5b4:
|
||||
|
||||
* Changed the destination setup for bite and lever to be less confusing and more powerful (custom CCs now possible). The VIB CTL item in the VIBRATO menu is now removed, and in SETUP CTL menu you will find BITE CTL, BITE CC, LEVER CTL and LEVER CC.
|
||||
|
||||
BITE CTL and LEVER CTL can both be set to any of these destinations:
|
||||
OFF - no destination active for this controller
|
||||
VIB - vibrato
|
||||
GLD - glide/portamento (defined by GLIDE MOD and GLIDE LMT settings)
|
||||
CC - custom CC output (defined in GLIDE CC and LEVER CC settings)
|
||||
|
||||
Settings in GLIDE CC and LEVER CC are only used when corresponding control is set to CC in its CTL setting as described above.
|
||||
|
||||
1.5b5:
|
||||
|
||||
* Changed names for ADJUST page titles (to shorten) and added numerical value readouts for THR and MAX settings.
|
||||
|
||||
* Corrected start position for rotators and added reset to first position when activated and on roller release (from top five octaves like for the otf key change).
|
||||
|
||||
1.5b6
|
||||
|
||||
* Added EVR to NuEVI fingering menu, for reversed roller action.
|
||||
|
||||
* Rebooting to program mode now possible when stuck at boot due to wrong version of firmware installed (NuEVI vs NuRAD version).
|
||||
|
||||
* Removed possibility to change portamento limit using pinky/mod key when in GLD setting (it was always getting altered in play or handling). This might come back if I find a better way to do it.
|
||||
|
||||
* Support for a CME WIDI Master Bluetooth MIDI board connected to Teensy underside pads. With this mod, if present it will be powered up by touching pinky/mod key and pressing enter in MIDI meny (what previously controlled the "slow midi" function that now is replaced by the CC interval menu item). "WIDI" will be indicated in the display below the MIDI channel number and the WIDI board will be powered up. Teensy pad connections: GND to GND (blue) of WIDI, 31 (TX2) via 47 ohm resistor to signal (green) of WIDI, 33 via 47 ohm resistor to power (red) of WIDI. 27 and 28 jumpered to indicate that the WIDI is connected.
|
||||
|
||||
1.5b7:
|
||||
|
||||
* Added three new settings in EXTRAS MENU – CV TUNE, CV SCALE and CV EC LFO. The first two allow for software tuning of the CV output for 1V/Oct when using NuEVI CV, NuEVI Plus or NuEVI/NuRAD with external CV box or module. Also makes more simple versions of the CV boards possible (no potentiometers for adjustment). The CV EC LFO setting controls a new CV LFO vibrato function for the extra controller (lip sensor). It can be set to OFF (no extra controller LFO vibrato) or values 1 through 8, which represent vibrato freq from 4.5Hz to 8Hz. Default value is 3 (5.5Hz).
|
||||
|
||||
1.5b8:
|
||||
|
||||
* New quarter tone setting for Pinky Key (NuEVI) and Mod Key (NuRAD) – QTN. This makes the Pinky/Mod key a key for playing one quarter tone down using pitchbend (MIDI) or directly affecting the built in note CV output (using CV module or NuEVI CV/Plus). Pitch bend range for MIDI synth needs to be two semitones up/dn (or compensated for in pitch bend divider setting in the controller to make the resulting range two semitones up/dn). On NuRAD, it is recommended to set the 3rd LH Pinky key (EXTRA PKEY setting) to mirror MOD key for playablility.
|
||||
|
||||
* Changes to extra controller harmonics settings (experimental). Reverse direction options (ending with an ‘R’) available following the ones going up. This can be used with experimental mouthpieces where increased lip tension creates less touched sensor area.
|
||||
|
|
@ -1,68 +1,68 @@
|
|||
POLY PLAY
|
||||
|
||||
In the Poly Play menu you configure everything having to do with polyphonic playing functions.
|
||||
|
||||
POLY PLAY – POLY MODE
|
||||
|
||||
Here you select which type of harmonization or which rotator setup will be activated by touching/holding MOD key (NuRAD) or Pinky Key (NuEVI) and then touching Special Key(s). Deactivate by just touching Special Key(s).
|
||||
|
||||
OFF – disables all Special Key functionality, including the Parallel Chord, Slur Sustain and Sub Octave functions
|
||||
MGR – Major Gospel Root – a gospel type triad voicing
|
||||
MGD – Major Gospel Dominant – same as MGR, but with a dominant on V instead of an inversion of the root
|
||||
MA9 – Major add9 – pop style add9 harmonization
|
||||
MND – minor Dorian – jazz type minor
|
||||
MNA – minor Aeolian – classical minor
|
||||
MNH – minor 4-voice Hip – a more hip dorian minor
|
||||
FWC – Four Way Close – old school block chord harmony (with additional options further down in the Poly Play menu)
|
||||
RTA – Rotator A
|
||||
RTB – Rotator B
|
||||
RTC - Rotator C
|
||||
|
||||
POLY PLAY – HMZ KEY
|
||||
|
||||
Selects the key you are playing in for the key based harmonizations.
|
||||
|
||||
POLY PLAY – OTF KEY
|
||||
|
||||
Enables on the fly key change for the key based harmonizers. To change key on the fly while playing, finger the key (not blowing) and briefly lift your thumb off the rollers (when in octave two or higher). Key change on the fly will not be stored when powered off.
|
||||
|
||||
POLY PLAY – HMZ LIMIT
|
||||
|
||||
Limits the number of voices to be played, starting elimination from lowest note and up. Applies to the key based harmonizations only, not Rotator, Parallel Chord or Slur Sustain.
|
||||
|
||||
POLY PLAY – FWC TYPE
|
||||
|
||||
Type of block chord for the Four Way Close harmonization. (6, m6, 7 or m7)
|
||||
|
||||
POLY PLAY – FWC LOCKH
|
||||
|
||||
"Lock Hands" (double melody) adds another melody note one octave down for the Four Way Close harmonizations. (OFF/ON)
|
||||
|
||||
POLY PLAY – FWC DROP2
|
||||
|
||||
"Drop 2" moves the second note (the one below melody note) one octave down for the FWC. (OFF/ON)
|
||||
|
||||
POLY PLAY – PRIORITY
|
||||
|
||||
Sets which note will get priority when playing mono patches (sounds really great to layer a mono patch with a poly patch for use with with the Poly Play functions). MEL will play the melody note as the mono lead and ROT will play the rotated note or last note of other poly modes.
|
||||
|
||||
POLY PLAY – RTA PARAL
|
||||
POLY PLAY – RTA ROT 1
|
||||
POLY PLAY – RTA ROT 2
|
||||
POLY PLAY – RTA ROT 3
|
||||
POLY PLAY – RTA ROT 4
|
||||
|
||||
POLY PLAY – RTB PARAL
|
||||
POLY PLAY – RTB ROT 1
|
||||
POLY PLAY – RTB ROT 2
|
||||
POLY PLAY – RTB ROT 3
|
||||
POLY PLAY – RTB ROT 4
|
||||
|
||||
POLY PLAY – RTC PARAL
|
||||
POLY PLAY – RTC ROT 1
|
||||
POLY PLAY – RTC ROT 2
|
||||
POLY PLAY – RTC ROT 3
|
||||
POLY PLAY – RTC ROT 4
|
||||
|
||||
This last section of settings is for the three rotators. They create a three note chord using the melody note, a fixed interval parallel note and a third note taken from a rotating selection of four notes. For every new note triggered, the rotation is advanced one step, and a new combination of notes is played. For each uf the three selectable rotator setups you can configure the fixed interval with RTx PARAL and the four intervals to be rotated for the third note with RTx ROT 1 to RTx ROT4, where x represents rotators A through C.
|
||||
|
||||
POLY PLAY
|
||||
|
||||
In the Poly Play menu you configure everything having to do with polyphonic playing functions.
|
||||
|
||||
POLY PLAY – POLY MODE
|
||||
|
||||
Here you select which type of harmonization or which rotator setup will be activated by touching/holding MOD key (NuRAD) or Pinky Key (NuEVI) and then touching Special Key(s). Deactivate by just touching Special Key(s).
|
||||
|
||||
OFF – disables all Special Key functionality, including the Parallel Chord, Slur Sustain and Sub Octave functions
|
||||
MGR – Major Gospel Root – a gospel type triad voicing
|
||||
MGD – Major Gospel Dominant – same as MGR, but with a dominant on V instead of an inversion of the root
|
||||
MA9 – Major add9 – pop style add9 harmonization
|
||||
MND – minor Dorian – jazz type minor
|
||||
MNA – minor Aeolian – classical minor
|
||||
MNH – minor 4-voice Hip – a more hip dorian minor
|
||||
FWC – Four Way Close – old school block chord harmony (with additional options further down in the Poly Play menu)
|
||||
RTA – Rotator A
|
||||
RTB – Rotator B
|
||||
RTC - Rotator C
|
||||
|
||||
POLY PLAY – HMZ KEY
|
||||
|
||||
Selects the key you are playing in for the key based harmonizations.
|
||||
|
||||
POLY PLAY – OTF KEY
|
||||
|
||||
Enables on the fly key change for the key based harmonizers. To change key on the fly while playing, finger the key (not blowing) and briefly lift your thumb off the rollers (when in octave two or higher). Key change on the fly will not be stored when powered off.
|
||||
|
||||
POLY PLAY – HMZ LIMIT
|
||||
|
||||
Limits the number of voices to be played, starting elimination from lowest note and up. Applies to the key based harmonizations only, not Rotator, Parallel Chord or Slur Sustain.
|
||||
|
||||
POLY PLAY – FWC TYPE
|
||||
|
||||
Type of block chord for the Four Way Close harmonization. (6, m6, 7 or m7)
|
||||
|
||||
POLY PLAY – FWC LOCKH
|
||||
|
||||
"Lock Hands" (double melody) adds another melody note one octave down for the Four Way Close harmonizations. (OFF/ON)
|
||||
|
||||
POLY PLAY – FWC DROP2
|
||||
|
||||
"Drop 2" moves the second note (the one below melody note) one octave down for the FWC. (OFF/ON)
|
||||
|
||||
POLY PLAY – PRIORITY
|
||||
|
||||
Sets which note will get priority when playing mono patches (sounds really great to layer a mono patch with a poly patch for use with with the Poly Play functions). MEL will play the melody note as the mono lead and ROT will play the rotated note or last note of other poly modes.
|
||||
|
||||
POLY PLAY – RTA PARAL
|
||||
POLY PLAY – RTA ROT 1
|
||||
POLY PLAY – RTA ROT 2
|
||||
POLY PLAY – RTA ROT 3
|
||||
POLY PLAY – RTA ROT 4
|
||||
|
||||
POLY PLAY – RTB PARAL
|
||||
POLY PLAY – RTB ROT 1
|
||||
POLY PLAY – RTB ROT 2
|
||||
POLY PLAY – RTB ROT 3
|
||||
POLY PLAY – RTB ROT 4
|
||||
|
||||
POLY PLAY – RTC PARAL
|
||||
POLY PLAY – RTC ROT 1
|
||||
POLY PLAY – RTC ROT 2
|
||||
POLY PLAY – RTC ROT 3
|
||||
POLY PLAY – RTC ROT 4
|
||||
|
||||
This last section of settings is for the three rotators. They create a three note chord using the melody note, a fixed interval parallel note and a third note taken from a rotating selection of four notes. For every new note triggered, the rotation is advanced one step, and a new combination of notes is played. For each uf the three selectable rotator setups you can configure the fixed interval with RTx PARAL and the four intervals to be rotated for the third note with RTx ROT 1 to RTx ROT4, where x represents rotators A through C.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue