From 6b49cbebb36db598c4f7fa25e740cfc000c4aa92 Mon Sep 17 00:00:00 2001 From: Elmar van Rijnswou Date: Wed, 16 Aug 2017 12:49:36 +0200 Subject: [PATCH] Solved inaccuracy problem with adc. Started with a nice overview for the raw samples --- software/app/adc.h | 19 +++- software/app/ads101x.cpp | 30 ++++- software/app/ads101x.h | 5 + software/app/web_interface.cpp | 200 +++++++++++++++++---------------- software/app/web_interface.h | 111 +++++++++++++++--- software/files/index.html | 22 +++- software/files/index.js | 5 +- 7 files changed, 272 insertions(+), 120 deletions(-) diff --git a/software/app/adc.h b/software/app/adc.h index 85628c1..6290397 100644 --- a/software/app/adc.h +++ b/software/app/adc.h @@ -12,13 +12,30 @@ namespace rijnfel { +/** + * Abstract interface for Analog to Digital converters. + * Template holds sample type and voltage type + */ template class cADC: public cSensor { public: + /** + * Default constructor + */ cADC() { } - virtual Voltage ConvertSample(Sample & sample) = 0; + + /** + * This virtual function should be implemented to convert a sample to a voltage + * @param i_sample the raw sample that should be converted + * @return a voltage in mili-volt + */ + virtual Voltage ConvertSample(Sample & i_sample) = 0; + + /** + * Default destructor + */ virtual ~cADC() { } diff --git a/software/app/ads101x.cpp b/software/app/ads101x.cpp index d9be1ba..e3102be 100644 --- a/software/app/ads101x.cpp +++ b/software/app/ads101x.cpp @@ -74,27 +74,34 @@ bool cADS101x::IsReady(void) { } uint16_t cADS101x::CreateSettings(uint8_t start) { - return OS_BIT(start) | MUX_BIT(m_mux) | PGA_BIT(m_gain) - | MODE_BIT(m_oneShot) | DR_BIT(m_sampleSpeed); + return OS_BIT(start) | MUX_BIT(m_mux) | PGA_BIT(m_gain) | MODE_BIT(m_oneShot) | DR_BIT(m_sampleSpeed); } void cADS101x::WriteSettings(uint16_t i_settings) { +#ifdef DUMMY_ADC + return; +#else Wire.beginTransmission(m_address); Wire.write((uint8_t) REGISTER_CONFIG); Wire.write((uint8_t) (i_settings >> 8)); Wire.write((uint8_t) (i_settings & 0xFF)); int8_t ret = Wire.endTransmission(); if (ret) { - Serial.printf("Err writing settings ret: %d\n\r", ret); + //Serial.printf("Err writing settings ret: %d\n\r", ret); } +#endif } uint16_t cADS101x::ReadRegister(uint8_t i_register) { +#ifdef DUMMY_ADC + return 1; +#else Wire.beginTransmission(m_address); Wire.write(i_register); Wire.endTransmission(); Wire.requestFrom(m_address, static_cast(2)); return ((Wire.read() << 8) | (Wire.read())); +#endif } void cADS101x::OneShot(void) { @@ -105,7 +112,11 @@ void cADS101x::OneShot(void) { } uint16_t cADS101x::GetSettings(void) { - return ReadRegister(REGISTER_CONFIG);; +#ifdef DUMMY_ADC + return CreateSettings(0); +#else + return ReadRegister(REGISTER_CONFIG); +#endif } ads_voltage_t cADS101x::ConvertSample(ads_sample_t & sample) { //Raw sample is in (parts of) millivolts, go to micro to remove fractions @@ -140,12 +151,20 @@ ads_voltage_t cADS101x::ConvertSample(ads_sample_t & sample) { } ads_sample_t cADS101x::RawSample(void) { +#ifdef DUMMY_ADC + ads_sample_t sample; + sample.gain = m_gain; + sample.mux = m_mux; + sample.rawSample = m_counter++; + return sample; +#else OneShot(); ads_sample_t sample; sample.rawSample = ReadRegister(REGISTER_CONVERSION); sample.gain = m_gain; sample.mux = m_mux; m_latestSample = sample; +#endif return sample; } @@ -154,6 +173,9 @@ void cADS101x::SetDefaults(void) { m_gain = eGainAmplifier::FSR_2_048; m_sampleSpeed = eSampleSpeed::SPS_1600; m_oneShot = true; +#ifdef DUMMY_ADC + m_counter = 0; +#endif } } diff --git a/software/app/ads101x.h b/software/app/ads101x.h index 6612ce5..96b2504 100644 --- a/software/app/ads101x.h +++ b/software/app/ads101x.h @@ -9,6 +9,7 @@ #define APP_ADS101X_H_ #include +#include "hardware.h" #include "adc.h" namespace rijnfel { @@ -65,6 +66,10 @@ private: enum eInputMux m_mux; enum eGainAmplifier m_gain; enum eSampleSpeed m_sampleSpeed; +private: +#ifdef DUMMY_ADC + uint16_t m_counter; +#endif }; } } diff --git a/software/app/web_interface.cpp b/software/app/web_interface.cpp index 67b5cab..5e19dfd 100644 --- a/software/app/web_interface.cpp +++ b/software/app/web_interface.cpp @@ -7,20 +7,18 @@ #include "web_interface.h" #include - -//TODO remove this -#include "ads101x.h" +#include namespace rijnfel { cWebInterface *cWebInterface::s_instance = 0; -static void onIndex(HttpRequest &request, HttpResponse &response) { - cWebInterface::GetInstance()->OnIndex(request, response); +static void onIndex(HttpRequest & i_request, HttpResponse & i_response) { + cWebInterface::GetInstance()->OnIndex(i_request, i_response); } -static void onRefresh(HttpRequest &request, HttpResponse &response) { - cWebInterface::GetInstance()->OnRefresh(request, response); +static void onRefresh(HttpRequest & i_request, HttpResponse & i_response) { + cWebInterface::GetInstance()->OnRefresh(i_request, i_response); } static void onConfiguration(HttpRequest &request, HttpResponse &response) { @@ -34,159 +32,174 @@ static void onConfiguration_json(HttpRequest &request, HttpResponse &response) { cWebInterface::cWebInterface() : m_serverStarted(false) { for (int i = 0; i < 4; i++) { - m_adc_value[i] = 0; + m_adc_value_average[i] = 0; + } + // Integer requires 8 digits, and one for the comma + m_jsonBuffer = new char[RAW_SAMPLES * 8 + RAW_SAMPLES * 2]; + if (m_jsonBuffer == NULL) { + Serial.print("Not enough ram"); } // TODO Auto-generated constructor stub } -void onFile(HttpRequest &request, HttpResponse &response) { - String file = request.getPath(); +void onFile(HttpRequest & i_request, HttpResponse & i_response) { + String file = i_request.getPath(); if (file[0] == '/') file = file.substring(1); if (file[0] == '.') - response.forbidden(); + i_response.forbidden(); else { - response.setCache(86400, true); // It's important to use cache for better performance. - response.sendFile(file); + i_response.setCache(86400, true); // It's important to use cache for better performance. + i_response.sendFile(file); } } -void cWebInterface::Start() { +void cWebInterface::StartServer() { if (m_serverStarted) return; - server.addPath("/", onIndex); - server.addPath("/state", onRefresh); - server.addPath("/config", onConfiguration); - server.addPath("/config.json", onConfiguration_json); - server.setDefaultHandler(onFile); - server.listen(80); + m_server.addPath("/", onIndex); + m_server.addPath("/state", onRefresh); + m_server.addPath("/config", onConfiguration); + m_server.addPath("/config.json", onConfiguration_json); + m_server.setDefaultHandler(onFile); + m_server.listen(80); } -void cWebInterface::Stop() { +void cWebInterface::StopServer() { if (!m_serverStarted) return; m_serverStarted = false; } -void cWebInterface::OnIndex(HttpRequest &request, HttpResponse &response) { - response.setCache(86400, true); // It's important to use cache for better performance. - response.sendFile("index.html"); +void cWebInterface::OnIndex(HttpRequest &i_request, HttpResponse & i_response) { + i_response.setCache(86400, true); // It's important to use cache for better performance. + i_response.sendFile("index.html"); } -void cWebInterface::OnRefresh(HttpRequest &request, HttpResponse &response) { +void cWebInterface::OnRefresh(HttpRequest & i_request, HttpResponse & i_response) { JsonObjectStream* stream = new JsonObjectStream(); JsonObject& json = stream->getRoot(); - json["adc_1"] = m_adc_value[0]; - json["adc_2"] = m_adc_value[1]; + json["adc_1"] = m_adc_value_average[0]; + json["adc_2"] = m_adc_value_average[1]; #ifdef REV_1 - json["adc_3"] = m_adc_value[3]; - json["adc_4"] = m_adc_value[2]; + json["adc_3"] = m_adc_value_average[3]; + json["adc_4"] = m_adc_value_average[2]; #else - json["adc_3"] = m_adc_value[2]; - json["adc_4"] = m_adc_value[3]; + json["adc_3"] = m_adc_value_average[2]; + json["adc_4"] = m_adc_value_average[3]; #endif - response.sendJsonObject(stream); + char * writePos = m_jsonBuffer; + for (int sample = 0; sample < m_adc_values_raw_cnt[RAW_CHANNEL]; sample++) { + const int pos = sprintf(writePos, "%d,", m_adc_values_raw[RAW_CHANNEL][sample]); + writePos = &m_jsonBuffer[pos]; + }/* + json["raw_adc"] = m_jsonBuffer; //ss.str(); + */ + i_response.sendJsonObject(stream); + m_adc_values_raw_cnt[RAW_CHANNEL] = 0; +} + +void cWebInterface::OnRawUpdate(HttpRequest& i_request, HttpResponse& i_response) { } -void cWebInterface::UpdateAdc(cADC & adc, - cDoubleBuffer& adcBuffer) { - ads::ads_sample_t * buf = &adcBuffer.GetReadyBuffer()[0]; +void cWebInterface::UpdateAdc(cADC & i_adc, cDoubleBuffer& i_adcBuffer) { + ads::ads_sample_t * buf = &i_adcBuffer.GetReadyBuffer()[0]; if (buf != NULL) { - ads::ads_sample_t averageSample; - averageSample.gain = buf->gain; - averageSample.mux = buf->mux; + int pos = buf->mux - ads::eInputMux::AIN_0; int64_t average = 0; - //Serial.printf("Channel: %d\n\r", buf->mux - ads::eInputMux::AIN_0); - int size = adcBuffer.GetSize(); + int size = i_adcBuffer.GetSize(); for (int i = 0; i < size; i++) { - average += buf[i].rawSample; - //Serial.printf("%d ", buf[i].rawSample); + 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]++; + } + } } - //Serial.printf("\n\r before: %d", average); if (size != 0) { average /= size; } - //Serial.printf("after: %d [%d]\n\r", average, size); - averageSample.rawSample = static_cast(average); - int pos = averageSample.mux - ads::eInputMux::AIN_0; - m_adc_value[pos] = adc.ConvertSample(averageSample); + m_adc_value_average[pos] = static_cast(average); } } void cWebInterface::PrintValues() { - Serial.printf("c[0]: %d c[1]: %d c[2]: %d c[3]: %d\n\r", m_adc_value[0], - m_adc_value[1], m_adc_value[2], m_adc_value[3]); + 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& adcBuffer) { +void cWebInterface::UpdateTemp(cDoubleBuffer& i_tempBuffer) { } cWebInterface::~cWebInterface() { // TODO Auto-generated destructor stub } -void cWebInterface::OnConfiguration(HttpRequest &request, HttpResponse &response) -{ +void cWebInterface::ResetRawValues() { + for (int channel = 0; channel < 4; channel++) { + for (int sample = 0; sample < 1000; sample++) { + m_adc_values_raw[channel][sample] = 0; + } + } +} + +void cWebInterface::OnConfiguration(HttpRequest &request, HttpResponse &response) { - if (request.method == HTTP_POST) - { - debugf("Update config"); + if (strcmp(request.getRequestMethod().c_str(), RequestMethod::POST) == 0) { + //debugf("Update config"); // Update config - if (request.getBody() == NULL) - { + if (request.getBody() == NULL) { Serial.println(request.getPostParameter("StaSSID")); - debugf("NULL bodyBuf"); + //debugf("NULL bodyBuf"); return; - } - else - { + } else { StaticJsonBuffer<200> jsonBuffer; JsonObject& root = jsonBuffer.parseObject(request.getBody()); //root.prettyPrintTo(Serial); //Uncomment it for debuging /* if (root["StaSSID"].success()) // Settings - { - uint8_t PrevStaEnable = ActiveConfig.StaEnable; - - ActiveConfig.StaSSID = String((const char *)root["StaSSID"]); - ActiveConfig.StaPassword = String((const char *)root["StaPassword"]); - ActiveConfig.StaEnable = root["StaEnable"]; - - if (PrevStaEnable && ActiveConfig.StaEnable) - { - WifiStation.enable(true); - WifiAccessPoint.enable(false); - WifiStation.config(ActiveConfig.StaSSID, ActiveConfig.StaPassword); - } - else if (ActiveConfig.StaEnable) - { - WifiStation.enable(true, true); - WifiAccessPoint.enable(false, true); - WifiStation.config(ActiveConfig.StaSSID, ActiveConfig.StaPassword); - } - else - { - WifiStation.enable(false, true); - WifiAccessPoint.enable(true, true); - WifiAccessPoint.config("TyTherm", "ENTERYOURPASSWD", AUTH_WPA2_PSK); - } - }*/ + { + uint8_t PrevStaEnable = ActiveConfig.StaEnable; + + ActiveConfig.StaSSID = String((const char *)root["StaSSID"]); + ActiveConfig.StaPassword = String((const char *)root["StaPassword"]); + ActiveConfig.StaEnable = root["StaEnable"]; + + if (PrevStaEnable && ActiveConfig.StaEnable) + { + WifiStation.enable(true); + WifiAccessPoint.enable(false); + WifiStation.config(ActiveConfig.StaSSID, ActiveConfig.StaPassword); + } + else if (ActiveConfig.StaEnable) + { + WifiStation.enable(true, true); + WifiAccessPoint.enable(false, true); + WifiStation.config(ActiveConfig.StaSSID, ActiveConfig.StaPassword); + } + else + { + WifiStation.enable(false, true); + WifiAccessPoint.enable(true, true); + WifiAccessPoint.config("TyTherm", "ENTERYOURPASSWD", AUTH_WPA2_PSK); + } + }*/ } //saveConfig(ActiveConfig); - } - else - { + } else { response.setCache(86400, true); // It's important to use cache for better performance. response.sendFile("config.html"); } } -void cWebInterface::OnConfiguration_json(HttpRequest &request, HttpResponse &response) -{ +void cWebInterface::OnConfiguration_json(HttpRequest &request, HttpResponse &response) { JsonObjectStream* stream = new JsonObjectStream(); JsonObject& json = stream->getRoot(); @@ -194,9 +207,8 @@ void cWebInterface::OnConfiguration_json(HttpRequest &request, HttpResponse &res json["StaPassword"] = 23; json["StaEnable"] = 24; - response.sendDataStream(stream, MIME_JSON); + response.sendDataStream(stream, ContentType::JSON); } - } /* namespace rijnfel */ diff --git a/software/app/web_interface.h b/software/app/web_interface.h index 05f6169..6ec5db6 100644 --- a/software/app/web_interface.h +++ b/software/app/web_interface.h @@ -9,44 +9,119 @@ #define APP_WEB_INTERFACE_H_ #include "adc.h" +//TODO remove this #include "ads101x.h" +#include "dummy_adc.h" + #include "double_buffer.h" #include namespace rijnfel { - +#define RAW_CHANNEL 1 +#define RAW_SAMPLES 1000 class cWebInterface { public: - static cWebInterface *s_instance; + /** + * Returns the global cWebInterface instance. + * Only one webserver should ever be running + * @return global cWebInterface instance + */ static cWebInterface *GetInstance() { if (cWebInterface::s_instance == NULL) cWebInterface::s_instance = new cWebInterface(); return cWebInterface::s_instance; } + + /// Singleton instance + static cWebInterface *s_instance; + public: - cWebInterface(); - cWebInterface(cWebInterface const&) { - m_serverStarted = false; - } - cWebInterface& operator=(cWebInterface const&) { - } - void Start(); - void Stop(); - void UpdateAdc(cADC & adc, - cDoubleBuffer & adcBuffer); - void UpdateTemp(cDoubleBuffer & adcBuffer); + /** + * Should not be used because it's a singleton + * @param delete + */ + cWebInterface(cWebInterface const&) = delete; + + /** + * Should not be used because it's a singleton + * @param delete + * @return delete + */ + cWebInterface& operator=(cWebInterface const&) = delete; + + /** + * Registers the paths and starts the server + */ + void StartServer(); + + /** + * Stops the server + */ + 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 & i_adc, cDoubleBuffer & i_adcBuffer); + + /** + * Updates the temperature on the website + * @param i_tempBuffer buffer containing temperature values + */ + void UpdateTemp(cDoubleBuffer & i_tempBuffer); + + /** + * This is a debug function that prints out the average values + * @todo remove this + */ void PrintValues(); + + /** + * Destructor + */ virtual ~cWebInterface(); public: - void OnIndex(HttpRequest &request, HttpResponse &response); - void OnRefresh(HttpRequest &request, HttpResponse &response); - void OnConfiguration_json(HttpRequest &request, HttpResponse &response); + /** + * + * @param i_request + * @param i_response Response to the client, index.html + */ + void OnIndex(HttpRequest & i_request, HttpResponse & i_response); + + /** + * Function gets called from the mobile to refresh the average values + * @param i_request Request from the client + * @param i_response Response to the client, contains JSON with averages + */ + void OnRefresh(HttpRequest & i_request, HttpResponse & i_response); + + /** + * + * @param i_request + * @param i_response + */ + void OnRawUpdate(HttpRequest& i_request, HttpResponse& i_response); + void OnConfiguration_json(HttpRequest &request, HttpResponse &response); void OnConfiguration(HttpRequest &request, HttpResponse &response); +protected: + /** + * Initializes the variables + */ + cWebInterface(); private: + void ResetRawValues(); + /// Whether the server has started or not bool m_serverStarted; - int32_t m_adc_value[4]; - HttpServer server; + /// Holds the average for all the channels + int32_t m_adc_value_average[4]; + /// Server instance + HttpServer m_server; + char * m_jsonBuffer; + int32_t m_adc_values_raw[4][RAW_SAMPLES]; + int m_adc_values_raw_cnt[4]; }; } /* namespace rijnfel */ diff --git a/software/files/index.html b/software/files/index.html index 0000c43..f09d1fd 100644 --- a/software/files/index.html +++ b/software/files/index.html @@ -28,9 +28,27 @@

TyTherm

+ +
+

 

+
+
+
+
+

Raw samples

+ +
+
+ +
+
+
+
+
-

 

@@ -82,7 +100,7 @@
- +
diff --git a/software/files/index.js b/software/files/index.js index 718b426..14efed6 100644 --- a/software/files/index.js +++ b/software/files/index.js @@ -7,7 +7,10 @@ $( document ).ready(function() { document.getElementById('adc_3').textContent = data.adc_3; document.getElementById('adc_4').textContent = data.adc_4; - setTimeout(worker, 1000); + //var text = document.getElementById('raw_adc'); + //text.value += data.raw_adc; + + setTimeout(worker, 500); }); })(); });