Skip to content

Instantly share code, notes, and snippets.

@parastuffs
Created November 9, 2023 09:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save parastuffs/2e9e98b5bcdfc7c70aec5b745d73096b to your computer and use it in GitHub Desktop.
Save parastuffs/2e9e98b5bcdfc7c70aec5b745d73096b to your computer and use it in GitHub Desktop.
#include "Arduino.h"
#include "Audio.h"
#include "BluetoothSerial.h" //Header File for Serial Bluetooth, will be added by default into Arduino
#include "FS.h"
#define SD_CS 5
#define SPI_MOSI 23
#define SPI_MISO 19
#define SPI_SCK 18
#define button_A 4 // Top face
#define button_B 32 // Board side
#define button_C 33 // Speaker side
#define button_D 15 // Left side
#define button_E 13 // Right side
/* Alpha: Always play sound */
//#define MODE_ALPHA
/* Beta: No sound */
//#define MODE_BETA
/* Gamma: Sound / No sound */
// #define MODE_GAMMA
/* Delta (YesNoYes): No sound / No sound / Sound */
#define MODE_DELTA
/**
* Global variables
*/
int i;
unsigned long curtime;
File myFile;
const char* exp_ID_filename = "/exp_ID.txt"; // For some reason, the leading '/' is now required.
const char* exp_filename_base = "/exp_";
const char* exp_filename_extension = ".csv";
String exp_filename;
char buf[4];
int exp_ID = 0;
#ifdef MODE_ALPHA
const char* measures_header = "observation, face, pression_start, pression_stop, sound, isExperiment, alpha";
#endif
#ifdef MODE_BETA
const char* measures_header = "observation, face, pression_start, pression_stop, sound, isExperiment, beta";
#endif
#ifdef MODE_GAMMA
const char* measures_header = "observation, face, pression_start, pression_stop, sound, isExperiment, gamma";
#endif
#ifdef MODE_DELTA
const char* measures_header = "observation, face, pression_start, pression_stop, sound, isExperiment, delta";
#endif
bool triggered[5] = {false, false, false, false, false};
bool rising_edge[5] = {false, false, false, false, false};
bool falling_edge[5] = {false, false, false, false, false};
unsigned long rising_time[5] = {0, 0, 0, 0, 0};
unsigned int cur_obs = 1;
unsigned int demo_press_count = 0;
bool isStandby = true; // True, don't do anything in the main loop.
bool isExperiment = true; // False is demo, true is experiment
BluetoothSerial BtSerial; // Object for Bluetooth
Audio audio(true, I2S_DAC_CHANNEL_BOTH_EN);
bool eof = false;
void(* resetFunc) (void) = 0;
void audio_eof_mp3(const char *info){ //end of file
eof = true;
}
void play_audio() {
while(not eof) {
audio.loop();
}
eof = false;
//audio.connecttoFS(SD, "/bird.mp3");
audio.connecttoFS(SD, "/sound.mp3");
}
/** **********************
*
* SETUP
*
* ***********************
*/
void setup() {
delay(100);
Serial.begin(115200);
/* Don't know why the delay works, but it avoids to run the setup twice, creating empty experiments. */
delay(1000);
Serial.println("Starting setup");
#ifdef MODE_ALPHA
BtSerial.begin("Cube_alpha"); // Name of Bluetooth Module
#endif
#ifdef MODE_BETA
BtSerial.begin("Cube_beta"); // Name of Bluetooth Module
#endif
#ifdef MODE_GAMMA
BtSerial.begin("Cube_gamma"); // Name of Bluetooth Module
#endif
#ifdef MODE_DELTA
BtSerial.begin("Cube_delta"); // Name of Bluetooth Module
#endif
delay(500);
Serial.println("Bluetooth Cube is Ready to Pair");
pinMode(SD_CS, OUTPUT);
digitalWrite(SD_CS, HIGH);
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
SPI.setFrequency(1000000);
if(!SD.begin(SD_CS)){
Serial.println("Card Mount Failed, reset.");
resetFunc();
return;
}
pinMode(button_A, INPUT);
pinMode(button_B, INPUT);
pinMode(button_C, INPUT);
pinMode(button_D, INPUT);
pinMode(button_E, INPUT);
newExperimentFile();
// listDir(SD, "/", 0);
audio.setVolume(21); // 0...21
audio.connecttoFS(SD, "/sound.mp3");
//play_audio();
}
/** **********************
*
* MAIN LOOP
*
* ***********************
*/
void loop()
{
if (BtSerial.available()) { // Check if we receive anything from Bluetooth
char incoming = BtSerial.read(); //Read what we recevive
Serial.print("Received:");
Serial.println(incoming);
if (incoming == '1') {
BtSerial.println("Starting experiment...");
//play_audio();
isExperiment = true;
isStandby = false;
}
else if (incoming == '0') {
BtSerial.println("Demonstration activated...");
isExperiment = false;
isStandby = false;
}
else if (incoming == '2') {
BtSerial.println("Back to standby.");
newExperimentFile();
isStandby = true;
}
}
if(!isExperiment && !isStandby) {
demoRoutine();
}
else if(isExperiment && !isStandby) {
experimentRoutine();
}
delay(20);
}
void audio_info(const char *info) {
Serial.print("info "); Serial.println(info);
}
/** **********************
*
* DEMONSTRATION ROUTINE
*
* ***********************
*/
void demoRoutine()
{
scanButtons(isExperiment);
#ifdef MODE_ALPHA
if(digitalRead(button_A) || digitalRead(button_B) || digitalRead(button_C) || digitalRead(button_D) || digitalRead(button_E)) {
play_audio();
/* Delay for a time, limiting multiple concurrent presses and overlapping sounds. */
delay(300);
}
#endif
#ifdef MODE_GAMMA
if(digitalRead(button_A) || digitalRead(button_B) || digitalRead(button_C) || digitalRead(button_D) || digitalRead(button_E)) {
demo_press_count ++;
if(demo_press_count == 2) {
play_audio();
demo_press_count = 0;
}
/* Delay for a time, limiting multiple concurrent presses and overlapping sounds. */
delay(300);
}
#endif
#ifdef MODE_DELTA
if(digitalRead(button_A) || digitalRead(button_B) || digitalRead(button_C) || digitalRead(button_D) || digitalRead(button_E)) {
demo_press_count ++;
if(demo_press_count == 8) {
play_audio();
demo_press_count = 0;
}
/* Delay for a time, limiting multiple concurrent presses and overlapping sounds. */
delay(300);
}
#endif
#ifdef MODE_BETA
/* Nothing happens in this mode. */
#endif
}
/** **********************
*
* EXPERIMENT ROUTINE
*
* ***********************
*/
void experimentRoutine()
{
scanButtons(isExperiment);
delay(5);
}
void scanButtons(bool isXP){
curtime = millis();
// TODO FACTORISE THIS!
if(digitalRead(button_A)){
Serial.print("A");
rising_edge[0] = true;
}
else if (!digitalRead(button_A) && rising_edge[0]) {
rising_edge[0] = false;
falling_edge[0] = true;
}
if(digitalRead(button_B)){
Serial.print("B");
rising_edge[1] = true;
}
else if(!digitalRead(button_B) && rising_edge[1]){
rising_edge[1] = false;
falling_edge[1] = true;
}
if(digitalRead(button_C)){
Serial.print("C");
rising_edge[2] = true;
}
else if(!digitalRead(button_C) && rising_edge[2]){
rising_edge[2] = false;
falling_edge[2] = true;
}
if(digitalRead(button_D)){
Serial.print("D");
rising_edge[3] = true;
}
else if(!digitalRead(button_D) && rising_edge[3]){
rising_edge[3] = false;
falling_edge[3] = true;
}
if(digitalRead(button_E)){
Serial.print("E");
rising_edge[4] = true;
}
else if(!digitalRead(button_E) && rising_edge[4]){
rising_edge[4] = false;
falling_edge[4] = true;
}
for(i=0;i<5;i++) {
if(rising_edge[i] && !triggered[i]) {
rising_time[i] = curtime;
triggered[i] = true;
}
}
for(i=0;i<5;i++) {
if(falling_edge[i]) {
//measures_header = "observation, face, pression_start, pression_stop, sound, isExperiment";
String measure_str = String(cur_obs) + "," + String(i+1) + "," + String(rising_time[i]) + "," + String(curtime) + "," + 0 + "," + isXP;
Serial.println("Writing this line to the SD card:");
Serial.println(measure_str);
/* Write to SD card, then immediatly flush the data to make sure it's actually written.
* This removes the need to close the file handler. We can shut down the system without
* corrupting the SD card data.
*/
myFile = SD.open(exp_filename, FILE_APPEND);
myFile.println(measure_str);
myFile.close();
cur_obs++;
triggered[i] = false;
falling_edge[i] = false;
}
}
}
void newExperimentFile(){
Serial.println("Creating a new experiment file.");
/* Determine the experiment ID */
if(!SD.exists(exp_ID_filename)) {
Serial.println("The experiment list file does not exist yet");
exp_ID = 1;
writeFile(SD, exp_ID_filename, "1");
}
else {
Serial.println("ID file exists");
myFile = SD.open(exp_ID_filename, FILE_READ);
while(myFile.available()) {
int max_len = myFile.available();
int read_len = myFile.readBytesUntil('\n', buf, max_len);
exp_ID = atoi(buf);
}
myFile.close();
Serial.println("ID read:");
Serial.println(String(exp_ID));
exp_ID += 1;
Serial.print("Experiment ID: ");
Serial.println(String(exp_ID));
myFile = SD.open(exp_ID_filename, FILE_WRITE);
myFile.println(String(exp_ID));
myFile.close();
}
/* Craft a new experiment file */
exp_filename = String(exp_filename_base) + exp_ID + exp_filename_extension;
Serial.print("New experiment filename: ");
Serial.println(exp_filename);
myFile = SD.open(exp_filename, FILE_WRITE);
myFile.println(measures_header);
/* Do not close the file at this step, so that we can keep using it in the loop(). */
// myFile.flush();
myFile.close(); // If I want Bluetooth to work, I actually need to close the file. I can't keep it open.
}
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\n", dirname);
File root = fs.open(dirname);
if(!root){
Serial.println("Failed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while(file){
if(file.isDirectory()){
Serial.print(" DIR : ");
Serial.println(file.name());
if(levels){
listDir(fs, file.name(), levels -1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void readFile(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if(!file){
Serial.println("Failed to open file for reading");
return;
}
Serial.print("Read from file: ");
while(file.available()){
Serial.write(file.read());
}
file.close();
}
void writeFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
if(file.print(message)){
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}
void appendFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file){
Serial.println("Failed to open file for appending");
return;
}
if(file.print(message)){
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
file.close();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment