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

Dependencies:   SMARTWAV mbed

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;

}