Labrador/Desktop Interface/isobuffer.cpp

305 lines
8.9 KiB
C++

#include "isobuffer.h"
#include "isodriver.h"
isoBuffer::isoBuffer(int bufferLen, isoDriver *caller, unsigned char channel_value)
{
buffer = (short *) calloc(bufferLen*2, sizeof(short));
bufferEnd = bufferLen-1;
samplesPerSecond = (double) bufferLen/(double)21;
samplesPerSecond = samplesPerSecond/375*374; //BABABOOEY
parent = caller;
channel = channel_value;
}
void isoBuffer::openFile(QString newFile)
{
if (fptr != NULL){
fclose(fptr);
}
if (newFile.isEmpty()){
fptr = NULL;
}
else {
QByteArray temp = newFile.toLatin1();
char *fileName = temp.data();
fptr = fopen(fileName, "w");
if (fptr == NULL) qFatal("Null fptr in isoBuffer::openFile");
qDebug() << "opening file" << fileName;
qDebug() << "fptr = " << fptr;
}
}
void isoBuffer::writeBuffer_char(char* data, int len)
{
double convertedSample;
for (int i=0; i<len;i++){
//qDebug() << "i = " << i;
buffer[back] = (short) data[i];
if (back == bufferEnd){
back = 0;
firstTime = false;
}
else back++;
//Output to CSV
if(fileIOEnabled){
convertedSample = sampleConvert(data[i], 128, channel==1 ? parent->AC_CH1 : parent->AC_CH2);
char numStr[32];
sprintf(numStr,"%f, ", convertedSample);
currentFile->write(numStr);
currentColumn++;
if (currentColumn > COLUMN_BREAK){
currentFile->write("\n");
currentColumn = 0;
}
}
}
return;
}
void isoBuffer::writeBuffer_short(short* data, int len)
{
//for (int i=(len-1);i>-1;i--){
for (int i=0; i<len;i++){
//qDebug() << "i = " << i;
buffer[back] = (short) data[i] >> 4; //Because it's a left adjust value!
if (back == bufferEnd){
back = 0;
firstTime = false;
}
else back++;
}
return;
}
short *isoBuffer::readBuffer(double sampleWindow, int numSamples, bool singleBit, double delayOffset)
{
//ignore singleBit for now
double timeBetweenSamples = (double) sampleWindow * (double) samplesPerSecond / (double) numSamples;
double accumulatedDelay = 0;
int delaySamples = (int)((double)delayOffset * (double)samplesPerSecond);
int front = back - 1 - delaySamples;
if (front < 0) front = 0;
int idx, subIdx;
if(readData!=NULL) free(readData);
readData = (short *) calloc(numSamples, sizeof(short));
if(singleBit){
for (int i=0; i<numSamples;i++){
if (timeBetweenSamples > (double) front){
accumulatedDelay -= (double) front;
front = bufferEnd;
}
idx = (int) floor(((double) front - accumulatedDelay));
subIdx = (int) floor(8*(((double) front - accumulatedDelay) - floor(((double) front - accumulatedDelay))));
if (idx < 0){
accumulatedDelay--;
accumulatedDelay -= (double) front;
front = bufferEnd;
idx = (int) round(((double) front - accumulatedDelay));
}
readData[i] = buffer[idx] & (1<<subIdx);
accumulatedDelay += timeBetweenSamples;
}
}else{
for (int i=0; i<numSamples;i++){
if (timeBetweenSamples > (double) front){
accumulatedDelay -= (double) front;
front = bufferEnd;
}
idx = (int) round(((double) front - accumulatedDelay));
if (idx < 0){
accumulatedDelay--;
accumulatedDelay -= (double) front;
front = bufferEnd;
idx = (int) round(((double) front - accumulatedDelay));
}
readData[i] = buffer[idx];
accumulatedDelay += timeBetweenSamples;
}
}
return readData;
}
void isoBuffer::clearBuffer()
{
for (int i=0; i<bufferEnd;i++){
buffer[i] = 0;
}
back = 0;
serialPtr = 0;
serialDecodingSymbol = false;
symbolCurrent = 0;
symbol = 0;
firstTime = true;
}
void isoBuffer::gainBuffer(int gain_log)
{
qDebug() << "Buffer shifted by" << gain_log;
for (int i=0; i<bufferEnd; i++){
if (gain_log == -1) buffer[i] *= 2;
else buffer[i] /= 2;
}
}
void isoBuffer::glitchInsert(short type)
{
}
void isoBuffer::serialDecode(double baudRate)
{
double dist_seconds = (double)serialDistance()/samplesPerSecond;
double bitPeriod_seconds = 1/baudRate;
unsigned short* tempPtr;
unsigned short tempShort;
unsigned char tempChar;
if(channel == 1) console = console1;
else if(channel == 2) console = console2;
else qFatal("Nonexistant console requested in isoBuffer::serialDecode");
while(dist_seconds > (bitPeriod_seconds + SERIAL_DELAY)){
tempPtr = (unsigned short *) readBuffer(0, 1, false, dist_seconds - bitPeriod_seconds);
tempShort = *(tempPtr);
tempShort = tempShort & 0xff;
tempChar = tempShort & (1 << serialPhase) ? 0 : 1;
if(serialDecodingSymbol){
//if((tempShort != 0) && (tempShort!= 255)) qDebug() << "tempShort = " << tempShort;
qDebug() << numOnes(tempShort);
decodeSymbol(numOnes(tempShort) > 4);
}
else serialDecodingSymbol = (numOnes(tempShort) < 8);
marchSerialPtr(bitPeriod_seconds * samplesPerSecond);
dist_seconds = (double)serialDistance()/samplesPerSecond;
}
}
int isoBuffer::serialDistance()
{
if(back >= serialPtr){
return back - serialPtr;
}else return bufferEnd - serialPtr + back;
}
void isoBuffer::serialBegin()
{
serialPtr = back;
}
void isoBuffer::decodeSymbol(unsigned char newBit) //Slow but works.
{
if(symbolCurrent == symbolMax){ //Last bit in symbol
console -> insertPlainText(QString(QChar((char)symbol)));
if(serialAutoScroll){
//http://stackoverflow.com/questions/21059678/how-can-i-set-auto-scroll-for-a-qtgui-qtextedit-in-pyqt4 DANKON
QTextCursor c = console->textCursor();
c.movePosition(QTextCursor::End);
console->setTextCursor(c);
// txtedit.ensureCursorVisible(); // you might need this also
}
symbolCurrent++;
return;
}
if(symbolCurrent > symbolMax){ //Wait for stop bit. Stops over the top calculation when you get a string of zeroes...
if(newBit == 1){
serialDecodingSymbol = false;
symbolCurrent = 0;
symbol = 0;
}
return;
}
//otherwise
symbol |= newBit << symbolCurrent;
symbolCurrent++;
}
void isoBuffer::marchSerialPtr(int bitPeriod_samples)
{
int halfPeriod = bitPeriod_samples * 0.6;
int sampleDistance = -1;
serialPtr += bitPeriod_samples;
if(serialPtr >= bufferEnd){
serialPtr -= bufferEnd;
}
if(!serialDecodingSymbol){
return;
}
if((serialPtr <= halfPeriod) || (serialPtr > (bufferEnd - halfPeriod))) return; //Don't bother readjusting. Too hard.
//otherwise...
if(buffer[serialPtr] != buffer[serialPtr - halfPeriod]){ //use LHS to calibrate
for (int i=halfPeriod;i>=0;i--){
if(buffer[serialPtr] == buffer[serialPtr-i]){
sampleDistance = i;
break;
}
}
if(sampleDistance != -1) serialPtr += (bitPeriod_samples/2) - sampleDistance;
}
if(sampleDistance == -1){
if(buffer[serialPtr] != buffer[serialPtr + halfPeriod]){ //same as above but with RHS
for (int i=halfPeriod;i>=0;i--){
if(buffer[serialPtr] == buffer[serialPtr+i]){
sampleDistance = i;
break;
}
}
if(sampleDistance != -1) serialPtr -= (bitPeriod_samples/2) - sampleDistance;
}
}
}
unsigned char isoBuffer::numOnes(unsigned short var){
return ((var&0x01) ? 1 : 0) + ((var&0x02) ? 1 : 0) + ((var&0x04) ? 1 : 0) + ((var&0x08) ? 1 : 0) + ((var&0x10) ? 1 : 0) + ((var&0x20) ? 1 : 0) + ((var&0x40) ? 1 : 0) + ((var&0x80) ? 1 : 0);
}
void isoBuffer::enableFileIO(QFile *file){
file->open(QIODevice::WriteOnly);
currentFile = file;
fileIOEnabled = true;
return;
}
void isoBuffer::disableFileIO(){
fileIOEnabled = false;
currentColumn = 0;
currentFile->close();
return;
}
double isoBuffer::sampleConvert(short sample, int TOP, bool AC){
double scope_gain = (double)(parent->driver->scopeGain);
double voltageLevel;
voltageLevel = (sample * (vcc/2)) / (R4/(R3+R4)*scope_gain*TOP);
if (parent->driver->deviceMode != 7) voltageLevel += vcc*(R2/(R1+R2));
#ifdef INVERT_MM
if(parent->driver->deviceMode == 7) voltageLevel *= -1;
#endif
if(AC){
voltageLevel -= parent->currentVmean; //This is old (1 frame in past) value and might not be good for signals with large variations in DC level (although the cap should filter that anyway)??
}
return voltageLevel;
}