First commit
Working on serial connection on Arduino side
This commit is contained in:
commit
12a04887fd
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.vscode
|
||||||
|
*.code-workspace
|
2
README.md
Normal file
2
README.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Arduino-mixer
|
||||||
|
Arduino gadget to control the Windows audio mixer using Python
|
322
arduino-mixer.ino
Normal file
322
arduino-mixer.ino
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
#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);
|
||||||
|
|
||||||
|
unsigned long time;
|
||||||
|
int connected = 0;
|
||||||
|
int editing = 0;
|
||||||
|
int blink = 0;
|
||||||
|
|
||||||
|
long position = 0;
|
||||||
|
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
int menuUpdate = 1;
|
||||||
|
int volume;
|
||||||
|
|
||||||
|
// Draw screen
|
||||||
|
void drawMenu(String 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
|
||||||
|
void drawName(String 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: Add rotary encoder support
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const byte numChars = 32;
|
||||||
|
char receivedChars[numChars];
|
||||||
|
char tempChars[numChars];
|
||||||
|
|
||||||
|
char command[numChars] = {0};
|
||||||
|
int data = 0;
|
||||||
|
|
||||||
|
boolean newData = false;
|
||||||
|
|
||||||
|
void processData() {
|
||||||
|
if (newData == true) {
|
||||||
|
Serial.print("Raw data recieved: ");
|
||||||
|
Serial.println(receivedChars);
|
||||||
|
|
||||||
|
strcpy(tempChars, receivedChars);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
char * strtokIndx; // this is used by strtok() as an index
|
||||||
|
|
||||||
|
strtokIndx = strtok(tempChars,","); // get the first part - the string
|
||||||
|
strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
|
||||||
|
|
||||||
|
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
|
||||||
|
integerFromPC = atoi(strtokIndx); // convert this part to an integer
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
// TODO: Get serial data for program
|
||||||
|
switch (currentProgram)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
drawMenu("Firefox", volume);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
drawMenu("Discord", volume);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
drawMenu("Steam", volume);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
python/start.py
Normal file
37
python/start.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
from pycaw.pycaw import AudioUtilities
|
||||||
|
from pprint import pprint
|
||||||
|
import serial
|
||||||
|
import serial.tools.list_ports
|
||||||
|
import time
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print ("Starting Arduino Mixer...\n")
|
||||||
|
|
||||||
|
# Get audio sessions
|
||||||
|
sessions = AudioUtilities.GetAllSessions()
|
||||||
|
print (str(len(sessions)) + " audio sessions found:")
|
||||||
|
for session in sessions:
|
||||||
|
volume = session.SimpleAudioVolume
|
||||||
|
print (" " + str(session.Process))
|
||||||
|
|
||||||
|
# Init serial connection
|
||||||
|
ports = serial.tools.list_ports.comports()
|
||||||
|
if len(ports) == 0:
|
||||||
|
print("\nNo Serial ports Available")
|
||||||
|
exit()
|
||||||
|
else:
|
||||||
|
print ("\nSerial ports Available:")
|
||||||
|
for port, desc, hwid in sorted(ports):
|
||||||
|
print(" {}: {} [{}]".format(port, desc, hwid))
|
||||||
|
|
||||||
|
board = serial.Serial()
|
||||||
|
board.baudrate = 115200
|
||||||
|
board.port = input("\nSelect COM port: ")
|
||||||
|
board.open()
|
||||||
|
|
||||||
|
time.sleep(5)
|
||||||
|
board.write("HELLO".encode("utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user