// Initialize the application and telephony API. Blocks. State * TeleKarma::Initialize(Action * a, State * s) { if (s->id != STATE_UNINITIALIZED) return s; bool flag = false; InitializeAction * ia = dynamic_cast<InitializeAction *>(a); State * result = NULL; if (ia == NULL) { result = SetState(new State(STATE_INITIALIZING, s->turn+1)); result = SetState(new State(result->id, result->turn, STATUS_FAILED, "Programming error: action cast failed")); result = SetState(new State(STATE_UNINITIALIZED, result->turn+1)); } else { // set stun server **before** entering INITIALIZING state model->SetStunServer(ia->stunServer); result = SetState(new State(STATE_INITIALIZING, s->turn+1)); // verify existence and type of 'logs' folder const char * strPath1 = "logs"; struct stat status; stat(strPath1, &status); bool existsLogs = !((ACCESS(strPath1, 0) == -1) || !(status.st_mode & S_IFDIR)); // verify existence and type of 'recordings' folder const char * strPath2 = "recordings"; stat(strPath2, &status); bool existsRecordings = !((ACCESS(strPath2, 0) == -1) || !(status.st_mode & S_IFDIR)); if (!(existsLogs || existsRecordings)){ result = SetState(new State(result->id, result->turn, STATUS_FAILED, "Please create \"logs\" and \"recordings\" folders in your TeleKarma program folder.")); flag = true; } else if (!existsLogs) { result = SetState(new State(result->id, result->turn, STATUS_FAILED, "Please create a \"logs\" folder in your TeleKarma program folder.")); flag = true; } else if (!existsRecordings) { result = SetState(new State(result->id, result->turn, STATUS_FAILED, "Please create a \"recordings\" folder in your TeleKarma program folder.")); flag = true; } if (flag) { result = SetState(new State(STATE_UNINITIALIZED, result->turn+1)); } else { // create log file PTime now; PString logFName("logs/log"); logFName += now.AsString("_yyyy.MM.dd_hh.mm.ss"); logFName += ".txt"; PTrace::Initialise(3, logFName); // initialize telephony (blocking call) phone->Initialise(ia->stunServer); PSTUNClient * stunClient = phone->GetSTUNClient(); if (stunClient != NULL) { model->SetStunType(stunClient->GetNatTypeName()); } else { model->SetStunType("none"); } result = SetState(new State(STATE_INITIALIZED, result->turn+1)); } } return result; }
State * TeleKarma::StartRecording(State * currentState) { State * result = NULL; PString assuranceName = "assurance.wav"; phone->PlayWAVCall(assuranceName, 0, 0); /* XXX Do we care about what the return value. */ result = SetState(new State(currentState->id, currentState->turn, STATUS_NOTIFY_RECORD)); while(phone->IsPlayingWav()); PTime now; PString recFName("recordings/rec"); recFName += now.AsString("_yyyy.MM.dd_hh.mm.ss"); recFName += ".wav"; phone->StartRecording(recFName); return result; }
void ControllerThread::Main() { PTime tBase; // base time for tStep multiplier PTimeInterval tStep(1); // 1ms, loop step (1Hz); up to 14 bytes per step for 115200 serial line PTime tNow; // current time PTime tThen; // expected execution time unsigned short i = 0; // multiplier for tStep // initialize PTRACE(1, "Arduino initialization"); char buffer[256]; PINDEX iRead = 0; PINDEX len = 0; // reset serial port pserial->ClearDTR(); pserial->ClearRTS(); pserial->ClearBreak(); pserial->SetDTR(); pserial->SetRTS(); // drop junk from serial port do { if (shutdown.Wait(0)) { return; }; pserial->Read(buffer, 256); // flush serial data } while (pserial->GetLastReadCount()); memset(buffer, 0, 256); // waiting for 3 heat beat do { if (shutdown.Wait(0)) { return; }; pserial->Read(buffer, 256); iRead = pserial->GetLastReadCount(); if (iRead == 2 && buffer[0] == 0 && buffer[1] == 0) { len += iRead; PTRACE(1, "HeatBeat from Arduino #" << len/2); }; } while(len < 6); PTRACE(1, "Arduino initialization done"); fReady = PTrue; // reset Arduino pushAction(0xFF, CMD_RESET); pushAction(0xFF, CMD_SETBASE0); // X1 pushAction(0xFF, calibrationTable[0]->GetAt(10000)); pushAction(0xFF, CMD_SETBASE1); // Y1 pushAction(0xFF, calibrationTable[1]->GetAt(10000)); pushAction(0xFF, CMD_SETBASE2); // X2 pushAction(0xFF, calibrationTable[2]->GetAt(10000)); pushAction(0xFF, CMD_SETBASE3); // Y2 pushAction(0xFF, calibrationTable[3]->GetAt(10000)); pushAction(0xFF, CMD_SETBASE4); // LT pushAction(0xFF, calibrationTable[4]->GetAt(10000)); pushAction(0xFF, CMD_SETBASE5); // RT pushAction(0xFF, calibrationTable[5]->GetAt(10000)); pushAction(0xFF, CMD_RESET); // main loop do { bool fNewActions = false; BYTE naction; PInt32l value; /* * get x, y, button and other events */ PTRACE(6, "Main\t" << dumpAction("actions before population: ")); while(popAction(&naction, &value)) { PIntArray *actionQueue = actionQueuePool[naction]; fNewActions = true; PTRACE(6, "Main\tadd new value to actionQueuePool[" << (int)naction << "] with queue size " << actionQueue->GetSize()); actionQueue->SetAt(actionQueue->GetSize(), value); }; if (fNewActions) { PTRACE(6, "Main\t" << dumpAction("actions after population: ")); summarizeActions(); // summarize action events by type PTRACE(6, "Main\t" << dumpAction("actions after summarization: ")); }; /* * process actions: * send current state to arduino * then receive state from arduino * and update actions after sucsessful transmit */ processActions(); /* * wait next tStep ms */ i++; tThen = tBase + tStep * i; tNow = PTime(); // reset multiplier if (i >= 255) { i = 0; tBase = tThen; }; // step was too long (tThen less than tNow) if (tNow.Compare(tThen) != LessThan) { PTRACE(6, "Main\tnow: " << tNow.AsString("h:m:s.uuuu") << " then: " << tThen.AsString("h:m:s.uuuu") << " i: " << (int)i << " diff: " << (tNow - tThen).GetMilliSeconds() << "ms"); i += (tNow - tThen).GetMilliSeconds() / tStep.GetMilliSeconds() + 1; // number of steps + 1 step tThen = tBase + tStep * i; PTRACE(6, "Main\tcorrected then: " << tThen.AsString("h:m:s.uuuu") << " i: " << (int)i); }; PTRACE(7, "Main\tstep " << (tThen - tNow).GetMilliSeconds() << "ms"); } while(!shutdown.Wait((tThen - tNow).GetMilliSeconds())); }