Browse Source

Reworked the architecture to allow for a publisher/subscriber model. Added signal processing. Make sure to stop the hub before changing channels! (To be done automatically in the future) and there is NO typesafety for the publisher/subscriber... yet!~

software_develop
Elmar van Rijnswou 7 years ago
parent
commit
937be691fc
  1. 3
      software/app/ads101x.cpp
  2. 43
      software/app/ads_converter.cpp
  3. 31
      software/app/ads_converter.h
  4. 34
      software/app/application.cpp
  5. 44
      software/app/data_provider.h
  6. 29
      software/app/data_receiver.h
  7. 26
      software/app/data_sink.h
  8. 8
      software/app/double_buffer.h
  9. 22
      software/app/helper_structs.h
  10. 23
      software/app/sensor_hub.cpp
  11. 5
      software/app/sensor_hub.h
  12. 15
      software/app/sensor_settings.h
  13. 38
      software/app/signal_process.cpp
  14. 31
      software/app/signal_process.h
  15. 44
      software/app/signal_processor.cpp
  16. 66
      software/app/signal_processor.h
  17. 47
      software/app/web_interface.cpp
  18. 29
      software/app/web_interface.h

3
software/app/ads101x.cpp

@ -155,7 +155,8 @@ ads_sample_t cADS101x::RawSample(void) {
ads_sample_t sample;
sample.gain = m_gain;
sample.mux = m_mux;
sample.rawSample = m_counter++;
sample.rawSample = m_counter;
m_counter += 16;
return sample;
#else
OneShot();

43
software/app/ads_converter.cpp

@ -0,0 +1,43 @@
/*
* ads_converter.cpp
*
* Created on: Aug 22, 2017
* Author: Elmar
*/
#include "ads_converter.h"
#include "double_buffer.h"
#include "helper_structs.h"
namespace rijnfel {
cAdsConverter::cAdsConverter(cADC<ads::ads_sample_t, int32_t> & i_adc) :
m_adc(i_adc), m_rawSamples(this) {
// TODO Auto-generated constructor stub
}
cAdsConverter::~cAdsConverter() {
// TODO Auto-generated destructor stub
}
void cAdsConverter::ReceiveCallback(void* i_data, cDataReceiver* i_provider) {
//We dont car for the provider
cDoubleBuffer<ads::ads_sample_t> * i_adcBuffer = static_cast<cDoubleBuffer<ads::ads_sample_t>*>(i_data);
ads::ads_sample_t * buf = &i_adcBuffer->GetReadyBuffer()[0];
if (buf != NULL) {
sSizedArray arr;
int pos = buf->mux - ads::eInputMux::AIN_0;
int64_t average = 0;
int size = i_adcBuffer->GetSize();
arr.size = size;
arr.array = new uint32_t[size];
for (int i = 0; i < size; i++) {
arr.array[i] = m_adc.ConvertSample(buf[i]);
}
m_convertedSamples[pos].Push(static_cast<void *>(&arr));
delete arr.array;
}
}
} /* namespace rijnfel */

31
software/app/ads_converter.h

@ -0,0 +1,31 @@
/*
* ads_converter.h
*
* Created on: Aug 22, 2017
* Author: Elmar
*/
#ifndef APP_ADS_CONVERTER_H_
#define APP_ADS_CONVERTER_H_
#include "data_receiver.h"
#include "data_provider.h"
#include "ads101x.h"
namespace rijnfel {
class cAdsConverter: public cDataSink {
public:
cAdsConverter(cADC<ads::ads_sample_t, int32_t> & i_adc);
virtual void ReceiveCallback(void * i_data, cDataReceiver * i_provider);
// Every channel has its own provider, after this we can not distinguish anymore
cDataProvider m_convertedSamples[4];
cDataReceiver m_rawSamples;
virtual ~cAdsConverter();
private:
cADC<ads::ads_sample_t, int32_t> & m_adc;
};
} /* namespace rijnfel */
#endif /* APP_ADS_CONVERTER_H_ */

34
software/app/application.cpp

@ -4,18 +4,23 @@
#include "ads101x.h"
#include <hardware.h>
#include "excitation_light.h"
#include "signal_processor.h"
#include "sensor_hub.h"
#include "sensor_settings.h"
#include "double_buffer.h"
#include "web_interface.h"
#include <stdint.h>
#include "ads_converter.h"
#include "signal_process.h"
using namespace rijnfel;
void STADisconnect(String ssid, uint8_t ssid_len, uint8_t bssid[6], uint8_t reason);
void STAGotIP(IPAddress ip, IPAddress mask, IPAddress gateway);
cAdsConverter * adsConverter;
//We want different signal processing for the channels
cSignalProcess signalProcess[2];
Timer procTimer;
Timer rectangleTimer;
ads::cADS101x adc(0, ADC_ADDRESS);
@ -49,17 +54,6 @@ void updateSensorHub() {
hub.Update();
}
void adcCallback(cDoubleBuffer<ads::ads_sample_t> & buffer) {
channel = 0;
if (channel > 3) {
channel = 0;
//cWebInterface::GetInstance()->PrintValues();
}
cSignalProcessor::GetInstance()->receiveADCValues(adc, buffer);
//cWebInterface::GetInstance()->UpdateAdc(adc, buffer);
adc.SetMux(static_cast<ads::eInputMux>(ads::eInputMux::AIN_0 + channel));
}
void ready() {
WifiAccessPoint.config("Sensus", "", AUTH_OPEN, false, 3);
//debugf("READY!");
@ -84,6 +78,7 @@ void init() {
//SET higher CPU freq & disable wifi sleep
// Turn off LED for measurements
hub.Stop();
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, 1);
adc.SetMux(ads::eInputMux::AIN_0);
@ -91,16 +86,29 @@ void init() {
adc.SetGain(ads::eGainAmplifier::FSR_4_096);
adc.SetOneShot(false);
hub.SetAdc(&adc);
adsConverter = new cAdsConverter(adc);
cSensorSettings<ads::ads_sample_t> * adcSettings;
adcSettings = new cSensorSettings<ads::ads_sample_t>(&adcCallback, ADC_TIMEBASE, ADC_PERIOD);
adcSettings = new cSensorSettings<ads::ads_sample_t>(ADC_TIMEBASE, ADC_PERIOD);
adcSettings->m_samplesProvider.Connect(&adsConverter->m_rawSamples);
hub.SetAdcSettings(adcSettings);
// Channel one and two are getting processed
adsConverter->m_convertedSamples[0].Connect(&signalProcess[0].m_incommingData);
adsConverter->m_convertedSamples[1].Connect(&signalProcess[1].m_incommingData);
signalProcess[0].m_processedData.Connect(&cWebInterface::GetInstance()->m_adc_0);
signalProcess[1].m_processedData.Connect(&cWebInterface::GetInstance()->m_adc_1);
// Channel three and four are not
adsConverter->m_convertedSamples[2].Connect(&cWebInterface::GetInstance()->m_adc_2);
adsConverter->m_convertedSamples[3].Connect(&cWebInterface::GetInstance()->m_adc_3);
WifiEvents.onStationDisconnect(STADisconnect);
WifiEvents.onStationGotIP(STAGotIP);
cWebInterface::GetInstance()->StartServer();
procTimer.initializeMs(HUB_PERIOD, updateSensorHub).start();
hub.Start();
//procTimer.initializeMs(1000, AdcTest).start();
//procTimer.initializeMs(5000, SettingsTest).start();
//mylight.SetCurrent(5000);

44
software/app/data_provider.h

@ -0,0 +1,44 @@
/*
* data_provider.h
*
* Created on: Aug 22, 2017
* Author: Elmar
*/
#ifndef APP_DATA_PROVIDER_H_
#define APP_DATA_PROVIDER_H_
#include <vector>
#include <stddef.h>
#include "data_receiver.h"
namespace rijnfel {
class cDataProvider {
public:
void Connect(cDataReceiver * i_receiver) {
m_receivers.push_back(i_receiver);
}
void Push(void * i_data) {
typedef std::vector<cDataReceiver*>::iterator Iterator;
for (Iterator it = m_receivers.begin(), it_e = m_receivers.end(); it != it_e; ++it) {
(*it)->Receive(i_data);
}
}
~cDataProvider() {
//
//typedef std::vector<cDataReceiver>::iterator Iterator;
//for (Iterator it = receivers.begin(), it_e = receivers.end(); it != it_e; ++it) {
// if ((*it) != NULL) {
// delete (*it);
// }
//}
}
private:
std::vector<cDataReceiver*> m_receivers;
};
}
#endif /* APP_DATA_PROVIDER_H_ */

29
software/app/data_receiver.h

@ -0,0 +1,29 @@
/*
* data_receiver.h
*
* Created on: Aug 22, 2017
* Author: Elmar
*/
#ifndef APP_DATA_RECEIVER_H_
#define APP_DATA_RECEIVER_H_
#include "data_sink.h"
namespace rijnfel {
class cDataReceiver {
public:
cDataReceiver(cDataSink * i_sink) {
m_sink = i_sink;
}
void Receive(void * i_data) {
m_sink->ReceiveCallback(i_data, this);
}
private:
cDataSink * m_sink;
};
}
#endif /* APP_DATA_RECEIVER_H_ */

26
software/app/data_sink.h

@ -0,0 +1,26 @@
/*
* data_sink.h
*
* Created on: Aug 22, 2017
* Author: Elmar
*/
#ifndef APP_DATA_SINK_H_
#define APP_DATA_SINK_H_
namespace rijnfel {
class cDataReceiver;
class cDataSink {
public:
virtual void ReceiveCallback(void * i_data, cDataReceiver * i_receiver);
protected:
cDataSink() {
}
virtual ~cDataSink() {
}
};
}
#endif /* APP_DATA_SINK_H_ */

8
software/app/double_buffer.h

@ -33,12 +33,16 @@ public:
m_buf[1] = new BufferType[m_size];
}
void Reset() {
m_bufferIndex = !m_bufferIndex;
m_writeIndex = 0;
}
bool AddValue(BufferType i_val) {
m_buf[m_bufferIndex][m_writeIndex] = i_val;
m_writeIndex++;
if (m_writeIndex >= m_size) {
m_bufferIndex = !m_bufferIndex;
m_writeIndex = 0;
Reset();
return true;
}
return false;

22
software/app/helper_structs.h

@ -0,0 +1,22 @@
/*
* helper_structs.h
*
* Created on: Aug 22, 2017
* Author: Elmar
*/
#ifndef APP_HELPER_STRUCTS_H_
#define APP_HELPER_STRUCTS_H_
namespace rijnfel{
struct sSizedArray{
size_t size;
uint32_t * array;
};
}
#endif /* APP_HELPER_STRUCTS_H_ */

23
software/app/sensor_hub.cpp

@ -15,13 +15,17 @@ cSensorHub::cSensorHub(uint32_t i_updatePeriod) :
m_adc = new ads::cADS101x();
m_adcSettings = NULL;
m_tempSettings = NULL;
m_running = false;
}
void cSensorHub::Update() {
if (!m_running)
return;
if (m_adcSettings) {
if (m_adcSettings->ShouldSample(m_updatePeriod)) {
if (m_adcSettings->m_buffer.AddValue(m_adc->RawSample())) {
m_adcSettings->m_callback(m_adcSettings->m_buffer);
//m_adcSettings->m_callback(m_adcSettings->m_buffer);
m_adcSettings->m_samplesProvider.Push(static_cast<void*>(&m_adcSettings->m_buffer));
}
}
}
@ -34,8 +38,7 @@ void cSensorHub::SetAdc(ads::cADS101x* i_adc) {
m_adc = i_adc;
}
void cSensorHub::SetAdcSettings(
cSensorSettings<ads::ads_sample_t> * i_adcSettings) {
void cSensorHub::SetAdcSettings(cSensorSettings<ads::ads_sample_t> * i_adcSettings) {
m_adcSettings = i_adcSettings;
}
@ -43,6 +46,20 @@ void cSensorHub::SetTempSettings(cSensorSettings<uint32_t> * i_tempSettings) {
m_tempSettings = i_tempSettings;
}
void cSensorHub::Stop() {
if (m_running) {
m_running = false;
//if (m_adcSettings) {
// m_adcSettings->m_samplesProvider.Push(static_cast<void*>(&m_adcSettings->m_buffer));
m_adcSettings->Reset();
//}
}
}
void cSensorHub::Start() {
m_running = true;
}
cSensorHub::~cSensorHub() {
if (m_adcSettings)
delete m_adcSettings;

5
software/app/sensor_hub.h

@ -11,6 +11,7 @@
#include "ads101x.h"
#include "sensor_settings.h"
namespace rijnfel {
class cSensorHub {
@ -19,14 +20,18 @@ public:
cSensorHub(uint32_t i_updatePeriod);
void SetAdc(ads::cADS101x * i_adc);
void SetAdcSettings(cSensorSettings<ads::ads_sample_t> * i_adcSettings);
void Stop();
void Start();
void SetTempSettings(cSensorSettings<uint32_t> * i_tempSettings);
void Update();
virtual ~cSensorHub();
private:
uint32_t m_updatePeriod;
cSensorSettings<ads::ads_sample_t> * m_adcSettings;
cSensorSettings<uint32_t> * m_tempSettings;
ads::cADS101x * m_adc;
bool m_running;
};
} /* namespace rijnfel */

15
software/app/sensor_settings.h

@ -9,6 +9,7 @@
#define APP_SENSOR_SETTINGS_H_
#include "double_buffer.h"
#include "data_provider.h"
namespace rijnfel {
//timebase, in miliseconds.
@ -17,13 +18,16 @@ namespace rijnfel {
template<typename BufferType>
class cSensorSettings {
public:
cSensorSettings(void (*i_callback)(cDoubleBuffer<BufferType> & buffer),
uint32_t i_timeBase, uint32_t i_period) :
m_callback(i_callback), m_periodTimer(0), m_period(i_period), m_buffer(
0) {
cSensorSettings(uint32_t i_timeBase, uint32_t i_period) :
m_periodTimer(0), m_period(i_period), m_buffer(0) {
m_buffer.Resize((int) (i_timeBase / m_period));
}
void Reset() {
m_periodTimer = 0;
m_buffer.Reset();
}
bool ShouldSample(uint32_t i_updatePeriod) {
m_periodTimer += i_updatePeriod;
if (m_periodTimer >= m_period) {
@ -32,9 +36,8 @@ public:
}
return false;
}
cDataProvider m_samplesProvider;
cDoubleBuffer<BufferType> m_buffer;
void (*m_callback)(cDoubleBuffer<BufferType> & buffer);
private:
uint32_t m_periodTimer;
uint32_t m_period;

38
software/app/signal_process.cpp

@ -0,0 +1,38 @@
/*
* signal_process.cpp
*
* Created on: Aug 22, 2017
* Author: Elmar
*/
#include "signal_process.h"
#include "helper_structs.h"
#include <stddef.h>
//TODO remove this
namespace rijnfel {
cSignalProcess::cSignalProcess() :
m_incommingData(this) {
m_currentIndex = 0;
m_currentMaxIndex = 0;
m_currentBuffer = NULL;
// TODO Auto-generated constructor stub
}
cSignalProcess::~cSignalProcess() {
// TODO Auto-generated destructor stub
}
void cSignalProcess::ReceiveCallback(void* i_data, cDataReceiver* i_provider) {
sSizedArray * arr = static_cast<sSizedArray*>(i_data);
process(arr->array, arr->size);
m_processedData.Push(i_data);
}
void cSignalProcess::process(uint32_t* io_array, size_t size) {
//Do whatever here really
}
} /* namespace rijnfel */

31
software/app/signal_process.h

@ -0,0 +1,31 @@
/*
* signal_process.h
*
* Created on: Aug 22, 2017
* Author: Elmar
*/
#ifndef APP_SIGNAL_PROCESS_H_
#define APP_SIGNAL_PROCESS_H_
#include "data_receiver.h"
#include "data_provider.h"
namespace rijnfel {
class cSignalProcess: public cDataSink {
public:
cSignalProcess();
virtual ~cSignalProcess();
void ReceiveCallback(void * i_data, cDataReceiver * i_provider);
cDataReceiver m_incommingData;
cDataProvider m_processedData;
protected:
void process(uint32_t * io_array, size_t size);
uint32_t * m_currentBuffer;
uint32_t m_currentIndex;
uint32_t m_currentMaxIndex;
};
} /* namespace rijnfel */
#endif /* APP_SIGNAL_PROCESS_H_ */

44
software/app/signal_processor.cpp

@ -1,44 +0,0 @@
//----------------------------------------------------------------------------------------------------------------------------
// Project: Uppsense
// Name: signal_processor.cpp
// Author: Maximilian Stiefel
// Date: 22.08.2017
//
// Description:
//
//----------------------------------------------------------------------------------------------------------------------------
//-------------------------------------Libraries------------------------------------------------------------------------------
#include "signal_processor.h"
#include <SmingCore/SmingCore.h>
//-------------------------------------Namespaces-----------------------------------------------------------------------------
namespace rijnfel {
cSignalProcessor* cSignalProcessor::s_instance = NULL;
//-------------------------------------GetInstance----------------------------------------------------------------------------
cSignalProcessor* cSignalProcessor::GetInstance()
{
if(s_instance == NULL)
s_instance = new cSignalProcessor;
return s_instance;
}
//-------------------------------------receiveADCValues-----------------------------------------------------------------------
void cSignalProcessor::receiveADCValues(cADC<ads::ads_sample_t, int32_t> & i_adc, cDoubleBuffer<ads::ads_sample_t>& i_adcBuffer) {
ads::ads_sample_t * buf = &i_adcBuffer.GetReadyBuffer()[0];
if (buf != NULL) {
int pos = buf->mux - ads::eInputMux::AIN_0;
int64_t average = 0;
int size = i_adcBuffer.GetSize();
for (int i = 0; i < size; i++) {
average += i_adc.ConvertSample(buf[i]);
}
if (size != 0) {
average /= size;
}
Serial.printf("Average: %d/n/r", average);
}
}
}

66
software/app/signal_processor.h

@ -1,66 +0,0 @@
//----------------------------------------------------------------------------------------------------------------------------
// Project: Uppsense
// Name: signal_processor.h
// Author: Maximilian Stiefel
// Date: 22.08.2017
//
// Description:
//
//----------------------------------------------------------------------------------------------------------------------------
#ifndef APP_SIGNAL_PROCESSOR_H_
#define APP_SIGNAL_PROCESSOR_H_
//-------------------------------------Libraries------------------------------------------------------------------------------
#include <stdint.h>
#include "defines.h"
#include "double_buffer.h"
#include "adc.h"
#include "ads101x.h"
//-------------------------------------Defines--------------------------------------------------------------------------------
//-------------------------------------Namespaces-----------------------------------------------------------------------------
namespace rijnfel {
//-------------------------------------Enums----------------------------------------------------------------------------------
//-------------------------------------cDAC101085-----------------------------------------------------------------------------
/** Small simple driver for the TI DAC101C085.
*/
class cSignalProcessor
{
public:
/**
* @brief Returns the global cSignalProcessor instance.
* Only one webserver should ever be running
* @return global cSignalProcessor instance
* */
static cSignalProcessor *GetInstance();
public:
/**
* @brief Notifies object that new samples are available.
* @param i_adc Instance of the adc sensor.
* @param i_adcBuffer Buffer containing the raw adc values.
* */
void receiveADCValues(cADC<ads::ads_sample_t, int32_t> & i_adc, cDoubleBuffer<ads::ads_sample_t> & i_adcBuffer);
private:
// Singleton instance
static cSignalProcessor *s_instance;
/**
* @brief Constructor is private, so it can not be called.
*/
cSignalProcessor(){};
/**
* @brief Copy constructor is private, so it can not be called.
*/
cSignalProcessor(cSignalProcessor const&){};
/**
* @brief Assignment operator is private, so it can not be used.
*/
cSignalProcessor& operator=(cSignalProcessor const&){};
};
}
#endif /* APP_SIGNAL_PROCESSOR_H_ */

47
software/app/web_interface.cpp

@ -6,6 +6,7 @@
*/
#include "web_interface.h"
#include "helper_structs.h"
#include <SmingCore/SmingCore.h>
#include <SmingCore/Network/WebConstants.h>
#include <SmingCore/FileSystem.h>
@ -31,7 +32,7 @@ static void onConfiguration_json(HttpRequest &request, HttpResponse &response) {
}
cWebInterface::cWebInterface() :
m_serverStarted(false) {
m_serverStarted(false), m_adc_0(this), m_adc_1(this), m_adc_2(this), m_adc_3(this) {
for (int i = 0; i < 4; i++) {
m_adc_value_average[i] = 0;
}
@ -103,38 +104,30 @@ void cWebInterface::OnRefresh(HttpRequest & i_request, HttpResponse & i_response
void cWebInterface::OnRawUpdate(HttpRequest& i_request, HttpResponse& i_response) {
}
void cWebInterface::UpdateAdc(cADC<ads::ads_sample_t, int32_t> & i_adc, cDoubleBuffer<ads::ads_sample_t>& i_adcBuffer) {
ads::ads_sample_t * buf = &i_adcBuffer.GetReadyBuffer()[0];
if (buf != NULL) {
int pos = buf->mux - ads::eInputMux::AIN_0;
int64_t average = 0;
int size = i_adcBuffer.GetSize();
for (int i = 0; i < size; i++) {
average += i_adc.ConvertSample(buf[i]);
if (pos == RAW_CHANNEL) {
int idx = m_adc_values_raw_cnt[RAW_CHANNEL];
if (idx < RAW_SAMPLES) {
m_adc_values_raw[RAW_CHANNEL][idx] = i_adc.ConvertSample(buf[i]);
m_adc_values_raw_cnt[RAW_CHANNEL]++;
}
}
}
if (size != 0) {
average /= size;
}
m_adc_value_average[pos] = static_cast<int32_t>(average);
void cWebInterface::ReceiveCallback(void* i_data, cDataReceiver* i_receiver) {
int64_t average = 0;
sSizedArray * arr = static_cast<sSizedArray *>(i_data);
for (int i = 0; i < arr->size; i++) {
average += arr->array[i];
}
average /= arr->size;
if (i_receiver == &m_adc_0) {
m_adc_value_average[0] = static_cast<int32_t>(average);
} else if (i_receiver == &m_adc_1) {
m_adc_value_average[1] = static_cast<int32_t>(average);
} else if (i_receiver == &m_adc_2) {
m_adc_value_average[2] = static_cast<int32_t>(average);
} else if (i_receiver == &m_adc_3) {
m_adc_value_average[3] = static_cast<int32_t>(average);
}
PrintValues();
}
void cWebInterface::PrintValues() {
Serial.printf("c[0]: %d c[1]: %d c[2]: %d c[3]: %d\n\r", m_adc_value_average[0], m_adc_value_average[1],
m_adc_value_average[2], m_adc_value_average[3]);
}
void cWebInterface::UpdateTemp(cDoubleBuffer<uint32_t>& i_tempBuffer) {
}
cWebInterface::~cWebInterface() {
// TODO Auto-generated destructor stub
}
@ -144,7 +137,7 @@ void cWebInterface::OnFile(HttpRequest& i_request, HttpResponse& i_response) {
file_t file = fileOpen(name, eFO_CreateIfNotExist | eFO_ReadWrite);
int size = m_adc_values_raw_cnt[RAW_CHANNEL];
Serial.printf("Size: %d\n\r",size);
Serial.printf("Size: %d\n\r", size);
char buf[12];
for (int i = 0; i < 4; i++) {
int len = sprintf(buf, "%d,", m_adc_values_raw[RAW_CHANNEL][i]);

29
software/app/web_interface.h

@ -15,11 +15,12 @@
#include "double_buffer.h"
#include <SmingCore/SmingCore.h>
#include "data_receiver.h"
namespace rijnfel {
#define RAW_CHANNEL 1
#define RAW_SAMPLES 1000
class cWebInterface {
class cWebInterface: public cDataSink {
public:
/**
* Returns the global cWebInterface instance.
@ -59,19 +60,6 @@ public:
*/
void StopServer();
/**
* Updates the adc on the website. Averages it
* @param i_adc Instance of the adc sensor
* @param i_adcBuffer Buffer containing the raw adc values
*/
void UpdateAdc(cADC<ads::ads_sample_t, int32_t> & i_adc, cDoubleBuffer<ads::ads_sample_t> & i_adcBuffer);
/**
* Updates the temperature on the website
* @param i_tempBuffer buffer containing temperature values
*/
void UpdateTemp(cDoubleBuffer<uint32_t> & i_tempBuffer);
/**
* This is a debug function that prints out the average values
* @todo remove this
@ -82,6 +70,19 @@ public:
* Destructor
*/
virtual ~cWebInterface();
// This is what the future will look like
// cDataReceiver m_sensorVal[2];
// cDataReceiver m_battery;
// cDataReceiver m_ledLife;
// cDataReceiver m_temp;
// But for now...
cDataReceiver m_adc_0;
cDataReceiver m_adc_1;
cDataReceiver m_adc_2;
cDataReceiver m_adc_3;
virtual void ReceiveCallback(void * i_data, cDataReceiver * i_receiver);
public:
/**
*

Loading…
Cancel
Save