/* * program.cpp - OpenPCR control software. * Copyright (C) 2010-2011 Josh Perfetto. All Rights Reserved. * * OpenPCR control software is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenPCR control software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * the OpenPCR control software. If not, see . */ #include "pcr_includes.h" #include "program.h" #include #include "display.h" //////////////////////////////////////////////////////////////////// // Class Step void Step::SetName(const char* szName) { strncpy(iName, szName, sizeof(iName)); iName[sizeof(iName) - 1] = '\0'; } void Step::Reset() { iStepReturned = false; iDuration = 0; iTemp = 0; iName[0] = '\0'; } void Step::BeginIteration() { iStepReturned = false; } Step* Step::GetNextStep() { if (iStepReturned) { return NULL; } else { iStepReturned = true; return this; } } //////////////////////////////////////////////////////////////////// // Class Cycle ProgramComponent* Cycle::GetComponent(int index) { return iComponents[index]; } PcrStatus Cycle::AddComponent(ProgramComponent* pComponent) { if (iNumComponents >= MAX_CYCLE_ITEMS) return ETooManySteps; iComponents[iNumComponents++] = pComponent; return ESuccess; } void Cycle::Reset() { iNumComponents = 0; iNumCycles = 0; iCurrentCycle = 0; iCurrentComponent = 0; } // iteration void Cycle::BeginIteration() { iCurrentCycle = 0; RestartCycle(); } Step* Cycle::GetNextStep() { //check for next step of existing component Step* pNextStep = iComponents[iCurrentComponent]->GetNextStep(); //advance to next component if current component done if (pNextStep == NULL && ++iCurrentComponent < iNumComponents) pNextStep = iComponents[iCurrentComponent]->GetNextStep(); //should never be NULL //advance to next cycle if current cycle done if (pNextStep == NULL && ++iCurrentCycle < iNumCycles) { RestartCycle(); //return first component of that cycle pNextStep = iComponents[iCurrentComponent]->GetNextStep(); //should never be NULL } return pNextStep; } void Cycle::RestartCycle() { iCurrentComponent = 0; for (int i = 0; i < iNumComponents; i++) iComponents[i]->BeginIteration(); } //////////////////////////////////////////////////////////////////// // Class CommandParser void CommandParser::ParseCommand(SCommand& command, char* pCommandBuf) { char* pValue; memset(&command, NULL, sizeof(command)); char buf[32]; gpThermocycler->Stop(); //need to stop here to reset program pools char* pParam = strtok(pCommandBuf, "&"); while (pParam) { pValue = strchr(pParam, '='); *pValue++ = '\0'; AddComponent(&command, pParam[0], pValue); pParam = strtok(NULL, "&"); } } void CommandParser::AddComponent(SCommand* pCommand, char key, char* szValue) { switch(key) { case 'n': strncpy(pCommand->name, szValue, sizeof(pCommand->name) - 1); pCommand->name[sizeof(pCommand->name) - 1] = '\0'; break; case 'c': if (strcmp(szValue, "start") == 0) pCommand->command = SCommand::EStart; else if (strcmp(szValue, "stop") == 0) pCommand->command = SCommand::EStop; else if (strcmp(szValue, "cfg") == 0) pCommand->command = SCommand::EConfig; break; case 'l': pCommand->lidTemp = atoi(szValue); break; case 'o': pCommand->contrast = atoi(szValue); case 'd': pCommand->commandId = atoi(szValue); break; case 'p': pCommand->pProgram = ParseProgram(szValue); break; } } Cycle* CommandParser::ParseProgram(char* pBuffer) { Cycle* pProgram = gpThermocycler->GetCyclePool().AllocateComponent(); pProgram->SetNumCycles(1); char* pCycBuf = strtok(pBuffer, "()"); while (pCycBuf != NULL) { pProgram->AddComponent(ParseCycle(pCycBuf)); pCycBuf = strtok(NULL, "()"); } return pProgram; } ProgramComponent* CommandParser::ParseCycle(char* pBuffer) { char countBuf[5]; //find first step char* pStep = strchr(pBuffer, '['); //get cycle count int countLen = pStep - pBuffer; strncpy(countBuf, pBuffer, countLen); countBuf[countLen] = '\0'; int cycCount = atoi(countBuf); Cycle* pCycle = gpThermocycler->GetCyclePool().AllocateComponent(); pCycle->SetNumCycles(cycCount); //add steps while (pStep != NULL) { *pStep++ = '\0'; char* pStepEnd = strchr(pStep, ']'); *pStepEnd++ = '\0'; Step* pNewStep = ParseStep(pStep); pCycle->AddComponent(pNewStep); pStep = strchr(pStepEnd, '['); } return pCycle; } Step* CommandParser::ParseStep(char* pBuffer) { char* pTemp = strchr(pBuffer, '|'); *pTemp++ = '\0'; char* pName = strchr(pTemp, '|'); *pName++ = '\0'; char* pEnd = strchr(pName, ']'); *pEnd = '\0'; int duration = atoi(pBuffer); float temp = atof(pTemp); Step* pStep = gpThermocycler->GetStepPool().AllocateComponent(); pStep->SetName(pName); pStep->SetDuration(duration); pStep->SetTemp(temp); return pStep; } //////////////////////////////////////////////////////////////////// // Class ProgramStore // // Note: Byte 0 of EEPROM is used for contrast // Bytes 1 and onwards are used for stored program string // uint8_t ProgramStore::RetrieveContrast() { return EEPROM.read(0); } #define PROG_START_STR "&c=start" const char PROG_START_STR_P[] PROGMEM = PROG_START_STR; boolean ProgramStore::RetrieveProgram(SCommand& command, char* pBuffer) { for (int i = 0; i < MAX_COMMAND_SIZE; i++) pBuffer[i] = EEPROM.read(i + 1); if (strncmp_P(pBuffer, PROG_START_STR_P, strlen(PROG_START_STR)) == 0) { //previous program stored CommandParser::ParseCommand(command, pBuffer); return true; } else { return false; } } void ProgramStore::StoreContrast(uint8_t contrast) { EEPROM.write(0, contrast); } void ProgramStore::StoreProgram(const char* szProgram) { for (int i = 0; i < MAX_COMMAND_SIZE; i++) EEPROM.write(i + 1, szProgram[i]); }