arduino-mixer/arduino-mixer.ino

345 lines
7.3 KiB
C++

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <Fonts/Picopixel.h>
#include <Button.h>
#include <Encoder.h>
Adafruit_PCD8544 display = Adafruit_PCD8544(14, 15, 16, 17, 18);
Button button(4);
Encoder encoder(3, 2);
// General vars
unsigned long time;
int connected = 0;
int editing = 0;
int blink = 0;
// Encoder related vars
long position = 0;
// Serial related vars
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];
char command[numChars] = {0};
char data[numChars] = {0};
int intData = 0;
boolean newData = false;
// Set backlight
int light = 0;
int timeout = 10000;
void toggleBacklight(int value = 128) {
if (light) {
analogWrite(5, 0);
light = 0;
} else {
analogWrite(5, value);
light = 1;
}
}
// Set variables for menu
int programLenght;
int currentProgram = 0;
char programName[numChars] = {0};
int menuUpdate = 1;
float volume;
// Draw screen
void drawMenu(char name, float percentage) {
display.clearDisplay();
display.setFont(&Picopixel);
// Check for connection
if (connected == 1)
{
// Draw top bar
display.setCursor(0, 4);
display.print((String)(currentProgram + 1) + "/" + (String)(programLenght));
display.setCursor(73, 4);
display.print("USB");
}
display.drawLine(0, 6, 84, 6, BLACK);
display.setFont(NULL);
// Check for connection
if (connected == 1) {
// Program name
drawName(name);
// Volume Bar
drawBar(percentage);
} else {
// Blink connection message if not connected
if (time % 500 == 0)
{
blink = (blink == 0) ? 1 : 0;
}
if (blink == 0)
{
display.setCursor(9, 10);
display.print("Waiting for");
display.setCursor(12, 18);
display.print("Connection");
}
}
// Bottom Bar
display.drawLine(0, 38, 84, 38, BLACK);
if (connected == 1)
{
display.setCursor(0, 40);
if (editing == 1)
{
display.print(" - OK + ");
} else {
display.print(" < OK > ");
}
}
display.display();
}
// Bar position
const int pos[2] = { 4, 26 };
// Draw volume bar and text
void drawBar(float percentage) {
// Set fonts and size
display.setFont(&Picopixel);
display.setCursor(4, pos[1] - 2);
display.print("Volume:");
// Blink percentage if editing
if (editing == 1 && time % 500 == 0)
{
blink = (blink == 0) ? 1 : 0;
}
// Center percentage
if (percentage == 0) {
display.setCursor(39, pos[1] - 2);
} else if (percentage == 100) {
display.setCursor(36, pos[1] - 2);
} else {
display.setCursor(37, pos[1] - 2);
}
if (blink == 0)
{
display.print((String)round(percentage) + "%");
}
// Draw volume bar
display.drawRect(pos[0], pos[1], 76, 8, BLACK);
display.drawLine(pos[0], pos[1] + 8, pos[0], pos[1] + 9, BLACK);
display.drawPixel(pos[0] + (76 / 4) * 1 - 1, pos[1] + 8, BLACK);
display.drawLine(pos[0] + (76 / 4) * 2 - 1, pos[1] + 8, pos[0] + (76 / 4) * 2 - 1, pos[1] + 9, BLACK);
display.drawPixel(pos[0] + (76 / 4) * 3 - 1, pos[1] + 8, BLACK);
display.drawLine(pos[0] + 75, pos[1] + 8, pos[0] + 75, pos[1] + 9, BLACK);
display.fillRect(pos[0], pos[1], round(percentage / 100 * 76), 8, BLACK);
display.setFont(NULL);
}
// Draw program name in the middle of the display or scroll it
// TODO: Fix char lenght
void drawName(char name) {
int width = name.length() * 6;
if (width > 84)
{
// TODO: Make the text scroll if the name is too long
} else {
int x = (84 / 2) - (width / 2);
display.setCursor(x, 10);
}
display.print(name);
}
// Check for button input
// TODO: Improve encoder input
void checkInput(unsigned long time) {
long newPosition = encoder.read();
if (newPosition != position) {
menuUpdate = 1;
if (newPosition < position) // Rotating anti-clockwise
{
if (editing != 1)
{
if (currentProgram == 0)
{
currentProgram = programLenght - 1;
} else {
currentProgram--;
}
} else {
volume--;
}
}
if (newPosition > position) // Rotating clockwise
{
if (editing != 1)
{
if (currentProgram == programLenght - 1)
{
currentProgram = 0;
} else {
currentProgram++;
}
} else {
volume++;
}
}
position = newPosition;
}
if (button.pressed())
{
editing = (editing == 1) ? 0 : 1;
blink = 0;
}
}
void processData() {
if (newData == true) {
Serial.print("Raw data recieved: ");
Serial.println(receivedChars);
strcpy(tempChars, receivedChars);
char * strtokIndx;
strtokIndx = strtok(tempChars,",");
strcpy(command, strtokIndx);
Serial.print("Command: ");
Serial.println(command);
strtokIndx = strtok(NULL, ",");
if (atoi(strtokIndx) > 0) // Integer data
{
intData = atoi(strtokIndx);
Serial.print("Int data: ");
Serial.println(intData);
} else { // String data
strcpy(data, strtokIndx);
Serial.print("String data: ");
Serial.println(data);
}
if (strcmp("HELLO", command) == 0)
{
Serial.println("<OK>");
}
else if (strcmp("COUNT", command) == 0)
{
programLenght = intData;
}
else if (strcmp("NAME", command) == 0)
{
// Set program name
}
else if (strcmp("GETVOL", command) == 0)
{
// Set volume
}
newData = false;
}
}
void checkSerial() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
processData();
}
// Init arduino
void setup() {
// Start serial connection
Serial.begin(115200);
// Init button
button.begin();
// Init display
display.begin();
display.setContrast(50);
toggleBacklight();
display.clearDisplay();
display.display();
// TODO: Remove testing variables
programLenght = 3;
currentProgram = 0;
volume = 50;
connected = 1;
}
void loop() {
// Check time
time = millis();
menuUpdate = (time % 1000 == 0) ? 1 : 0;
// Check for serial data or commands
checkSerial();
// Check if serial connection is established
if (connected == 1)
{
// Draw menu every second or every 0.1 second when editing
if (menuUpdate == 1 || (editing == 1 && time % 100 == 0)) {
menuUpdate = 0;
drawMenu(programName, volume);
}
// Check input
checkInput(time);
} else {
if (menuUpdate == 1)
{
// Draw menu with "Waiting for connection", name and volume are ignored bij drawMenu()
menuUpdate = 0;
drawMenu("", 0.0);
}
}
}