// sss t 222 // s t 2 2 // s ttttt eee pppp 2 // sss t e e p p 2 // s t eeeee p p 2 // s t e p p 2 // ssss tt eeee pppp 22222 // p // p // include necessary libraries #include // for talking to shield #include // SD card library #include // MusicMaker library #include #include "avr/pgmspace.h" // used to store commands in program spac // create global object for ACode file File file_ACode; // placeholder variables for optional function arguments int optArg=0; // analog pin for AAEF inout #define soundPin A15 // Command list #define PlayMove 0 #define PlayScript 1 #define StartScript 2 #define EndScript 3 #define JumpTo 4 #define Label 5 #define SyncPoint 6 #define EndSync 7 #define ScriptPause 8 #define Say 9 #define RandomMove 10 #define RandomPause 11 #define CallScript 12 #define EndWait 13 #define NetWait 14 #define OneOnly 15 #define ActionSeq 16 // define pins used for control #define pausePin 27 #define runPin 25 #define gndPin 23 // define the pins used for the MusicMaker shield #define CLK 13 // SPI Clock, shared with SD card #define MISO 12 // Input data, from VS1053/SD card #define MOSI 11 // Output data, to VS1053/SD card #define SHIELD_CS 7 // VS1053 chip select pin (output) #define SHIELD_DCS 6 // VS1053 Data/command select pin (output) #define CARDCS 4 // Card chip select pin #define DREQ 3 // VS1053 Data request, ideally an Interrupt pin //debug default value #define optPArg -1 // setup move commands #include "pMoveCommands.h" // Script object int ScriptAction[127]; int ScriptDescription[127]; int ScriptOption[127]; int ScriptStack[127]; int ScriptSize; int ScriptStep; int MainScript; #define EndMain ScriptSize // initilize the Music Maker shield Adafruit_VS1053_FilePlayer audioplayer = Adafruit_VS1053_FilePlayer(SHIELD_CS, SHIELD_DCS, DREQ, CARDCS); // sss t // s t 4 4 // s ttttt eee pppp 4 4 // sss t e e p p 4 4 // s t eeeee p p 44444 // s t e p p 4 // ssss tt eeee pppp 4 // p 4 // p // ==================== // Function Definitions // ==================== // simple function used in when displaying step status void tab(int loc) { for (int i=1;i<=loc;i++){ Serial.print(F(" ")); } } // function used to display the status of A-Code byte code execution // After printing the player & step, the display indents the remaining // data. Action (in text) is always printed; the remainder are optional void displayStep(int player,int myStep, String displayAction, int displayDesc=optPArg, int displayOption=optPArg, int displayStack=optPArg) { Serial.print(player); Serial.print(F(":")); Serial.print(myStep); Serial.print(F("/")); tab(player); Serial.print(displayAction); if(displayDesc!=-1){ Serial.print(F(",")); Serial.print(displayDesc); } if (displayOption!=-1){ Serial.print(F(",")); Serial.print(displayOption); } if (displayStack!=-1){ Serial.print(F(",")); Serial.print(displayStack); } Serial.println(); } // sss t // s t 55555 // s ttttt eee pppp 5 // sss t e e p p 5 // s t eeeee p p 555 // s t e p p 5 // ssss tt eeee pppp 5555 // p // p boolean readln_ACode(int& action, int& desc=optArg, int& option=optArg, int& stack=optArg) /* Function to read ACode from SD card Parses each line into for comma separated values in the forn of "0,0,0,0" Any non-numeric value is ignored, so the file can be self-documenting. I.e., the following is valid input: Action=0,Desc-0,option=0,stack=o Parameters are defined by reference, so that the function dan return multiple (4) values. */ { String inputstring=""; int inputvalues[4]={0,0,0,0}; byte inputchar; byte index=0; boolean Done=false; inputchar='\0'; while ((! Done) && (file_ACode.available())) { inputchar=file_ACode.read(); if (inputchar==',') { // comma found, have chars for number inputvalues[index]=inputstring.toInt(); index ++; inputstring=""; } else { if (inputchar == 13 ) { // EOL found; last number found Done = true; inputvalues[index]=inputstring.toInt(); inputstring=""; } else { if (inputchar >= '0' && inputchar <='9') { // character is a digit; append to string inputstring=String(inputstring+String(char(inputchar))); } else { } } } } action =inputvalues[0]; // all Global variables desc =inputvalues[1]; option =inputvalues[2]; stack =inputvalues[3]; return file_ACode.available(); } // sss t // s t 666 // s ttttt eee pppp 6 // sss t e e p p 6 // s t eeeee p p 6666 // s t e p p 6 6 // ssss tt eeee pppp 666 // p // p // ==================== // Setup // ==================== void setup() { /* Initialize: Serial communications Random numbers ACode Sound shield */ boolean more=true; int index=0; int filler=0; Serial.begin(9600); Serial1.begin(9600); Serial.println("Requesting version"); Serial1.println("VER"); int count=0; char inputchar='\0'; while(count <= 13) { if (Serial1.available()) { inputchar=Serial1.read(); Serial.print(inputchar); count++; } Serial.println(); } randomSeed(analogRead(A0)); // Open serial communications and wait for port to open: if (! audioplayer.begin()) { // initialise the music player Serial.println(F("Couldn't find VS1053, do you have the right pins defined?")); while (true); } Serial.println(F("VS1053 found")); if (!SD.begin(CARDCS)) { Serial.println(F("initialization failed!")); while(true);} Serial.println(F("initialization done.")); // inititialize audio player/MusicMaker audioplayer.setVolume(20,20); // Set volume for left, right channels. lower numbers == louder volume! audioplayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT); // DREQ int if (! audioplayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT)) Serial.println(F("DREQ pin is not an interrupt pin")); // initializa SD card to read ACode Serial.print(F("Initializing SD card...")); pinMode(10, OUTPUT); if (SD.exists("ACode.csv")) { Serial.println(F("ACode.csv exists.")); } else { Serial.println(F("ACode.csv doesn't exist.")); while(true); } // setup tokenized program // open file Serial.println(F("Opening ACode.csv...")); file_ACode = SD.open("ACode.csv"); // read header more = readln_ACode(ScriptSize,MainScript); Serial.print(F("Script Size....... = ")); Serial.println(ScriptSize); Serial.print(F("Main Script starts @ ")); Serial.println(MainScript); // read tokenized program while (more) { index++; more=readln_ACode(ScriptAction[index],ScriptDescription[index],ScriptOption[index],ScriptStack[index]); } file_ACode.close(); //initialize the digitl input control pins pinMode(pausePin,INPUT_PULLUP); pinMode(runPin,INPUT_PULLUP); pinMode(gndPin,OUTPUT); digitalWrite(gndPin,LOW); // print free memory Serial.print("Free RAM: "); Serial.println(freeMemory(), DEC); } // ==================== // Main Program // ==================== void loop() { // sss t // s t 77777 // s ttttt eee pppp 7 // sss t e e p p 7 // s t eeeee p p 7 // s t e p p 7 // ssss tt eeee pppp 7 // p // p // variables used in sound/mouth processing int PW; // pulse width int lastPW; // last pulse width byte level; const byte MLim1=12; const byte MLim2=24; String ssc32cmd; String tempFN; char soundfilename[12]; unsigned long SoundEndWait=0; // Player object int Player; int MaxPlayers=0; int LocalIndex; int PlayerStep[32]; unsigned long PlayerEndWait[32]; PlayerEndWait[0]=0ul; // Move commands byte MoveIndex=0; char buffer[64]; // Sync. scripts int SyncPoints[32]; byte SyncPointIndex=0; unsigned int SyncPointStatus=0; // Random play command index byte Selections; // Pause/random pause int minPause; int maxPause; int timePause; int ScriptStep=0; // Loop control boolean NotDone=true; // pause control variables char inputchar=' '; int runPinValue = HIGH; int pausePinValue = HIGH; const int PauseState=HIGH; // define first step MaxPlayers=0; PlayerStep[MaxPlayers] = MainScript; Serial.println(F("Starting...")); // sss t // s t 888 // s ttttt eee pppp 8 8 // sss t e e p p 888 // s t eeeee p p 8 8 // s t e p p 8 8 // ssss tt eeee pppp 888 // p // p while (NotDone){ // Looping through player list (player 0 through Player n) // ------------------------------------------------------- for (Player=0;Player<=MaxPlayers;Player++) { // if the control switch is set to pause, pause the program. pausePinValue = digitalRead(pausePin); runPinValue = digitalRead(runPin); if (runPinValue == PauseState) { delay(40); displayStep(0,0,"Paused"); while (digitalRead(runPin) == PauseState); } // speech processing here if ((SoundEndWait-millis()) <0) { level=analogRead(soundPin); if ((level>= 0) & (level <= MLim1)){ ssc32cmd="#3P600"; PW=600; } else if ((level>MLim1) & (level<=MLim2)) { ssc32cmd="#3P700"; PW=700; } else if ((level>MLim2) & (level<=255)) { ssc32cmd="#3P800"; PW=800; } if (lastPW!=PW) { Serial2.println(ssc32cmd); } lastPW = PW; SoundEndWait=millis()+long(0.012); } // check for proximity of 'visitor' TBD // check for location of visitor TBD // check for visitor comment (hearing) TBD if (((PlayerEndWait[Player] MaxPlayers) MaxPlayers++; PlayerStep[IndexPlayers]=ScriptDescription[ScriptStep]; PlayerEndWait[IndexPlayers]=0; PlayerStep[Player]=ScriptStack[ScriptStep]; PlayerEndWait[Player]=millis()+long(ScriptOption[ScriptStep]/1000); break; } case EndScript: { displayStep(Player,ScriptStep,"End script",ScriptDescription[ScriptStep]); PlayerStep[Player]=ScriptStack[ScriptStep]; if (PlayerStep[Player]==0) { for (int i=Player;i<=MaxPlayers;i++){ PlayerStep[i]=PlayerStep[i+1]; } MaxPlayers--; } ScriptStack[ScriptStep] = 0; NotDone = (ScriptStep != EndMain); break; } case JumpTo: { displayStep(Player,ScriptStep,"Jump to",ScriptDescription[ScriptStep]); PlayerStep[Player] = ScriptDescription[ScriptStep]; break; } case SyncPoint: { displayStep(Player,ScriptStep,"Define sync point",ScriptDescription[ScriptStep]); SyncPointIndex=ScriptDescription[ScriptStep]; SyncPoints[SyncPointIndex] = SyncPoints[SyncPointIndex] | (2^Player); PlayerStep[Player] = ScriptStack[ScriptStep]; break; } case EndSync: { displayStep(Player,ScriptStep,"End sync point",ScriptDescription[ScriptStep]); SyncPointIndex=ScriptDescription[ScriptStep]; SyncPointStatus = SyncPoints[SyncPointIndex] & (! 2^Player); SyncPoints[SyncPointIndex] = SyncPointStatus; if (SyncPoints[SyncPointIndex] == 0) { PlayerStep[Player] = ScriptStack[ScriptStep]; } break; } case OneOnly: { displayStep(Player,ScriptStep,"One Only",ScriptDescription[ScriptStep]); if (ScriptOption[ScriptStep]==0) { LocalIndex=ScriptStep+1; while ((ScriptAction[LocalIndex] != EndSync) && (LocalIndex < ScriptSize)) { LocalIndex+=1; } if (LocalIndex > ScriptSize) { Serial.println(F("Cannot find end of script")); while(true); } else { ScriptOption[ScriptStep] = LocalIndex; } } // check to see if there are any other instances of this script running SyncPointIndex = ScriptDescription[ScriptStep]; SyncPointStatus = SyncPoints[SyncPointIndex] & (~ 2^Player); if (SyncPointStatus==0) { PlayerStep[Player]=ScriptStack[ScriptStep]; // none, go to next step } else { PlayerStep[Player]=ScriptOption[ScriptStep]; // found instance, go to end of script } break; } case RandomMove: { displayStep(Player,ScriptStep,"Random move",ScriptDescription[ScriptStep]); Selections=ScriptDescription[ScriptStep]; MoveIndex=int(random(1,Selections+1)); PlayerStep[Player]=ScriptStep+MoveIndex; break; } case ActionSeq: { displayStep(Player,ScriptStep,"Seq. Action",ScriptDescription[ScriptStep],ScriptOption[ScriptStep]); LocalIndex=ScriptStack[ScriptStep]; PlayerStep[Player]=ScriptStack[ScriptStep]; LocalIndex+=1; if (LocalIndex > ScriptOption[ScriptStep]) LocalIndex=ScriptDescription[ScriptStep]; ScriptStack[ScriptStep] = LocalIndex; break; } case Say: { displayStep(Player,ScriptStep,"Say",ScriptDescription[ScriptStep],ScriptOption[ScriptStep],ScriptStack[ScriptStep]); // identify & construct file name // play through MusicMaker shield if(audioplayer.playingMusic){ audioplayer.stopPlaying(); delay(25); } audioplayer.reset(); delay(25); tempFN=String("track"+String(ScriptDescription[ScriptStep])+".mp3"); tempFN.toCharArray(soundfilename,12); Serial.print(F("Playing ")); Serial.println(tempFN); audioplayer.startPlayingFile(soundfilename); PlayerStep[Player]=ScriptStack[ScriptStep]; break; } case NetWait: { // feature not implemented on this platform displayStep(Player,ScriptStep,"Not implemented",ScriptDescription[ScriptStep]); PlayerStep[Player]=ScriptStack[ScriptStep]; break; } case EndWait: { // feature not implemented on this platform displayStep(Player,ScriptStep,"Not implemented",ScriptDescription[ScriptStep]); PlayerStep[Player]=ScriptStack[ScriptStep]; break; } default: { displayStep(Player,ScriptStep,"Unrecognized",ScriptDescription[ScriptStep]); while(true); //do nothing } } } } } while(true); }