Microcontroller firmware that uses a simple, yet powerful scripting language to control the timing of input and output events with high temporal resolution. Written by Mattias Karlsson
hardwareInterface.cpp
- Committer:
- mkarlsso
- Date:
- 2017-02-07
- Revision:
- 7:5fe7329751d4
- Parent:
- 6:6a6761a47951
- Child:
- 8:872b843a3053
File content as of revision 7:5fe7329751d4:
#include "hardwareInterface.h" //#include <ostream> #include <sstream> using namespace std; //In debug mode, debug messages output to the screen #ifdef DEBUGOUTPUT bool debugOut = true; #else bool debugOut = false; #endif uint32_t timeKeeper; //the main clock (updated every ms) bool resetTimer; bool clockSlave; bool changeToSlave; bool changeToStandAlone; #ifdef MBEDHARDWARE //On the MBED, this needs to be put on a defined bank of memory, or else we run out of memory __attribute((section("AHBSRAM0"),aligned)) outputStream textDisplay(512); #else outputStream textDisplay(256); #endif //--------------------------------------------------------- sSystem::sSystem() { for (int i=0;i<32;i++) { ignorePortUpdates[i] = true; //by default, all digital port changes are not automatically reported. } } //The user can toggle whether a particular port triggers a state update report every time it changes //This is useful for inputs that toggle continuously. void sSystem::setPortUpdatesOff(int portNum) { ignorePortUpdates[portNum] = true; } void sSystem::setPortUpdatesOn(int portNum) { ignorePortUpdates[portNum] = false; } bool* sSystem::getIgnoreUpdates() { return ignorePortUpdates; } void sSystem::immediateClockReset() { //For external clock reset timeKeeper = 0; textDisplay << timeKeeper << " Clock reset\r\n"; } void sSystem::mainLoopToDo() { } void sSystem::pauseInterrupts() { } void sSystem::reset() { } void sSystem::resumeInterrupts() { } int sSystem::getPendingFunctionTriggers(uint16_t *bufferPtr) { return 0; } uint32_t sSystem::getDigitalOutputChangeFlags() { } uint32_t sSystem::getDigitalInputChangeFlags() { } //----------------------------------------------------- sAnalogOut::sAnalogOut() { } //------------------------------------------------------ sAnalogIn::sAnalogIn() { } //------------------------------------------------------ sDigitalOut::sDigitalOut() { } //---------------------------------------------------- sDigitalIn::sDigitalIn() { lastDownEvent.triggered = false; lastUpEvent.triggered = false; bufferedDownEvent.triggered = false; bufferedUpEvent.triggered = false; updating = false; } void sDigitalIn::addStateChange(int newState, uint32_t timeStamp) { //With levers and beam breaks, there will be flutter when triggers happen. //The goal is to capture the initial event time, so we ignore extra triggers //until it has been processed if (!updating) { if ((newState == 0) && (!lastDownEvent.triggered)){ lastDownEvent.timeStamp = timeStamp; lastDownEvent.triggered = true; } else if ((newState == 1) && (!lastUpEvent.triggered)) { lastUpEvent.timeStamp = timeStamp; lastUpEvent.triggered = true; } } else { //If we are currently checking this input, then we buffer the trigger and deal with it after if (newState == 0){ bufferedDownEvent.timeStamp = timeStamp; bufferedDownEvent.triggered = true; } else if (newState == 1) { bufferedUpEvent.timeStamp = timeStamp; bufferedUpEvent.triggered = true; } } /* if ((newState == 0) && (!lastDownEvent.triggered)){ lastDownEvent.timeStamp = timeStamp; lastDownEvent.triggered = true; } else if ((newState == 1) && (!lastUpEvent.triggered)) { lastUpEvent.timeStamp = timeStamp; lastUpEvent.triggered = true; }*/ } void sDigitalIn::setUpdate(bool state) { updating = state; //If true, then we buffer any trigger events until the update check is done. if (!updating) { if (bufferedUpEvent.triggered) { lastUpEvent = bufferedUpEvent; } if (bufferedDownEvent.triggered) { lastDownEvent = bufferedDownEvent; } bufferedDownEvent.triggered = false; bufferedUpEvent.triggered = false; } } //----------------------------------------------------- sSerialPort::sSerialPort() { } //------------------------------------------------------ sSound::sSound(void): fileNameExists(false), volumePtr(NULL), volume(-1), play(true), reset(false) { } void sSound::setFile(string fileNameIn) { for (int i = 0; i < 20; i++) { fileName[i] = NULL; } size_t length = fileNameIn.size(); if (length <= 20) { fileNameIn.copy(fileName, length, 0); fileNameExists = true; } } void sSound::setVolume(int volumeIn) { if ((volumeIn >= 0) && (volumeIn < 256)) { volume = volumeIn; volumePtr = NULL; } } void sSound::setVolume(int* volumeIn) { volume = -1; volumePtr = volumeIn; } void sSound::setPlayback(bool playIn) { play = playIn; } void sSound::setReset() { reset = true; } //----------------------------------------------------- outputStream::outputStream(int bufferSizeIn): readHead(0), writeHead(0), totalWriteHead(0), totalReadHead(0), bufferSize(bufferSizeIn), unsentData(false), serialPtr(NULL) { outputBuffer = new char[bufferSize]; } outputStream::~outputStream() { delete[] outputBuffer; } void outputStream::setSerial(sSerialPort *s) { serialPtr = s; } //used to immediately write to serial port void outputStream::flush() { if (serialPtr != NULL) { while(unsentData) { serialPtr->writeChar(getNextChar()); } } } //adds text to the buffer void outputStream::send(const string &outputString) { int strLen = outputString.size(); int total = 0; int chunk = 0; if (totalWriteHead+strLen > (totalReadHead + bufferSize)) { //We don't have enough space in the buffer, so flush it flush(); } if (!(totalWriteHead+strLen > (totalReadHead + bufferSize))) { while (strLen - total > 0) { chunk = min((bufferSize - writeHead), strLen - total); outputString.copy(outputBuffer + writeHead, chunk, total); writeHead = (writeHead + chunk) % bufferSize; totalWriteHead += chunk; total += chunk; } if (total > 0) { unsentData = true; } } } //adds text to the buffer void outputStream::send(const char *s) { int strLen = strlen(s); int total = 0; //int chunk = 0; if (totalWriteHead+strLen > (totalReadHead + bufferSize)) { //We don't have enough space in the buffer, so flush it flush(); } if (!(totalWriteHead+strLen > (totalReadHead + bufferSize))) { while (strLen - total > 0) { strncpy(outputBuffer + writeHead, s+total,1); total++; writeHead = (writeHead + 1) % bufferSize; totalWriteHead += 1; /* chunk = min((bufferSize - writeHead), strLen - total); strncpy(outputBuffer + writeHead,); outputString.copy(outputBuffer + writeHead, chunk, total); writeHead = (writeHead + chunk) % bufferSize; totalWriteHead += chunk; total += chunk; */ } if (total > 0) { unsentData = true; } } } void outputStream::debug(const char *s) { //send to serial immediately, but only if debugOut is true if (debugOut) { string tmpString = string(s); send(tmpString); flush(); } } //Overloaded << operator to for debugging output. This eliminates the //need for printf statements outputStream& outputStream::operator<<(const string &outputString) { send(outputString); return *this; } outputStream& outputStream::operator<<(const char* s) { //string tmpString = string(s); //send(tmpString); send(s); return *this; } outputStream& outputStream::operator<<(int outputNum) { ostringstream varConvert; varConvert << outputNum; send(varConvert.str()); return *this; } outputStream& outputStream::operator<<(uint32_t outputNum) { ostringstream varConvert; varConvert << outputNum; send(varConvert.str()); return *this; } //the main loop gets one character per loop and write it to the serial port char outputStream::getNextChar() { if (totalReadHead < totalWriteHead) { tmpOut = *(outputBuffer+readHead); readHead = (readHead+1) % bufferSize; totalReadHead++; if (totalReadHead >= totalWriteHead) { unsentData = false; } } return tmpOut; }