Functiongencontrol refactor - part 2 (#69)

* use an enum instead of int to identify function generator channels

* Use local 8 bit encoding instead of utf8 for file paths

* use static_cast instead of function-style casts

* remove length member from channelData struct. use reference captures on some lambdas
This commit is contained in:
Sebastián Mestre 2019-03-07 05:58:52 -03:00 committed by Chris Esposito
parent a144105b23
commit c149063452
5 changed files with 89 additions and 75 deletions

View File

@ -9,53 +9,60 @@ functionGenControl::functionGenControl(QWidget *parent) : QLabel(parent)
void functionGenControl::waveformName_CH1(QString newName) void functionGenControl::waveformName_CH1(QString newName)
{ {
waveformName(newName, 0); waveformName(ChannelID::CH1, newName);
} }
void functionGenControl::freqUpdate_CH1(double newFreq) void functionGenControl::freqUpdate_CH1(double newFreq)
{ {
freqUpdate(newFreq, 0); freqUpdate(ChannelID::CH1, newFreq);
} }
void functionGenControl::amplitudeUpdate_CH1(double newAmplitude) void functionGenControl::amplitudeUpdate_CH1(double newAmplitude)
{ {
amplitudeUpdate(newAmplitude, 0); amplitudeUpdate(ChannelID::CH1, newAmplitude);
} }
void functionGenControl::offsetUpdate_CH1(double newOffset) void functionGenControl::offsetUpdate_CH1(double newOffset)
{ {
offsetUpdate(newOffset, 0); offsetUpdate(ChannelID::CH1, newOffset);
} }
void functionGenControl::waveformName_CH2(QString newName) void functionGenControl::waveformName_CH2(QString newName)
{ {
waveformName(newName, 1); waveformName(ChannelID::CH2, newName);
} }
void functionGenControl::freqUpdate_CH2(double newFreq) void functionGenControl::freqUpdate_CH2(double newFreq)
{ {
freqUpdate(newFreq, 1); freqUpdate(ChannelID::CH2, newFreq);
} }
void functionGenControl::amplitudeUpdate_CH2(double newAmplitude) void functionGenControl::amplitudeUpdate_CH2(double newAmplitude)
{ {
amplitudeUpdate(newAmplitude, 1); amplitudeUpdate(ChannelID::CH2, newAmplitude);
} }
void functionGenControl::offsetUpdate_CH2(double newOffset) void functionGenControl::offsetUpdate_CH2(double newOffset)
{ {
offsetUpdate(newOffset, 1); offsetUpdate(ChannelID::CH2, newOffset);
} }
void functionGenControl::waveformName(QString newName, int channelID) functionGenControl::ChannelData& functionGenControl::getChannelData(ChannelID channelID)
{ {
ChannelData& channel = channels[channelID]; return channels[static_cast<int>(channelID)];
}
void functionGenControl::waveformName(ChannelID channelID, QString newName)
{
ChannelData& channel = getChannelData(channelID);
qDebug() << "newName = " << newName; qDebug() << "newName = " << newName;
newName.append(".tlw"); newName.append(".tlw");
int length;
#ifdef PLATFORM_ANDROID #ifdef PLATFORM_ANDROID
QString waveformFilePath("assets:/waveforms/"); QString waveformFilePath("assets:/waveforms/");
waveformFilePath.append(newName); waveformFilePath.append(newName);
@ -69,7 +76,7 @@ void functionGenControl::waveformName(QString newName, int channelID)
line = fptr.readLine(); line = fptr.readLine();
strcpy(lengthString, line.data()); strcpy(lengthString, line.data());
sscanf(lengthString, "%d", &channel.length); sscanf(lengthString, "%d", &length);
qDebug() << "lengthString" << lengthString; qDebug() << "lengthString" << lengthString;
line = fptr.readLine(); line = fptr.readLine();
@ -77,27 +84,27 @@ void functionGenControl::waveformName(QString newName, int channelID)
sscanf(divisibilityString, "%d", &channel.divisibility); sscanf(divisibilityString, "%d", &channel.divisibility);
qDebug() << "divisibilityString" << divisibilityString; qDebug() << "divisibilityString" << divisibilityString;
qDebug() << "Length = " << channel.length; qDebug() << "Length = " << length;
qDebug() << "Divisibility = " << channel.divisibility; qDebug() << "Divisibility = " << channel.divisibility;
QByteArray remainingData = fptr.readAll(); QByteArray remainingData = fptr.readAll();
char *dataString = remainingData.data(); char *dataString = remainingData.data();
channel.samples.resize(channel.length); channel.samples.resize(length);
int dummy; int dummy;
char *dataStringCurrent = dataString; char *dataStringCurrent = dataString;
for (int i = 0; i < channel.length; i++) for (int i = 0; i < length; i++)
{ {
sscanf(dataStringCurrent, "%d", &dummy); sscanf(dataStringCurrent, "%d", &dummy);
dataStringCurrent += strcspn(dataStringCurrent, "\t") + 1; dataStringCurrent += strcspn(dataStringCurrent, "\t") + 1;
channel.samples[i] = uint8_t(dummy); channel.samples[i] = static_cast<uint8_t>(dummy);
} }
#else #else
QByteArray filePath = QCoreApplication::applicationDirPath() QByteArray filePath = QCoreApplication::applicationDirPath()
.append("/waveforms/").append(newName).toUtf8(); .append("/waveforms/").append(newName).toLocal8Bit();
qDebug() << "opening" << filePath; qDebug() << "opening" << filePath;
@ -107,7 +114,7 @@ void functionGenControl::waveformName(QString newName, int channelID)
char lengthString[16]; char lengthString[16];
fgets(lengthString, 5, fptr); fgets(lengthString, 5, fptr);
sscanf(lengthString, "%d", &channel.length); sscanf(lengthString, "%d", &length);
char divisibilityString[16]; char divisibilityString[16];
//Bit of bullshit to deal with CRLF line endings on Mac. //Bit of bullshit to deal with CRLF line endings on Mac.
@ -119,67 +126,68 @@ void functionGenControl::waveformName(QString newName, int channelID)
sscanf(divisibilityString, "%d", &channel.divisibility); sscanf(divisibilityString, "%d", &channel.divisibility);
qDebug() << "Length = " << channel.length; qDebug() << "Length = " << length;
qDebug() << "Divisibility = " << channel.divisibility; qDebug() << "Divisibility = " << channel.divisibility;
channel.samples.resize(channel.length); channel.samples.resize(length);
char *dataString = (char *) malloc(channel.length*5+1); char *dataString = (char *) malloc(length*5+1);
fgets(dataString, channel.length*5+1, fptr); fgets(dataString, length*5+1, fptr);
int dummy; int dummy;
char *dataStringCurrent = dataString; char *dataStringCurrent = dataString;
for (int i = 0; i < channel.length; i++) for (int i = 0; i < length; i++)
{ {
sscanf(dataStringCurrent, "%d", &dummy); sscanf(dataStringCurrent, "%d", &dummy);
dataStringCurrent += strcspn(dataStringCurrent, "\t") + 1; dataStringCurrent += strcspn(dataStringCurrent, "\t") + 1;
channel.samples[i] = uint8_t(dummy); channel.samples[i] = static_cast<uint8_t>(dummy);
} }
free(dataString); free(dataString);
fclose(fptr); fclose(fptr);
#endif #endif
double newMaxFreq = DAC_SPS / (channel.length >> (channel.divisibility - 1)); double newMaxFreq = DAC_SPS / (length >> (channel.divisibility - 1));
double newMinFreq = double(CLOCK_FREQ) / 1024.0 / 65535.0 / channel.length; double newMinFreq = double(CLOCK_FREQ) / 1024.0 / 65535.0 / length;
// NOTE: Not very clean... Not sure what to do about it. // NOTE: Not very clean... Not sure what to do about it.
// I guess the "right thing" would be to have a Channel QObject class with its // I guess the "right thing" would be to have a Channel QObject class with its
// own signals and slots, or have a single setMaxFreq signal with channelID as // own signals and slots, or have a single setMaxFreq signal with channelID as
// an argument. Either solution would require changes in other places in the // an argument. Either solution would require changes in other places in the
// codebase so this will have to do for now. // codebase so this will have to do for now.
if (channelID == 0) switch (channelID)
{ {
case ChannelID::CH1:
setMaxFreq_CH1(newMaxFreq); setMaxFreq_CH1(newMaxFreq);
setMinFreq_CH1(newMinFreq); setMinFreq_CH1(newMinFreq);
} break;
else case ChannelID::CH2:
{
setMaxFreq_CH2(newMaxFreq); setMaxFreq_CH2(newMaxFreq);
setMinFreq_CH2(newMinFreq); setMinFreq_CH2(newMinFreq);
break;
} }
functionGenToUpdate(channelID, this); functionGenToUpdate(channelID, this);
} }
void functionGenControl::freqUpdate(double newFreq, int channelID) void functionGenControl::freqUpdate(ChannelID channelID, double newFreq)
{ {
qDebug() << "newFreq" << channelID << " = " << newFreq; qDebug() << "newFreq" << int(channelID) << " = " << newFreq;
channels[channelID].freq = newFreq; getChannelData(channelID).freq = newFreq;
functionGenToUpdate(channelID, this); functionGenToUpdate(channelID, this);
} }
void functionGenControl::amplitudeUpdate(double newAmplitude, int channelID) void functionGenControl::amplitudeUpdate(ChannelID channelID, double newAmplitude)
{ {
qDebug() << "newAmplitude" << channelID << " = " << newAmplitude; qDebug() << "newAmplitude" << int(channelID) << " = " << newAmplitude;
channels[channelID].amplitude = newAmplitude; getChannelData(channelID).amplitude = newAmplitude;
functionGenToUpdate(channelID, this); functionGenToUpdate(channelID, this);
} }
void functionGenControl::offsetUpdate(double newOffset, int channelID) void functionGenControl::offsetUpdate(ChannelID channelID, double newOffset)
{ {
qDebug() << "newOffset" << channelID << " = " << newOffset; qDebug() << "newOffset" << int(channelID) << " = " << newOffset;
channels[channelID].offset = newOffset; getChannelData(channelID).offset = newOffset;
functionGenToUpdate(channelID, this); functionGenToUpdate(channelID, this);
} }

View File

@ -17,37 +17,42 @@ class functionGenControl : public QLabel
{ {
Q_OBJECT Q_OBJECT
public: public:
struct ChannelData struct ChannelData
{ {
std::vector<uint8_t> samples; std::vector<uint8_t> samples;
// TODO: get rid of length member. samples:std::vector already has this information
int length;
int divisibility; int divisibility;
double freq = 1000.0; double freq = 1000.0;
double amplitude = 0.0; double amplitude = 0.0;
double offset = 0.0; double offset = 0.0;
}; };
enum class ChannelID
{
CH1 = 0,
CH2 = 1
};
explicit functionGenControl(QWidget *parent = 0); explicit functionGenControl(QWidget *parent = 0);
ChannelData channels[2]; ChannelData channels[2];
private: public:
// NOTE: An enum instead of a plain int would probably be better here ChannelData& getChannelData(ChannelID channelID);
void waveformName(QString newName, int channelID);
void freqUpdate(double newFreq, int channelID);
void amplitudeUpdate(double newAmplitude, int channelID);
void offsetUpdate(double newOffset, int channelID);
signals: signals:
void functionGenToUpdate(int channel, functionGenControl *fGenControl); void functionGenToUpdate(ChannelID channel, functionGenControl *fGenControl);
void setMaxFreq_CH1(double maxFreq); void setMaxFreq_CH1(double maxFreq);
void setMinFreq_CH1(double minFreq); void setMinFreq_CH1(double minFreq);
void setMaxFreq_CH2(double maxFreq); void setMaxFreq_CH2(double maxFreq);
void setMinFreq_CH2(double minFreq); void setMinFreq_CH2(double minFreq);
public slots: public slots:
void waveformName(ChannelID channelId, QString newName);
void freqUpdate(ChannelID channelId, double newFreq);
void amplitudeUpdate(ChannelID channelId, double newAmplitude);
void offsetUpdate(ChannelID channelId, double newOffset);
void waveformName_CH1(QString newName); void waveformName_CH1(QString newName);
void freqUpdate_CH1(double newFreq); void freqUpdate_CH1(double newFreq);
void amplitudeUpdate_CH1(double newAmplitude); void amplitudeUpdate_CH1(double newAmplitude);

View File

@ -75,8 +75,9 @@ void genericUsbDriver::setPsu(double voltage){
qDebug() << "Going to send value " << dutyPsu; qDebug() << "Going to send value " << dutyPsu;
} }
void genericUsbDriver::setFunctionGen(int channelID, functionGenControl *fGenControl) void genericUsbDriver::setFunctionGen(functionGenControl::ChannelID channelID, functionGenControl *fGenControl)
{ {
using ChannelID = functionGenControl::ChannelID;
//////////////////////////// ////////////////////////////
////NO RESIZING (YET)!!!//// ////NO RESIZING (YET)!!!////
//////////////////////////// ////////////////////////////
@ -86,24 +87,24 @@ void genericUsbDriver::setFunctionGen(int channelID, functionGenControl *fGenCon
////////////////////////////////////// //////////////////////////////////////
//For recalling on crash. //For recalling on crash.
if (channelID == 0) if (channelID == ChannelID::CH1)
fGenPtr_CH1 = fGenControl; fGenPtr_CH1 = fGenControl;
else else
fGenPtr_CH2 = fGenControl; fGenPtr_CH2 = fGenControl;
//Reading in data //Reading in data
functionGenControl::ChannelData channelData = fGenControl->channels[channelID]; functionGenControl::ChannelData channelData = fGenControl->getChannelData(channelID);
//Triple mode //Triple mode
if ((channelData.amplitude + channelData.offset) > FGEN_LIMIT) if ((channelData.amplitude + channelData.offset) > FGEN_LIMIT)
{ {
channelData.amplitude /= 3.0; channelData.amplitude /= 3.0;
channelData.offset /= 3.0; channelData.offset /= 3.0;
fGenTriple |= uint8_t(!channelID + 1); fGenTriple |= static_cast<uint8_t>(!static_cast<uint8_t>(channelID) + 1);
} }
else else
{ {
fGenTriple &= uint8_t(254 - !channelID); fGenTriple &= static_cast<uint8_t>(254 - !static_cast<uint8_t>(channelID));
} }
//Waveform scaling in V //Waveform scaling in V
@ -127,7 +128,7 @@ void genericUsbDriver::setFunctionGen(int channelID, functionGenControl *fGenCon
usbSendControl(0x40, 0xa4, fGenTriple, 0, 0, NULL); usbSendControl(0x40, 0xa4, fGenTriple, 0, 0, NULL);
#endif #endif
auto applyAmplitudeAndOffset = [=](unsigned char sample) -> unsigned char auto applyAmplitudeAndOffset = [&](unsigned char sample) -> unsigned char
{ {
return sample / 255.0 * channelData.amplitude + channelData.offset; return sample / 255.0 * channelData.amplitude + channelData.offset;
}; };
@ -139,19 +140,20 @@ void genericUsbDriver::setFunctionGen(int channelID, functionGenControl *fGenCon
//Need to increase size of wave if its freq too high, or too low! //Need to increase size of wave if its freq too high, or too low!
{ {
int shift = 0; int shift = 0;
int newLength = channelData.samples.size();
while ((channelData.length >> shift) * channelData.freq > DAC_SPS) while ((newLength >> shift) * channelData.freq > DAC_SPS)
shift++; shift++;
if (shift != 0) if (shift != 0)
{ {
channelData.divisibility -= shift; channelData.divisibility -= shift;
channelData.length >>= shift; newLength >>= shift;
for (int i = 0; i < channelData.length; ++i) for (int i = 0; i < newLength; ++i)
channelData.samples[i] = channelData.samples[i << shift]; channelData.samples[i] = channelData.samples[i << shift];
channelData.samples.resize(channelData.length); channelData.samples.resize(newLength);
channelData.samples.shrink_to_fit(); channelData.samples.shrink_to_fit();
if (channelData.divisibility <= 0) if (channelData.divisibility <= 0)
@ -161,9 +163,9 @@ void genericUsbDriver::setFunctionGen(int channelID, functionGenControl *fGenCon
// Timer Setup // Timer Setup
int validClockDivs[7] = {1, 2, 4, 8, 64, 256, 1024}; int validClockDivs[7] = {1, 2, 4, 8, 64, 256, 1024};
auto period = [=](int division) -> int auto period = [&](int division) -> int
{ {
return CLOCK_FREQ / (division * channelData.length * channelData.freq); return CLOCK_FREQ / (division * channelData.samples.size() * channelData.freq);
}; };
int* clkSettingIt = std::find_if(std::begin(validClockDivs), std::end(validClockDivs), int* clkSettingIt = std::find_if(std::begin(validClockDivs), std::end(validClockDivs),
@ -178,11 +180,10 @@ void genericUsbDriver::setFunctionGen(int channelID, functionGenControl *fGenCon
qDebug("DEVICE IS IN MODE 5"); qDebug("DEVICE IS IN MODE 5");
if (channelID == ChannelID::CH2)
if (channelID) usbSendControl(0x40, 0xa1, timerPeriod, clkSetting, channelData.samples.size(), channelData.samples.data());
usbSendControl(0x40, 0xa1, timerPeriod, clkSetting, channelData.length, channelData.samples.data());
else else
usbSendControl(0x40, 0xa2, timerPeriod, clkSetting, channelData.length, channelData.samples.data()); usbSendControl(0x40, 0xa2, timerPeriod, clkSetting, channelData.samples.size(), channelData.samples.data());
return; return;
} }
@ -204,8 +205,8 @@ void genericUsbDriver::setDeviceMode(int mode){
deviceMode = mode; deviceMode = mode;
usbSendControl(0x40, 0xa5, (mode == 5 ? 0 : mode), gainMask, 0, NULL); usbSendControl(0x40, 0xa5, (mode == 5 ? 0 : mode), gainMask, 0, NULL);
if (fGenPtr_CH1!=NULL) setFunctionGen(0, fGenPtr_CH1); if (fGenPtr_CH1 != NULL) setFunctionGen(functionGenControl::ChannelID::CH1, fGenPtr_CH1);
if (fGenPtr_CH2!=NULL) setFunctionGen(1, fGenPtr_CH2); if (fGenPtr_CH2 != NULL) setFunctionGen(functionGenControl::ChannelID::CH2, fGenPtr_CH2);
//switch on new deviceMode!! //switch on new deviceMode!!
switch(deviceMode){ switch(deviceMode){

View File

@ -115,7 +115,7 @@ signals:
void calibrateMe(void); void calibrateMe(void);
public slots: public slots:
void setPsu(double voltage); void setPsu(double voltage);
void setFunctionGen(int channel, functionGenControl *fGenControl); void setFunctionGen(functionGenControl::ChannelID channel, functionGenControl *fGenControl);
void setDeviceMode(int mode); void setDeviceMode(int mode);
void newDig(int digState); void newDig(int digState);
void psuTick(void); void psuTick(void);

View File

@ -127,7 +127,7 @@ MainWindow::MainWindow(QWidget *parent) :
connect(ui->debugButton1, SIGNAL(clicked()), ui->controller_iso->driver, SLOT(avrDebug())); connect(ui->debugButton1, SIGNAL(clicked()), ui->controller_iso->driver, SLOT(avrDebug()));
connect(ui->psuSlider, SIGNAL(voltageChanged(double)), ui->controller_iso->driver, SLOT(setPsu(double))); connect(ui->psuSlider, SIGNAL(voltageChanged(double)), ui->controller_iso->driver, SLOT(setPsu(double)));
connect(ui->controller_iso, SIGNAL(setGain(double)), ui->controller_iso->driver, SLOT(setGain(double))); connect(ui->controller_iso, SIGNAL(setGain(double)), ui->controller_iso->driver, SLOT(setGain(double)));
connect(ui->controller_fg, SIGNAL(functionGenToUpdate(int,functionGenControl*)), ui->controller_iso->driver, SLOT(setFunctionGen(int,functionGenControl*))); connect(ui->controller_fg, &functionGenControl::functionGenToUpdate, ui->controller_iso->driver, &genericUsbDriver::setFunctionGen);
connect(ui->bufferDisplay, SIGNAL(modeChange(int)), ui->controller_iso->driver, SLOT(setDeviceMode(int))); connect(ui->bufferDisplay, SIGNAL(modeChange(int)), ui->controller_iso->driver, SLOT(setDeviceMode(int)));
connect(ui->bufferDisplay, SIGNAL(updateDig(int)), ui->controller_iso->driver, SLOT(newDig(int))); connect(ui->bufferDisplay, SIGNAL(updateDig(int)), ui->controller_iso->driver, SLOT(newDig(int)));
@ -1334,7 +1334,7 @@ void MainWindow::reinitUsbStage2(void){
connect(ui->debugButton3, SIGNAL(clicked()), ui->controller_iso->driver, SLOT(bootloaderJump())); connect(ui->debugButton3, SIGNAL(clicked()), ui->controller_iso->driver, SLOT(bootloaderJump()));
connect(ui->psuSlider, SIGNAL(voltageChanged(double)), ui->controller_iso->driver, SLOT(setPsu(double))); connect(ui->psuSlider, SIGNAL(voltageChanged(double)), ui->controller_iso->driver, SLOT(setPsu(double)));
connect(ui->controller_iso, SIGNAL(setGain(double)), ui->controller_iso->driver, SLOT(setGain(double))); connect(ui->controller_iso, SIGNAL(setGain(double)), ui->controller_iso->driver, SLOT(setGain(double)));
connect(ui->controller_fg, SIGNAL(functionGenToUpdate(int,functionGenControl*)), ui->controller_iso->driver, SLOT(setFunctionGen(int,functionGenControl*))); connect(ui->controller_fg, &functionGenControl::functionGenToUpdate, ui->controller_iso->driver, &genericUsbDriver::setFunctionGen);
connect(ui->bufferDisplay, SIGNAL(modeChange(int)), ui->controller_iso->driver, SLOT(setDeviceMode(int))); connect(ui->bufferDisplay, SIGNAL(modeChange(int)), ui->controller_iso->driver, SLOT(setDeviceMode(int)));
connect(ui->bufferDisplay, SIGNAL(updateDig(int)), ui->controller_iso->driver, SLOT(newDig(int))); connect(ui->bufferDisplay, SIGNAL(updateDig(int)), ui->controller_iso->driver, SLOT(newDig(int)));
@ -1368,8 +1368,8 @@ void MainWindow::resetUsbState(void){
ui->psuSlider->poke(); ui->psuSlider->poke();
//ui->controller_iso->driver->newDig(digitalPinState); //ui->controller_iso->driver->newDig(digitalPinState);
ui->bufferDisplay->poke(); ui->bufferDisplay->poke();
ui->controller_iso->driver->setFunctionGen(0,ui->controller_fg); ui->controller_iso->driver->setFunctionGen(functionGenControl::ChannelID::CH1, ui->controller_fg);
ui->controller_iso->driver->setFunctionGen(1,ui->controller_fg); ui->controller_iso->driver->setFunctionGen(functionGenControl::ChannelID::CH2, ui->controller_fg);
ui->controller_iso->clearBuffers(1,1,1); ui->controller_iso->clearBuffers(1,1,1);
ui->controller_iso->doNotTouchGraph = false; ui->controller_iso->doNotTouchGraph = false;