From 7e9d726ccd53626251e56b92c8eec47772bfe0f9 Mon Sep 17 00:00:00 2001 From: Jeremy Tan Date: Wed, 23 Oct 2013 16:12:04 +0800 Subject: [PATCH] stuff --- server/actuator.c | 37 +++++++++--- server/actuator.h | 3 +- server/actuators/Makefile | 2 +- server/actuators/pregulator.c | 33 ++++++++++ server/actuators/pregulator.h | 11 ++++ server/actuators/relays.c | 48 +++++++++++++++ server/actuators/relays.h | 18 ++++++ server/bbb_pin.c | 3 +- server/fastcgi.c | 9 ++- server/filetest | 1 + server/main.c | 4 +- server/parameters | 5 +- server/sensor.c | 60 ++++++++++++------- server/sensor.h | 5 ++ server/sensors/pressure.c | 3 + server/sensors/strain.c | 29 ++++++++- server/sensors/strain.h | 3 + testing/MCTXWeb/public_html/control.html | 36 +++++++++-- .../public_html/static/mctx.control.js | 52 ++++++++++++---- .../MCTXWeb/public_html/static/mctx.graph.js | 6 +- testing/MCTXWeb/public_html/stream.html | 5 ++ 21 files changed, 310 insertions(+), 63 deletions(-) create mode 100644 server/actuators/pregulator.c create mode 100644 server/actuators/pregulator.h create mode 100644 server/actuators/relays.c create mode 100644 server/actuators/relays.h create mode 100644 server/filetest create mode 100644 testing/MCTXWeb/public_html/stream.html diff --git a/server/actuator.c b/server/actuator.c index 1c105db..617136e 100644 --- a/server/actuator.c +++ b/server/actuator.c @@ -35,7 +35,7 @@ int Actuator_Add(const char * name, int user_id, SetFn set, InitFn init, CleanFn a->init = init; // Set init function a->sanity = sanity; - + a->cleanup = cleanup; pthread_mutex_init(&(a->mutex), NULL); if (init != NULL) @@ -51,16 +51,35 @@ int Actuator_Add(const char * name, int user_id, SetFn set, InitFn init, CleanFn /** - * One off initialisation of *all* Actuators + * Initialisation of *all* Actuators */ -#include "actuators/ledtest.h" -#include "actuators/filetest.h" +#include "actuators/pregulator.h" +#include "actuators/relays.h" void Actuator_Init() { //Actuator_Add("ledtest",0, Ledtest_Set, NULL,NULL,NULL); - Actuator_Add("filetest", 0, Filetest_Set, Filetest_Init, Filetest_Cleanup, Filetest_Sanity, 0); + //Actuator_Add("filetest", 0, Filetest_Set, Filetest_Init, Filetest_Cleanup, Filetest_Sanity, 0); + Actuator_Add("pregulator", 0, Pregulator_Set, Pregulator_Init, Pregulator_Cleanup, Pregulator_Sanity, 0); + Actuator_Add("can_select", RELAY_CANSELECT, Relay_Set, Relay_Init, Relay_Cleanup, Relay_Sanity, 0); + Actuator_Add("can_enable", RELAY_CANENABLE, Relay_Set, Relay_Init, Relay_Cleanup, Relay_Sanity, 0); + Actuator_Add("main_pressure", RELAY_MAIN, Relay_Set, Relay_Init, Relay_Cleanup, Relay_Sanity, 1); +} + +/** + * Deinitialise actuators + */ +void Actuator_Cleanup() +{ + for (int i = 0; i < g_num_actuators; ++i) + { + Actuator * a = g_actuators+i; + if (a->cleanup != NULL) + a->cleanup(a->user_id); + } + g_num_actuators = 0; } + /** * Sets the actuator to the desired mode. No checks are * done to see if setting to the desired mode will conflict with @@ -143,8 +162,12 @@ void Actuator_SetMode(Actuator * a, ControlModes mode, void *arg) */ void Actuator_SetModeAll(ControlModes mode, void * arg) { + if (mode == CONTROL_START) + Actuator_Init(); for (int i = 0; i < g_num_actuators; i++) Actuator_SetMode(&g_actuators[i], mode, arg); + if (mode == CONTROL_STOP) + Actuator_Cleanup(); } /** @@ -173,7 +196,7 @@ void * Actuator_Loop(void * arg) // Currently does discrete steps after specified time intervals struct timespec wait; - DOUBLE_TO_TIMEVAL(a->control.stepsize, &wait); + DOUBLE_TO_TIMEVAL(a->control.stepwait, &wait); while (!a->control_changed && a->control.steps > 0 && a->activated) { clock_nanosleep(CLOCK_MONOTONIC, 0, &wait, NULL); @@ -381,7 +404,7 @@ void Actuator_Handler(FCGIContext * context, char * params) ActuatorControl c = {0.0, 0.0, 0.0, 0}; // Need to set default values (since we don't require them all) // sscanf returns the number of fields successfully read... - int n = sscanf(set, "%lf,%lf,%lf,%d", &(c.start), &(c.stepwait), &(c.stepsize), &(c.steps)); // Set provided values in order + int n = sscanf(set, "%lf_%lf_%lf_%d", &(c.start), &(c.stepwait), &(c.stepsize), &(c.steps)); // Set provided values in order if (n != 4) { // If the user doesn't provide all 4 values, the Actuator will get set *once* using the first of the provided values diff --git a/server/actuator.h b/server/actuator.h index f818526..a5ac75b 100644 --- a/server/actuator.h +++ b/server/actuator.h @@ -67,13 +67,14 @@ typedef struct /** Sanity check function **/ SanityFn sanity; /** Cleanup function **/ - CleanFn clean; + CleanFn cleanup; /** Last setting **/ DataPoint last_setting; } Actuator; extern void Actuator_Init(); // One off initialisation of *all* Actuators +extern void Actuator_Cleanup(); extern void Actuator_SetModeAll(ControlModes mode, void *arg); extern void Actuator_SetMode(Actuator * a, ControlModes mode, void *arg); diff --git a/server/actuators/Makefile b/server/actuators/Makefile index a2ba5dc..dfc247c 100644 --- a/server/actuators/Makefile +++ b/server/actuators/Makefile @@ -3,7 +3,7 @@ CXX = gcc FLAGS = -std=c99 -Wall -pedantic -g -I../ #-I/usr/include/opencv -I/usr/include/opencv2/highgui For OpenCV LIB = -lpthread -OBJ = ledtest.o filetest.o +OBJ = relays.o pregulator.o HEADERS = $(wildcard *.h) RM = rm -f diff --git a/server/actuators/pregulator.c b/server/actuators/pregulator.c new file mode 100644 index 0000000..3740729 --- /dev/null +++ b/server/actuators/pregulator.c @@ -0,0 +1,33 @@ +#include "pregulator.h" +#include "../bbb_pin.h" + +#define PREGULATOR_PWM ECAP0 +#define PREGULATOR_PERIOD 500000 +//16666667 + +/** + * Initiliase the pressure regulator + */ +bool Pregulator_Init(const char * name, int id) +{ + return PWM_Export(PREGULATOR_PWM) && PWM_Set(PREGULATOR_PWM, false, PREGULATOR_PERIOD, 0); +} + +bool Pregulator_Cleanup(int id) +{ + if (!PWM_Set(PREGULATOR_PWM, false, PREGULATOR_PERIOD, 0)) + return false; + PWM_Unexport(PREGULATOR_PWM); + return true; +} + +bool Pregulator_Set(int id, double value) +{ + return PWM_Set(PREGULATOR_PWM, false, PREGULATOR_PERIOD, value*(PREGULATOR_PERIOD)); +} + +bool Pregulator_Sanity(int id, double value) +{ + return (value >= 0.0 && value <= 1.0); +} + diff --git a/server/actuators/pregulator.h b/server/actuators/pregulator.h new file mode 100644 index 0000000..c721140 --- /dev/null +++ b/server/actuators/pregulator.h @@ -0,0 +1,11 @@ +#ifndef _PREGULATOR + +#include "../common.h" + +extern bool Pregulator_Init(const char * name, int id); +extern bool Pregulator_Cleanup(int id); +extern bool Pregulator_Set(int id, double value); +extern bool Pregulator_Sanity(int id, double value); + + +#endif //_PREGULATOR diff --git a/server/actuators/relays.c b/server/actuators/relays.c new file mode 100644 index 0000000..dfa3d74 --- /dev/null +++ b/server/actuators/relays.c @@ -0,0 +1,48 @@ +#include "relays.h" +#include "../log.h" + +#include "../bbb_pin.h" + + +static int GetGPIO(int id) +{ + switch (id) + { + case RELAY_CANSELECT: + return 14; + case RELAY_CANENABLE: + return 115; + case RELAY_MAIN: + return 112; + } + Fatal("Unknown id %d", id); + return 0; +} + +bool Relay_Init(const char * name, int id) +{ + if (!GPIO_Export(GetGPIO(id))) + return false; + return GPIO_Set(GetGPIO(id), false); +} + +bool Relay_Cleanup(int id) +{ + bool err = GPIO_Set(GetGPIO(id), false); + GPIO_Unexport(GetGPIO(id)); + return err; +} + +bool Relay_Set(int id, double value) +{ + bool set = (bool)value; + return GPIO_Set(GetGPIO(id), set); +} + +bool Relay_Sanity(int id, double value) +{ + //bool set = (bool)value; + //TODO: Make a more sane sanity check + return true; + +} diff --git a/server/actuators/relays.h b/server/actuators/relays.h new file mode 100644 index 0000000..dcffbf9 --- /dev/null +++ b/server/actuators/relays.h @@ -0,0 +1,18 @@ +#ifndef _RELAY_H +#define _RELAY_H + +#include "../common.h" + +typedef enum +{ + RELAY_CANSELECT, + RELAY_CANENABLE, + RELAY_MAIN +} RelayID; + +extern bool Relay_Init(const char * name, int id); +extern bool Relay_Set(int id, double value); +extern bool Relay_Sanity(int id, double value); +extern bool Relay_Cleanup(int id); + +#endif //_RELAY_H diff --git a/server/bbb_pin.c b/server/bbb_pin.c index 2ffc9e5..bd31365 100644 --- a/server/bbb_pin.c +++ b/server/bbb_pin.c @@ -501,7 +501,8 @@ bool ADC_Read(int id, int *value) if (pread(g_adc[id].fd_value, adc_str, ADC_DIGITS-1, 0) == -1) { - AbortBool("ADC %d read failed: %s", id, strerror(errno)); + //AbortBool("ADC %d read failed: %s", id, strerror(errno)); + return false; } *value = strtol(adc_str, NULL, 10); diff --git a/server/fastcgi.c b/server/fastcgi.c index 525e964..75863c1 100644 --- a/server/fastcgi.c +++ b/server/fastcgi.c @@ -64,7 +64,9 @@ static void IdentifyHandler(FCGIContext *context, char *params) if (i > 0) { FCGI_JSONValue(",\n\t\t"); } - FCGI_JSONValue("\"%d\" : \"%s\"", i, Sensor_GetName(i)); + DataPoint d = Sensor_LastData(i); + FCGI_JSONValue("\"%d\" : {\"name\" : \"%s\", \"value\" : [%f,%f] }", + i, Sensor_GetName(i), d.time_stamp, d.value); } FCGI_JSONValue("\n\t}"); } @@ -75,7 +77,9 @@ static void IdentifyHandler(FCGIContext *context, char *params) if (i > 0) { FCGI_JSONValue(",\n\t\t"); } - FCGI_JSONValue("\"%d\" : \"%s\"", i, Actuator_GetName(i)); + + DataPoint d = Sensor_LastData(i); + FCGI_JSONValue("\"%d\" : {\"name\" : \"%s\", \"value\" : [%f, %f] }", i, Actuator_GetName(i), d.time_stamp, d.value); } FCGI_JSONValue("\n\t}"); } @@ -599,6 +603,7 @@ void * FCGI_RequestLoop (void *data) { //:( Log(LOGWARN, "Locking control (no auth!)"); FCGI_LockControl(&context, NOAUTH_USERNAME, USER_ADMIN); + FCGI_SendControlCookie(&context, true); } else { diff --git a/server/filetest b/server/filetest new file mode 100644 index 0000000..945da8f --- /dev/null +++ b/server/filetest @@ -0,0 +1 @@ +0.000000 diff --git a/server/main.c b/server/main.c index 5b8e09c..a4b7c5a 100644 --- a/server/main.c +++ b/server/main.c @@ -123,7 +123,7 @@ void Cleanup() { Log(LOGDEBUG, "Begin cleanup."); Sensor_Cleanup(); - //Actuator_Cleanup(); + Actuator_Cleanup(); Log(LOGDEBUG, "Finish cleanup."); } @@ -199,8 +199,6 @@ int main(int argc, char ** argv) - Sensor_Init(); - Actuator_Init(); Pin_Init(); // Try and start things diff --git a/server/parameters b/server/parameters index da48239..26e2892 100644 --- a/server/parameters +++ b/server/parameters @@ -23,7 +23,7 @@ pin_test="0" #auth_uri="ldap://192.168.1.1" #auth_uri="ldaps://ldap.pheme.uwa.edu.au" #UWA #auth_uri="/etc/shadow" -auth_uri="shadow" +#auth_uri="shadow" # Set to the dn of the LDAP server ldap_base_dn="ou=People,dc=daedalus" # Testing @@ -31,4 +31,5 @@ ldap_base_dn="ou=People,dc=daedalus" # Testing ## OPTIONS TO BE PASSED TO SERVER; DO NOT EDIT -parameters="-v $verbosity -p $pin_test -A $auth_uri -d $ldap_base_dn" +parameters="-v $verbosity -p $pin_test" +# -A $auth_uri -d $ldap_base_dn" diff --git a/server/sensor.c b/server/sensor.c index ae5cdf4..d146905 100644 --- a/server/sensor.c +++ b/server/sensor.c @@ -47,7 +47,7 @@ int Sensor_Add(const char * name, int user_id, ReadFn read, InitFn init, CleanFn s->init = init; // Set init function // Start by averaging values taken over a second - DOUBLE_TO_TIMEVAL(1e-4, &(s->sample_time)); + DOUBLE_TO_TIMEVAL(1e-3, &(s->sample_time)); s->averages = 1; s->num_read = 0; @@ -62,6 +62,8 @@ int Sensor_Add(const char * name, int user_id, ReadFn read, InitFn init, CleanFn s->current_data.time_stamp = 0; s->current_data.value = 0; + s->averaged_data.time_stamp = 0; + s->averaged_data.value = 0; return g_num_sensors; } @@ -75,16 +77,16 @@ int Sensor_Add(const char * name, int user_id, ReadFn read, InitFn init, CleanFn #include "sensors/pressure.h" void Sensor_Init() { - Sensor_Add("cpu_stime", RESOURCE_CPU_SYS, Resource_Read, NULL, NULL, NULL); - Sensor_Add("cpu_utime", RESOURCE_CPU_USER, Resource_Read, NULL, NULL, NULL); - //Sensor_Add("pressure_high0", PRES_HIGH0, Pressure_Read, Pressure_Init, Pressure_Cleanup, NULL); - //Sensor_Add("pressure_high1", PRES_HIGH1, Pressure_Read, Pressure_Init, Pressure_Cleanup, NULL); - //Sensor_Add("pressure_low0", PRES_LOW0, Pressure_Read, Pressure_Init, Pressure_Cleanup, NULL); + //Sensor_Add("cpu_stime", RESOURCE_CPU_SYS, Resource_Read, NULL, NULL, NULL); + //Sensor_Add("cpu_utime", RESOURCE_CPU_USER, Resource_Read, NULL, NULL, NULL); + Sensor_Add("pressure_high0", PRES_HIGH0, Pressure_Read, Pressure_Init, Pressure_Cleanup, NULL); + Sensor_Add("pressure_high1", PRES_HIGH1, Pressure_Read, Pressure_Init, Pressure_Cleanup, NULL); + Sensor_Add("pressure_low0", PRES_LOW0, Pressure_Read, Pressure_Init, Pressure_Cleanup, NULL); //Sensor_Add("../testing/count.py", 0, Piped_Read, Piped_Init, Piped_Cleanup, 1e50,-1e50,1e50,-1e50); - //Sensor_Add("strain0", STRAIN0, Strain_Read, Strain_Init, 5000,0,5000,0); - //Sensor_Add("strain1", STRAIN1, Strain_Read, Strain_Init, 5000,0,5000,0); - //Sensor_Add("strain2", STRAIN2, Strain_Read, Strain_Init, 5000,0,5000,0); - //Sensor_Add("strain3", STRAIN3, Strain_Read, Strain_Init, 5000,0,5000,0); + Sensor_Add("strain0", STRAIN0, Strain_Read, Strain_Init, Strain_Cleanup, Strain_Sanity); + Sensor_Add("strain1", STRAIN1, Strain_Read, Strain_Init, Strain_Cleanup, Strain_Sanity); + Sensor_Add("strain2", STRAIN2, Strain_Read, Strain_Init, Strain_Cleanup, Strain_Sanity); + Sensor_Add("strain3", STRAIN3, Strain_Read, Strain_Init, Strain_Cleanup, Strain_Sanity); //Sensor_Add("pressure0", PRESSURE0, Pressure_Read, Pressure_Init, 5000,0,5000,0); //Sensor_Add("pressure1", PRESSURE1, Pressure_Read, Pressure_Init, 5000,0,5000,0); //Sensor_Add("pressure_feedback", PRESSURE_FEEDBACK, Pressure_Read, Pressure_Init, 5000,0,5000,0); @@ -103,6 +105,7 @@ void Sensor_Cleanup() if (s->cleanup != NULL) s->cleanup(s->user_id); } + g_num_sensors = 0; } /** @@ -183,8 +186,12 @@ void Sensor_SetMode(Sensor * s, ControlModes mode, void * arg) */ void Sensor_SetModeAll(ControlModes mode, void * arg) { + if (mode == CONTROL_START) + Sensor_Init(); for (int i = 0; i < g_num_sensors; i++) Sensor_SetMode(&g_sensors[i], mode, arg); + if (mode == CONTROL_STOP) + Sensor_Cleanup(); } @@ -201,38 +208,40 @@ void * Sensor_Loop(void * arg) // Until the sensor is stopped, record data points while (s->activated) { - DataPoint d; - d.value = 0; - bool success = s->read(s->user_id, &(d.value)); + + bool success = s->read(s->user_id, &(s->current_data.value)); struct timespec t; clock_gettime(CLOCK_MONOTONIC, &t); - d.time_stamp = TIMEVAL_DIFF(t, *Control_GetStartTime()); + s->current_data.time_stamp = TIMEVAL_DIFF(t, *Control_GetStartTime()); if (success) { if (s->sanity != NULL) { - if (!s->sanity(s->user_id, d.value)) + if (!s->sanity(s->user_id, s->current_data.value)) { Fatal("Sensor %s (%d,%d) reads unsafe value", s->name, s->id, s->user_id); } } - s->current_data.time_stamp += d.time_stamp; - s->current_data.value += d.value; + s->averaged_data.time_stamp += s->current_data.time_stamp; + s->averaged_data.value = s->current_data.value; if (++(s->num_read) >= s->averages) { - s->current_data.time_stamp /= s->averages; - s->current_data.value /= s->averages; - Data_Save(&(s->data_file), &(s->current_data), 1); // Record it + s->averaged_data.time_stamp /= s->averages; + s->averaged_data.value /= s->averages; + Data_Save(&(s->data_file), &(s->averaged_data), 1); // Record it s->num_read = 0; - s->current_data.time_stamp = 0; - s->current_data.value = 0; + s->averaged_data.time_stamp = 0; + s->averaged_data.value = 0; } } else - Log(LOGWARN, "Failed to read sensor %s (%d,%d)", s->name, s->id,s->user_id); + { + // Silence because strain sensors fail ~50% of the time :S + //Log(LOGWARN, "Failed to read sensor %s (%d,%d)", s->name, s->id,s->user_id); + } clock_nanosleep(CLOCK_MONOTONIC, 0, &(s->sample_time), NULL); @@ -408,5 +417,10 @@ const char * Sensor_GetName(int id) return g_sensors[id].name; } +DataPoint Sensor_LastData(int id) +{ + Sensor * s = &(g_sensors[id]); + return s->current_data; +} diff --git a/server/sensor.h b/server/sensor.h index 0188361..3de48e0 100644 --- a/server/sensor.h +++ b/server/sensor.h @@ -61,6 +61,9 @@ typedef struct int averages; /** Current data **/ DataPoint current_data; + + /** Summed data **/ + DataPoint averaged_data; /** Number of points read so far before applying average **/ int num_read; @@ -82,6 +85,8 @@ extern Sensor * Sensor_Identify(const char * str); // Identify a Sensor from a s extern void Sensor_Handler(FCGIContext *context, char * params); // Handle a FCGI request for Sensor data +extern DataPoint Sensor_LastData(int id); + extern const char * Sensor_GetName(int id); diff --git a/server/sensors/pressure.c b/server/sensors/pressure.c index 61cdbcf..29b8d28 100644 --- a/server/sensors/pressure.c +++ b/server/sensors/pressure.c @@ -40,6 +40,9 @@ double Pressure_Callibrate(int id, int adc) { //double voltage = ADC_TO_VOLTS(adc); // convert reading to voltage + return (double)adc; + + //TODO: Fix this switch (id) { case PRES_HIGH0: diff --git a/server/sensors/strain.c b/server/sensors/strain.c index 9492de7..77a11a2 100644 --- a/server/sensors/strain.c +++ b/server/sensors/strain.c @@ -6,6 +6,8 @@ #include #define STRAIN_ADC ADC0 +// TODO: Choose this +#define STRAIN_GPIO 15 /** * Convert Strain gauge id number to a GPIO pin on the Mux @@ -59,15 +61,36 @@ bool Strain_Init(const char * name, int id) if (!GPIO_Set(gpio_num, false)) Fatal("Couldn't set GPIO%d for strain sensor %d to LOW", gpio_num, id); - static bool init_adc = false; - if (!init_adc) + static int init = 0; + if (++init == 1) { - init_adc = true; + GPIO_Export(STRAIN_GPIO); + GPIO_Set(STRAIN_GPIO, true); ADC_Export(STRAIN_ADC); } return true; } +bool Strain_Cleanup(int id) +{ + static int killed = 0; + if (++killed == 4) + { + + GPIO_Set(STRAIN_GPIO, false); + ADC_Unexport(STRAIN_ADC); + } + + int gpio_num = Strain_To_GPIO(id); + GPIO_Unexport(gpio_num); + return true; +} + +bool Strain_Sanity(int id, double value) +{ + return true; +} + /** * Read from a Strain gauge * @param id - The strain gauge to read diff --git a/server/sensors/strain.h b/server/sensors/strain.h index 1afb625..21b926e 100644 --- a/server/sensors/strain.h +++ b/server/sensors/strain.h @@ -19,4 +19,7 @@ extern bool Strain_Init(const char * name, int id); // Read from a strain gauge extern bool Strain_Read(int id, double * value); +extern bool Strain_Cleanup(int id); +extern bool Strain_Sanity(int id, double value); + #endif //_STRAIN_H diff --git a/testing/MCTXWeb/public_html/control.html b/testing/MCTXWeb/public_html/control.html index 412f7f8..5d22e90 100644 --- a/testing/MCTXWeb/public_html/control.html +++ b/testing/MCTXWeb/public_html/control.html @@ -18,13 +18,13 @@ $(document).ready(function () { $("form").submit(function () { //Prevent form submit globally return false; - }) + }); //Set the status updated $("#state-exp").setStatusUpdater(); //Set the logic for the start controls - $("#start-controls").submit(function () { + $("#start-controls input[type='button']").click(function () { var start = $("#start-controls input[type='button']"); var force = $("#start-controls input[name='start_force']"); @@ -49,8 +49,28 @@ $(this).setPressure(pressure, $("#pressure-result")); }); - //Set logic for sensor sample rate thing - $("#sensor-select").loadSensorList($("#samplerate-result")); + $("#pressure-controls input[name='clear']").click(function () { + $("#pressure-set")[0].reset(); + }); + + $("#pressure-controls input[name='zero']").click(function () { + $("#pressure-controls input[name='clear']").click(); + $("#pressure-set").val("0"); + + $("#pressure-controls").submit(); + }); + + $("#pressure-controls input[name='step-it']").click(function () { + var pressure = { + set : $("#pressure-set").val(), step : "", wait : "", count : "" + }; + + $(this).setPressure(pressure, $("#pressure-result")).done(function () { + var next = Number($("#pressure-set").val()) + Number($("#pressure-stepsize").val()); + $("#pressure-set").val(next.toString()); + }); + + }); $("#samplerate-controls").submit(function () { setSampleRate($("#sensor-select option:selected").val(), $("#sensor-set").val(), $("#samplerate-result")); @@ -157,8 +177,9 @@  

- - + + +

@@ -187,6 +208,9 @@  

+ + +

diff --git a/testing/MCTXWeb/public_html/static/mctx.control.js b/testing/MCTXWeb/public_html/static/mctx.control.js index 1d5c744..d3b5348 100644 --- a/testing/MCTXWeb/public_html/static/mctx.control.js +++ b/testing/MCTXWeb/public_html/static/mctx.control.js @@ -47,6 +47,7 @@ function setSampleRate(id, val, result) { $.fn.loadSensorList = function (result, input) { var select = this; + select.empty(); //Reset list $.ajax({ url : mctx.api + 'identify', @@ -56,7 +57,7 @@ $.fn.loadSensorList = function (result, input) { return; } for (var id in data.sensors) { - var option = $("