Qubit 2020 / presensfirmwareupdate

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers wifi_events.cpp Source File

wifi_events.cpp

00001 #include "cisme.h"
00002 #include "wifi_events.h"
00003 #include "wifi.h"
00004 #include "debug.h"
00005 #include "pb_encode.h"
00006 #include "pb_decode.h"
00007 #include "messages.pb.h"
00008 #include "light.h"
00009 #include "pump.h"
00010 #include "presens.h"
00011 #include "calibration.h"
00012 #include "experiments.h"
00013 #include "battery.h"
00014 
00015 #ifdef USE_WIFI
00016 
00017 #define FILE_BLOCK_SIZE 128
00018 
00019 // Struct to encode payload in generic message
00020 typedef struct {
00021     const pb_field_t* fields;
00022     void* msg;
00023 } PbEncodeMessage;
00024 
00025 // Struct to get payload from generic message
00026 typedef struct {
00027     uint8_t* msg;
00028     size_t msgLen;
00029 } PbDecodeMessage;
00030 
00031 typedef bool (*Encoder)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg);
00032 
00033 char startErrors = 0;
00034 
00035 // Files data
00036 static int32_t fileId;
00037 static int32_t blockId;
00038 static FILE* curFile;
00039 static uint32_t fileLen;
00040 static int32_t numBlocks;
00041 
00042 // Experiments data
00043 static int  currentExpId;
00044 static bool isExpExecuting;
00045 
00046 static LocalFileSystem local("local");
00047 
00048 static void wifiEventsSendFinishExpInd(int32_t id, char* fileName);
00049 
00050 static int getNoSetBits(int value)
00051 {
00052     int result = 0;
00053 
00054     while (value != 0) {
00055         value &= (value - 1);
00056         result++;
00057     }
00058 
00059     return result;
00060 }
00061 
00062 static bool pbEncodeMsg(pb_ostream_t* stream, const pb_field_t* field, void* const* arg)
00063 {
00064     if (!pb_encode_tag_for_field(stream, field)) {
00065         return false;
00066     }
00067 
00068     if (*arg == NULL) {
00069         pb_encode_varint(stream, 0);
00070         return true;
00071     }
00072 
00073     PbEncodeMessage* message = (PbEncodeMessage*)*arg;
00074 
00075     if (!pb_encode_submessage(stream, message->fields, message->msg)) {
00076         return false;
00077     }
00078 
00079     return true;
00080 }
00081 
00082 static bool pbDecodeMsg(pb_istream_t* stream, const pb_field_t* field, void** arg)
00083 {
00084     uint8_t* src = (uint8_t*)stream->state;
00085 
00086     PbDecodeMessage* message = (PbDecodeMessage*)*arg;
00087     message->msg = (uint8_t*)stream->state;
00088     message->msgLen = stream->bytes_left;
00089     stream->bytes_left = 0;
00090     stream->state = src + message->msgLen;
00091 
00092     return true;
00093 }
00094 
00095 static bool pbEncodeString(pb_ostream_t* stream, const pb_field_t* field, void* const* arg)
00096 {
00097     char* str = (char*)*arg;
00098 
00099     if (!pb_encode_tag_for_field(stream, field)) {
00100         return false;
00101     }
00102 
00103     if (!pb_encode_string(stream, (uint8_t*)str, strlen(str))) {
00104         return false;
00105     }
00106 
00107     return true;
00108 }
00109 
00110 static bool pbEncodeErrors(pb_ostream_t* stream, const pb_field_t* field, void* const* arg)
00111 {
00112     static const char* errorsText[4] = {"Low battery level. Device will be disabled soon.",
00113                                         "Zero pump RPM. Please, check RPM wire.",
00114                                         "Failed to read isfet.sys file.",
00115                                         "Failed to read dsparams.sys file."
00116                                        };
00117     int  errorNo   = 0;
00118     char errorList = **((char**)arg);
00119 
00120     while ((1 << errorNo) <= errorList) {
00121         if ((errorList & (1 << errorNo)) == 0) {
00122             errorNo++;
00123             continue;
00124         }
00125 
00126         pbEncodeString(stream, field, (void**)&(errorsText[errorNo]));
00127         errorNo++;
00128     }
00129 
00130     return true;
00131 }
00132 
00133 static bool pbEncodeFiles(pb_ostream_t* stream, const pb_field_t* field, void* const* arg)
00134 {
00135     DIR* dir = opendir("/msc/data/");
00136     struct dirent* entry = NULL;
00137 
00138     while ((entry = readdir(dir)) != NULL) {
00139         if (strstr(entry->d_name, ".csv") == NULL) {
00140             continue;
00141         }
00142 
00143         if (!pb_encode_tag_for_field(stream, field)) {
00144             return false;
00145         }
00146 
00147         if (!pb_encode_string(stream, (uint8_t*)entry->d_name, strlen(entry->d_name))) {
00148             return false;
00149         }
00150     }
00151 
00152     return true;
00153 }
00154 
00155 static bool pbEncodeFileBlock(pb_ostream_t* stream, const pb_field_t* field, void* const* arg)
00156 {
00157     if (!pb_encode_tag_for_field(stream, field)) {
00158         return false;
00159     }
00160 
00161     uint64_t size = (blockId < numBlocks) ? FILE_BLOCK_SIZE : (fileLen % FILE_BLOCK_SIZE);
00162 
00163     if (!pb_encode_varint(stream, size)) {
00164         return false;
00165     }
00166 
00167     if (stream->callback != NULL) {
00168         size_t result = fread(stream->state, 1, size, curFile);
00169         if (result != size) {
00170             return false;
00171         }
00172 
00173         uint8_t* src = (uint8_t*)stream->state;
00174         stream->state = src + size;
00175     }
00176 
00177     stream->bytes_written += size;
00178 
00179     return true;
00180 }
00181 
00182 static bool pbDecodeString(pb_istream_t* stream, const pb_field_t* field, void** arg)
00183 {
00184     char* str = (char*)*arg;
00185     size_t len = stream->bytes_left;
00186 
00187     if (!pb_read(stream, (uint8_t*)str, len)) {
00188         return false;
00189     }
00190 
00191     str[len] = '\0';
00192 
00193     return true;
00194 }
00195 
00196 static bool pbDecodeProgramSteps(pb_istream_t* stream, const pb_field_t* field, void** arg)
00197 {
00198     uint8_t* stepIx = (uint8_t*)*arg;
00199 
00200     cisme_startExperimentMsg_Step stepMsg = cisme_startExperimentMsg_Step_init_default;
00201 
00202     if (!pb_decode(stream, cisme_startExperimentMsg_Step_fields, &stepMsg)) {
00203         return false;
00204     }
00205 
00206     if (!stepMsg.has_duration) {
00207         return false;
00208     }
00209 
00210     DEBUG1("Program step: lightLevel=%d, duration=%d, phCutoff=%2.3f, o2Cutoff=%3.0f",
00211            stepMsg.lightLevel, stepMsg.duration, stepMsg.phCutoff, stepMsg.o2Cutoff);
00212 
00213     pgm[*stepIx][1] = stepMsg.lightLevel;
00214     pgm[*stepIx][2] = stepMsg.duration;
00215     pgm[*stepIx][3] = stepMsg.phCutoff;
00216     pgm[*stepIx][4] = stepMsg.o2Cutoff;
00217     if (stepMsg.has_pumpSpeed) {
00218         pgm[*stepIx][0] = stepMsg.pumpSpeed;
00219     }
00220 
00221     (*stepIx)++;
00222     return true;
00223 }
00224 
00225 // Encode and send message to app
00226 static void wifiEventsSendMsg(cisme_MessageType type, const pb_field_t* fields, void* msg)
00227 {
00228     static uint8_t msgBuffer[WIFI_MESSAGE_MAX_LENGTH];
00229 
00230     cisme_genericMsg genericMsg = cisme_genericMsg_init_default;
00231     genericMsg.type = type;
00232     genericMsg.payload.funcs.encode = &pbEncodeMsg;
00233     pb_ostream_t stream = pb_ostream_from_buffer(msgBuffer, WIFI_MESSAGE_MAX_LENGTH);
00234 
00235     if (fields != NULL && msg != NULL) {
00236         PbEncodeMessage message = {fields, msg};
00237         genericMsg.payload.arg = &message;
00238     }
00239 
00240     if (!pb_encode(&stream, cisme_genericMsg_fields, &genericMsg)) {
00241         ERROR("Failed to encode message");
00242         return;
00243     }
00244 
00245     if (debugGetCurrLvl() >= DEBUG_LEVEL_2) {
00246         DEBUG2("Start of message----------------------------------------------");
00247         for (int sendByteIt= 0; sendByteIt < stream.bytes_written; sendByteIt++) {
00248             DEBUG2("Byte %d=%d", sendByteIt, msgBuffer[sendByteIt]);
00249         }
00250         DEBUG2("End of message----------------------------------------------");
00251     }
00252 
00253     wifiSendMessage(msgBuffer, stream.bytes_written);
00254 
00255     wait(WIFI_COMM_TIME / 1000.0);
00256 }
00257 
00258 // Collect data and send heartbeat message
00259 static void wifiEventsSendBeatInd(void)
00260 {
00261     if (isExpExecuting) {
00262         return;
00263     }
00264 
00265     cisme_beatDataMsg beatMsg = cisme_beatDataMsg_init_default;
00266     beatMsg.has_battery = true;
00267     beatMsg.has_temperature = true;
00268     beatMsg.has_ph = true;
00269     beatMsg.has_o2 = true;
00270     beatMsg.has_lightLevel = true;
00271     beatMsg.has_pumpRpm = true;
00272 
00273     beatMsg.battery = batteryGet();
00274 
00275     float presensData[PRESENS_RES_LENGTH];
00276     presensGetData(presensData);
00277     beatMsg.temperature = PHTEMP;
00278     beatMsg.ph = pHCorrected;
00279     beatMsg.o2 = presensData[2];
00280     beatMsg.lightLevel = lightRead();
00281     beatMsg.pumpRpm = pumpSpeed();
00282 
00283     DEBUG1("Send BEAT_DATA_IND: battery=%3.1f, temperature=%2.1f, ph=%3.2f, o2=%3.0f, lightLevel=%d, pumpRpm=%d",
00284            beatMsg.battery, beatMsg.temperature, beatMsg.ph, beatMsg.o2, beatMsg.lightLevel, beatMsg.pumpRpm);
00285     wifiEventsSendMsg(cisme_MessageType_BEAT_DATA_IND, cisme_beatDataMsg_fields, &beatMsg);
00286 }
00287 
00288 // Send instrument identifier to app
00289 static void wifiEventsHandleIdReq(void)
00290 {
00291     DEBUG1("Receive INSTRUMENT_ID_REQ");
00292 
00293     cisme_instrumentIdMsg idRsp = cisme_instrumentIdMsg_init_default;
00294     idRsp.id.funcs.encode = &pbEncodeString;
00295     idRsp.id.arg = instrumentId;
00296 
00297     DIR* dir = opendir("/local");
00298     struct dirent* entry = NULL;
00299     while ((entry = readdir(dir)) != NULL) {
00300         DEBUG1("binary=%s", entry->d_name);
00301         if (strstr(entry->d_name, ".BIN") == NULL) {
00302             continue;
00303         }
00304 
00305         idRsp.binary.funcs.encode = &pbEncodeString;
00306         idRsp.binary.arg = entry->d_name;
00307         break;
00308     }
00309 
00310 
00311     static char buildTime[sizeof(__DATE__) + sizeof(__TIME__) + 1];
00312     sprintf(buildTime, "%s %s", __DATE__, __TIME__);
00313     idRsp.timestamp.funcs.encode = &pbEncodeString;
00314     idRsp.timestamp.arg = buildTime;
00315 
00316     char* name = entry->d_name;
00317     DEBUG1("Send INSTRUMENT_ID_RSP: id=%s, binary=%s, timestamp=%s", instrumentId, name, buildTime);
00318 
00319     wifiEventsSendMsg(cisme_MessageType_INSTRUMENT_ID_RSP, cisme_instrumentIdMsg_fields, &idRsp);
00320     closedir(dir);
00321 }
00322 
00323 // Handle time synchronization
00324 static void wifiEventsHandleTimeRsp(uint8_t* msg, size_t msgLen)
00325 {
00326     if (msg == NULL || msgLen == 0) {
00327         ERROR("Empty GET_TIME_RSP");
00328         return;
00329     }
00330 
00331     cisme_timeMsg timeMsg = cisme_timeMsg_init_default;
00332     pb_istream_t stream = pb_istream_from_buffer(msg, msgLen);
00333 
00334     if (!pb_decode(&stream, cisme_timeMsg_fields, &timeMsg)) {
00335         ERROR("Can't decode received message");
00336         return;
00337     }
00338 
00339     if (!timeMsg.has_time) {
00340         ERROR("Missing time field in GET_TIME_RSP");
00341         return;
00342     }
00343 
00344     DEBUG1("Receive GET_TIME_RSP: time=%d", timeMsg.time);
00345 
00346     INFO("Set time to %s", ctime((time_t*)&timeMsg.time));
00347     set_time(timeMsg.time);
00348 }
00349 
00350 // Fill pump speed message and send to app
00351 static void wifiEventsSendPumpRsp(cisme_MessageType type)
00352 {
00353     cisme_pumpSpeedMsg speedMsg = cisme_pumpSpeedMsg_init_default;
00354     speedMsg.has_speed = true;
00355     speedMsg.speed = pumpCurrentIntensity();
00356 
00357     DEBUG1("Send %s: speed=%d", (type == cisme_MessageType_SET_PUMP_RSP) ? "SET_PUMP_RSP" : "GET_PUMP_RSP", speedMsg.speed);
00358     wifiEventsSendMsg(type, cisme_pumpSpeedMsg_fields, &speedMsg);
00359 }
00360 
00361 // Handle request to set pump speed
00362 static void wifiEventsHandleSetPumpReq(uint8_t* msg, size_t msgLen)
00363 {
00364     cisme_pumpSpeedMsg pumpMsg = cisme_pumpSpeedMsg_init_default;
00365 
00366     pb_istream_t stream = pb_istream_from_buffer(msg, msgLen);
00367 
00368     if (!pb_decode(&stream, cisme_pumpSpeedMsg_fields, &pumpMsg)) {
00369         ERROR("Can't decode received message");
00370         return;
00371     }
00372 
00373     DEBUG1("Receive SET_PUMP_REQ: speed=%d", pumpMsg.speed);
00374 
00375     pumpSetRpm(pumpMsg.speed);
00376 
00377     // Send response
00378     wifiEventsSendPumpRsp(cisme_MessageType_SET_PUMP_RSP);
00379 }
00380 
00381 // Handle request to get pump speed
00382 static void wifiEventsHandleGetPumpReq(void)
00383 {
00384     DEBUG1("Receive GET_PUMP_REQ");
00385     // Send response
00386     wifiEventsSendPumpRsp(cisme_MessageType_GET_PUMP_RSP);
00387 }
00388 
00389 // Fill light level message and send to app
00390 static void wifiEventsSendLightRsp(cisme_MessageType type)
00391 {
00392     cisme_lightLevelMsg levelMsg = cisme_lightLevelMsg_init_default;
00393     levelMsg.has_level = true;
00394     levelMsg.level = lightRead();
00395 
00396     DEBUG1("Send %s: level=%d", (type == cisme_MessageType_SET_PUMP_RSP) ? "SET_LIGHT_RSP" : "GET_LIGHT_RSP", levelMsg.level);
00397     wifiEventsSendMsg(type, cisme_lightLevelMsg_fields, &levelMsg);
00398 }
00399 
00400 // Handle request to set light level
00401 static void wifiEventsHandleSetLightReq(uint8_t* msg, size_t msgLen)
00402 {
00403     cisme_lightLevelMsg levelMsg = cisme_lightLevelMsg_init_default;
00404     pb_istream_t stream = pb_istream_from_buffer(msg, msgLen);
00405 
00406     if (!pb_decode(&stream, cisme_lightLevelMsg_fields, &levelMsg)) {
00407         ERROR("Can't decode received message");
00408         return;
00409     }
00410 
00411     DEBUG1("Receive SET_LIGHT_REQ: level=%d", levelMsg.level);
00412 
00413     if ((levelMsg.level < LIGHT_MIN_INTENSITY) || (levelMsg.level > LIGHT_MAX_INTENSITY)) {
00414         ERROR("Incorrect light level: %d", levelMsg.level);
00415         return;
00416     }
00417 
00418     lightSet(levelMsg.level);
00419 
00420     // Send response
00421     wifiEventsSendLightRsp(cisme_MessageType_SET_LIGHT_RSP);
00422 }
00423 
00424 // Handle request to get light level
00425 static void wifiEventsHandleGetLightReq(void)
00426 {
00427     DEBUG1("Receive GET_LIGHT_REQ");
00428     // Send response
00429     wifiEventsSendLightRsp(cisme_MessageType_GET_LIGHT_RSP);
00430 }
00431 
00432 // Send temperature calibration factor
00433 static void wifiEventsSendTempCalibrationRsp(float bValue)
00434 {
00435     cisme_tempCalibrationRspMsg tempRsp = cisme_tempCalibrationRspMsg_init_default;
00436     tempRsp.has_bValue = true;
00437     tempRsp.bValue = bValue;
00438 
00439     DEBUG1("Send TEMP_CALIBRATION_RSP: bValue=%2.6f", tempRsp.bValue);
00440     wifiEventsSendMsg(cisme_MessageType_TEMP_CALIBRATION_RSP, cisme_tempCalibrationRspMsg_fields, &tempRsp);
00441 }
00442 
00443 // Handle request to calibrate temperature
00444 static void wifiEventsHandleTempCalibrationReq(uint8_t* msg, size_t msgLen)
00445 {
00446     cisme_tempCalibrationMsg tempMsg = cisme_tempCalibrationMsg_init_default;
00447     pb_istream_t stream = pb_istream_from_buffer(msg, msgLen);
00448 
00449     if (!pb_decode(&stream, cisme_tempCalibrationMsg_fields, &tempMsg)) {
00450         ERROR("Can't decode received message");
00451         return;
00452     }
00453 
00454     if (!tempMsg.has_temperature) {
00455         ERROR("Missing temperature field in TEMP_CALIBRATION_REQ");
00456         return;
00457     }
00458 
00459     DEBUG1("Receive TEMP_CALIBRATION_REQ: temperature=%2.3f, lightLevel=%d, pumpSpeed=%d",
00460            tempMsg.temperature, tempMsg.lightLevel, tempMsg.pumpSpeed);
00461 
00462     // Set light and pump intensity
00463     if (tempMsg.lightLevel) {
00464         float TempLight = lightRead();
00465         lightSet(TempLight);
00466     } else {
00467         lightSet(LIGHT_OFF_INTENSITY);
00468     }
00469 
00470     if (tempMsg.pumpSpeed) {
00471         //pumpSet(50);
00472         float TempSpeed = pumpSpeed();
00473         pumpSetRpm(TempSpeed);
00474     } else {
00475         pumpSet(PUMP_OFF_INTENSITY);
00476     }
00477 
00478     float bValue = calibrationTemperature(tempMsg.temperature);
00479 
00480     // Send response
00481     wifiEventsSendTempCalibrationRsp(bValue);
00482 }
00483 
00484 // Apply O2 calibration parameters
00485 static void wifiEventsHandleO2CalibrationReq(uint8_t* msg, size_t msgLen)
00486 {
00487     cisme_o2CalibrationMsg o2Msg = cisme_o2CalibrationMsg_init_default;
00488     pb_istream_t stream = pb_istream_from_buffer(msg, msgLen);
00489 
00490     if (!pb_decode(&stream, cisme_o2CalibrationMsg_fields, &o2Msg)) {
00491         ERROR("Can't decode received message");
00492         return;
00493     }
00494 
00495     if (!o2Msg.has_pressure) {
00496         ERROR("Missing pressure field in O2_CALIBRATION_REQ");
00497         return;
00498     }
00499 
00500     if (!o2Msg.has_led) {
00501         ERROR("Missing led field in O2_CALIBRATION_REQ");
00502         return;
00503     }
00504 
00505     if (!o2Msg.has_phase1) {
00506         ERROR("Missing phase1 field in O2_CALIBRATION_REQ");
00507         return;
00508     }
00509 
00510     if (!o2Msg.has_temperature1) {
00511         ERROR("Missing temperature1 field in O2_CALIBRATION_REQ");
00512         return;
00513     }
00514 
00515     if (!o2Msg.has_phase2) {
00516         ERROR("Missing phase2 field in O2_CALIBRATION_REQ");
00517         return;
00518     }
00519 
00520     if (!o2Msg.has_temperature2) {
00521         ERROR("Missing temperature2 field in O2_CALIBRATION_REQ");
00522         return;
00523     }
00524 
00525     DEBUG1("Receive O2_CALIBRATION_REQ: pressure=%1.2f, led=%1.2f, phase1=%1.2f, temperature1=%1.2f, phase2=%1.2f, temperature2=%1.2f",
00526            o2Msg.pressure, o2Msg.led, o2Msg.phase1, o2Msg.temperature1, o2Msg.phase2, o2Msg.temperature2);
00527 
00528     // Set parameters
00529     PresCal = o2Msg.pressure;
00530     PhaseCal1 = o2Msg.phase1;
00531     TempCal1 = o2Msg.temperature1;
00532     PhaseCal2 = o2Msg.phase2;
00533     TempCal2 = o2Msg.temperature2;
00534     LEDCurrent = o2Msg.led;
00535 
00536     // Apply parameters
00537     calibrationO2();
00538 
00539     // Send response
00540     DEBUG1("Send O2_CALIBRATION_RSP: pressure=%1.2f, led=%1.2f, phase1=%1.2f, temperature1=%1.2f, phase2=%1.2f, temperature2=%1.2f",
00541            o2Msg.pressure, o2Msg.led, o2Msg.phase1, o2Msg.temperature1, o2Msg.phase2, o2Msg.temperature2);
00542     wifiEventsSendMsg(cisme_MessageType_O2_CALIBRATION_RSP, cisme_o2CalibrationMsg_fields, &o2Msg);
00543 }
00544 
00545 // Handle request to calibrate PH
00546 static void wifiEventsHandlePhCalibrationReq(uint8_t* msg, size_t msgLen)
00547 {
00548     cisme_phCalibrationMsg phMsg = cisme_phCalibrationMsg_init_default;
00549     pb_istream_t stream = pb_istream_from_buffer(msg, msgLen);
00550 
00551     if (!pb_decode(&stream, cisme_phCalibrationMsg_fields, &phMsg)) {
00552         ERROR("Can't decode received message");
00553         return;
00554     }
00555 
00556     if (!phMsg.has_ph) {
00557         ERROR("Missing ph field in PH_CALIBRATION_REQ");
00558         return;
00559     }
00560 
00561     DEBUG1("Receive PH_CALIBRATION_REQ: ph=%2.3f, lightLevel=%d, pumpSpeed=%d",
00562            phMsg.ph, phMsg.lightLevel, phMsg.pumpSpeed);
00563 
00564     // Set light and pump intensity
00565     if (phMsg.lightLevel) {
00566         float pHLight = lightRead();
00567         lightSet(pHLight);
00568     } else {
00569         lightSet(LIGHT_OFF_INTENSITY);
00570     }
00571 
00572     if (phMsg.pumpSpeed) {
00573         float pHSpeed = pumpSpeed();
00574         pumpSetRpm(pHSpeed);
00575         
00576     } else {
00577         pumpSet(PUMP_OFF_INTENSITY);
00578     }
00579 
00580     // Allocate response
00581     cisme_phCalibrationRspMsg phRsp = cisme_phCalibrationRspMsg_init_default;
00582     phRsp.has_phBuffer = true;
00583     phRsp.has_phTemp = true;
00584     phRsp.has_slope = true;
00585     phRsp.has_eo = true;
00586     phRsp.phBuffer = phMsg.ph;
00587 
00588     calibrationPh(phRsp.phBuffer, &phRsp.phTemp, &phRsp.slope, &phRsp.eo, NULL);
00589 
00590     // Send response
00591     DEBUG1("Send PH_CALIBRATION_RSP: ph=%2.3f, phTemp=%2.3f, slope=%2.6f, eo=%2.6f",
00592            phRsp.phBuffer, phRsp.phTemp, phRsp.slope, phRsp.eo);
00593     wifiEventsSendMsg(cisme_MessageType_PH_CALIBRATION_RSP, cisme_phCalibrationRspMsg_fields, &phRsp);
00594 }
00595 
00596 // Send current PH parameters
00597 static void wifiEventsSendCurCalPh(void)
00598 {
00599     cisme_phCalibrationRspMsg phRsp = cisme_phCalibrationRspMsg_init_default;
00600     phRsp.has_phBuffer = true;
00601     phRsp.has_phTemp = true;
00602     phRsp.has_slope = true;
00603     phRsp.has_eo = true;
00604     phRsp.phBuffer = PHBUFFERF;
00605     phRsp.phTemp = PHTEMPF;
00606     phRsp.slope = MSINGLEPT;
00607     phRsp.eo = EOSINGLEPT;
00608 
00609     // Send response
00610     DEBUG1("Send PH_CALIBRATION_RSP: ph=%2.3f, phTemp=%2.3f, slope=%2.6f, eo=%2.6f",
00611            phRsp.phBuffer, phRsp.phTemp, phRsp.slope, phRsp.eo);
00612     wifiEventsSendMsg(cisme_MessageType_PH_CALIBRATION_RSP, cisme_phCalibrationRspMsg_fields, &phRsp);
00613 }
00614 
00615 // Send current O2 parameters
00616 static void wifiEventsSendCurCalO2(void)
00617 {
00618     cisme_o2CalibrationMsg o2Msg = cisme_o2CalibrationMsg_init_default;
00619     o2Msg.has_pressure = true;
00620     o2Msg.has_phase1 = true;
00621     o2Msg.has_temperature1 = true;
00622     o2Msg.has_phase2 = true;
00623     o2Msg.has_temperature2 = true;
00624     o2Msg.has_led = true;
00625     o2Msg.pressure = PresCal;
00626     o2Msg.phase1 = PhaseCal1;
00627     o2Msg.temperature1 = TempCal1;
00628     o2Msg.phase2 = PhaseCal2;
00629     o2Msg.temperature2 = TempCal2;
00630     o2Msg.led = LEDCurrent;
00631 
00632     // Send response
00633     DEBUG1("Send O2_CALIBRATION_RSP: pressure=%1.2f, led=%1.2f, phase1=%1.2f, temperature1=%1.2f, phase2=%1.2f, temperature2=%1.2f",
00634            o2Msg.pressure, o2Msg.led, o2Msg.phase1, o2Msg.temperature1, o2Msg.phase2, o2Msg.temperature2);
00635     wifiEventsSendMsg(cisme_MessageType_O2_CALIBRATION_RSP, cisme_o2CalibrationMsg_fields, &o2Msg);
00636 }
00637 
00638 static void sendPumpCalibrationRsp(float aValue, float bValue, float cValue)
00639 {
00640     cisme_pumpCalibrationMsg rspMsg = cisme_pumpCalibrationMsg_init_default;
00641     rspMsg.has_a = true;
00642     rspMsg.has_b = true;
00643     rspMsg.has_c = true;
00644     rspMsg.a = aValue;
00645     rspMsg.b = bValue;
00646     rspMsg.c = cValue;
00647 
00648     DEBUG1("Send PUMP_CALIBRATION_RSP: a=%f, b=%f, c=%f", rspMsg.a, rspMsg.b, rspMsg.c);
00649     wifiEventsSendMsg(cisme_MessageType_PUMP_CALIBRATION_RSP, cisme_pumpCalibrationMsg_fields, &rspMsg);
00650 }
00651 
00652 // Handle request to get current calibrated parameters
00653 static void wifiEventsHandleCurCalibrationReq(uint8_t* msg, size_t msgLen)
00654 {
00655     cisme_currentCalibrationMsg calMsg = cisme_currentCalibrationMsg_init_default;
00656     pb_istream_t stream = pb_istream_from_buffer(msg, msgLen);
00657 
00658     if (!pb_decode(&stream, cisme_currentCalibrationMsg_fields, &calMsg)) {
00659         ERROR("Can't decode received message");
00660         return;
00661     }
00662 
00663     if (!calMsg.has_type) {
00664         calMsg.type = cisme_CalibrationType_PH;
00665     }
00666 
00667     DEBUG1("Receive CUR_CALIBRATION_REQ: type=%d", calMsg.type);
00668 
00669     switch(calMsg.type) {
00670         case cisme_CalibrationType_PH:
00671             wifiEventsSendCurCalPh();
00672             break;
00673         case cisme_CalibrationType_TEMPERATURE:
00674             wifiEventsSendTempCalibrationRsp(B);
00675             break;
00676         case cisme_CalibrationType_O2:
00677             wifiEventsSendCurCalO2();
00678             break;
00679         case cisme_CalibrationType_PUMP: {
00680             float a = 0.0;
00681             float b = 0.0;
00682             float c = 0.0;
00683             pumpGetParams(&a, &b, &c);
00684             sendPumpCalibrationRsp(a, b, c);
00685             break;
00686         }
00687         default:
00688             break;
00689     }
00690 }
00691 
00692 // Send calibration accept response
00693 static void wifiEventsSendCalAcceptRsp(cisme_CalibrationType type)
00694 {
00695     cisme_currentCalibrationMsg calMsg = cisme_currentCalibrationMsg_init_default;
00696     calMsg.has_type = true;
00697     calMsg.type = type;
00698 
00699     DEBUG1("Send CALIBRATION_ACCEPT_RSP: type=%d", calMsg.type);
00700     wifiEventsSendMsg(cisme_MessageType_CALIBRATION_ACCEPT_RSP, cisme_currentCalibrationMsg_fields, &calMsg);
00701 }
00702 
00703 // Handle request to save temperature parameters
00704 static void wifiEventsHandleTempCalAcceptReq(uint8_t* msg, size_t msgLen)
00705 {
00706     cisme_tempCalibrationRspMsg tempMsg = cisme_tempCalibrationRspMsg_init_default;
00707     pb_istream_t stream = pb_istream_from_buffer(msg, msgLen);
00708 
00709     if (!pb_decode(&stream, cisme_tempCalibrationRspMsg_fields, &tempMsg)) {
00710         ERROR("Can't decode received message");
00711         return;
00712     }
00713 
00714     if (!tempMsg.has_bValue) {
00715         ERROR("Missing bValue field in TEMP_CALIBRATION_ACCEPT_REQ");
00716         return;
00717     }
00718 
00719     DEBUG1("Receive TEMP_CALIBRATION_ACCEPT_REQ: bValue=%2.6f", tempMsg.bValue);
00720 
00721     calibrationTemperatureSave(tempMsg.bValue);
00722 
00723     // Send response
00724     wifiEventsSendCalAcceptRsp(cisme_CalibrationType_TEMPERATURE);
00725 }
00726 
00727 // Handle request to save PH parameters
00728 static void wifiEventsHandlePhCalAcceptReq(uint8_t* msg, size_t msgLen)
00729 {
00730     cisme_phCalibrationRspMsg phMsg = cisme_phCalibrationRspMsg_init_default;
00731     pb_istream_t stream = pb_istream_from_buffer(msg, msgLen);
00732 
00733     if (!pb_decode(&stream, cisme_phCalibrationRspMsg_fields, &phMsg)) {
00734         ERROR("Can't decode received message");
00735         return;
00736     }
00737 
00738     if (!phMsg.has_phBuffer) {
00739         ERROR("Missing phBuffer field in PH_CALIBRATION_ACCEPT_REQ");
00740         return;
00741     }
00742 
00743     if (!phMsg.has_slope) {
00744         ERROR("Missing slope field in PH_CALIBRATION_ACCEPT_REQ");
00745         return;
00746     }
00747 
00748     if (!phMsg.has_phTemp) {
00749         ERROR("Missing phTemp field in PH_CALIBRATION_ACCEPT_REQ");
00750         return;
00751     }
00752 
00753     if (!phMsg.has_eo) {
00754         ERROR("Missing eo field in PH_CALIBRATION_ACCEPT_REQ");
00755         return;
00756     }
00757 
00758     DEBUG1("Receive PH_CALIBRATION_ACCEPT_REQ: ph=%2.3f, phTemp=%2.3f, slope=%2.6f, eo=%2.6f",
00759            phMsg.phBuffer, phMsg.phTemp, phMsg.slope, phMsg.eo);
00760 
00761     PHBUFFERF = (float)phMsg.phBuffer;
00762     PHTEMPF = (float)phMsg.phTemp;
00763     PHTEMPKF = (float)(phMsg.phTemp + 273.15);
00764     PHVOLTSF = (float)(phMsg.eo + phMsg.slope * phMsg.phBuffer);
00765     MSINGLEPT = (float)phMsg.slope;
00766     EOSINGLEPT = (float)phMsg.eo;
00767 
00768     // Send response
00769     wifiEventsSendCalAcceptRsp(cisme_CalibrationType_PH);
00770 
00771     // Save parameters and restart board
00772     calibrationPhSave();
00773 }
00774 
00775 // Start experiment
00776 static void wifiEventsHandleStartExpInd(uint8_t* msg, size_t msgLen)
00777 {
00778     cisme_startExperimentMsg expMsg = cisme_startExperimentMsg_init_default;
00779     static char receivedPrefix[256] = {0};
00780 
00781     pb_istream_t stream = pb_istream_from_buffer(msg, msgLen);
00782     if (!pb_decode(&stream, cisme_startExperimentMsg_fields, &expMsg)) {
00783         ERROR("Can't decode received message");
00784         return;
00785     }
00786 
00787     if (!expMsg.has_id) {
00788         ERROR("Missing id field in START_EXPERIMENT_IND");
00789         return;
00790     }
00791 
00792     if (!expMsg.has_stepsCount) {
00793         ERROR("Missing stepsCount field in START_EXPERIMENT_IND");
00794         return;
00795     }
00796 
00797     if (!expMsg.has_salinity) {
00798         ERROR("Missing salinity field in START_EXPERIMENT_IND");
00799         return;
00800     }
00801 
00802     DEBUG1("Receive START_EXPERIMENT_IND: id=%d, experiment=%d, stepsCount=%d, salinity=%d, pumpSpeed=%d repeats=%d",
00803            expMsg.id, expMsg.experiment, expMsg.stepsCount, expMsg.salinity, expMsg.pumpSpeed, expMsg.repeats);
00804 
00805     if (isExpExecuting == true && expMsg.id != currentExpId) {
00806         ERROR("Received START_EXPERIMENT_IND with expMsg.id=%d, but already executing experiment id=%d",
00807               expMsg.id, currentExpId);
00808         return;
00809     }
00810 
00811     if (expMsg.stepsCount * (1 + expMsg.repeats) > MAX_STEPS_NO) {
00812         expMsg.repeats = (MAX_STEPS_NO / expMsg.stepsCount) - 1;
00813         ERROR("User wants too many steps. Count of repeats decreased to: %d", expMsg.repeats);
00814     }
00815 
00816     for (int ix = 0; ix < expMsg.stepsCount * (1 + expMsg.repeats); ix++) {
00817         pgm[ix][0] = expMsg.pumpSpeed;
00818     }
00819 
00820     // Decode steps
00821     uint8_t stepIx = 0;
00822     expMsg.steps.funcs.decode = &pbDecodeProgramSteps;
00823     expMsg.steps.arg = &stepIx;
00824 
00825     expMsg.filePrefix.funcs.decode = & pbDecodeString;
00826     expMsg.filePrefix.arg = receivedPrefix;
00827 
00828     stream = pb_istream_from_buffer(msg, msgLen);
00829     if (!pb_decode(&stream, cisme_startExperimentMsg_fields, &expMsg)) {
00830         ERROR("Can't decode received message");
00831         return;
00832     }
00833 
00834     if (strcmp(receivedPrefix, "") != 0) {
00835         /* User wants some prefix for the file name.*/
00836         strncpy(FilePrefix, receivedPrefix, FILE_PREFIX_LENGTH);
00837         DEBUG1("User wants prefix:%s", FilePrefix);
00838     }
00839 
00840     Salinity           = expMsg.salinity;
00841     numberofprograms   = expMsg.stepsCount;
00842     currentExpId       = expMsg.id;
00843     isExpExecuting     = true;
00844     MeasurementTypeVal = PGM;
00845 
00846     if (expMsg.has_repeats && expMsg.experiment >= cisme_startExperimentMsg_ExperimentType_RESPIRATION &&
00847             expMsg.experiment < cisme_startExperimentMsg_ExperimentType_MULTI &&
00848             expMsg.repeats > 0) {
00849         for (int repeatIx = 0; repeatIx < expMsg.repeats; repeatIx++) {
00850             memcpy(&(pgm[numberofprograms * (repeatIx + 1)]), pgm, sizeof(float) * 20 * numberofprograms);
00851         }
00852 
00853         numberofprograms *= expMsg.repeats + 1;
00854     }
00855 
00856     experimentPrepareUserProgram();
00857 }
00858 
00859 // Handle experiment action (next step or stop)
00860 static void wifiEventsHandleActionExpInd(cisme_MessageType type, uint8_t* msg, size_t msgLen)
00861 {
00862     cisme_experimentMsg expMsg = cisme_experimentMsg_init_default;
00863 
00864     pb_istream_t stream = pb_istream_from_buffer(msg, msgLen);
00865     if (!pb_decode(&stream, cisme_experimentMsg_fields, &expMsg)) {
00866         ERROR("Can't decode received message");
00867         return;
00868     }
00869 
00870     if (!expMsg.has_id) {
00871         ERROR("Missing id field in %s",
00872               (type == cisme_MessageType_NEXT_EXPERIMENT_IND) ? "NEXT_EXPERIMENT_IND" : "STOP_EXPERIMENT_IND");
00873         return;
00874     }
00875 
00876     if (isExpExecuting == false) {
00877         /* Not ERROR because this can happen if the message will be received when experiment already finished. */
00878         INFO("Unexpected actionExpInd. We are not executing experiment right now.");
00879         return;
00880     }
00881 
00882     if (expMsg.id != currentExpId) {
00883         ERROR("Unexpected expId received. Received expId=%d currentExpId=%d", expMsg.id, currentExpId);
00884         return;
00885     }
00886 
00887     switch (type) {
00888         case cisme_MessageType_NEXT_EXPERIMENT_IND:
00889             SwitchMode = 1;
00890             INFO("Experiment switched by user.");
00891             fprintf(currentFile,"User Advanced Step\n");
00892             break;
00893         case cisme_MessageType_STOP_EXPERIMENT_IND:
00894 
00895             INFO("User Ended Experiment");
00896             fprintf(currentFile,"User Ended Experiment\n");
00897             isExpExecuting = false;
00898 
00899             finishExperiment();
00900 
00901             wifiEventsSendFinishExpInd(currentExpId, FileName);
00902             break;
00903         default:
00904             ERROR("Unexpected message type received:%d", type);
00905             return;
00906     }
00907 }
00908 
00909 // Send file download response
00910 static void wifiEventsSendFileDownloadRsp(int32_t fileId, int32_t numBlocks)
00911 {
00912     cisme_fileDownloadRspMsg fileRsp = cisme_fileDownloadRspMsg_init_default;
00913     fileRsp.has_fileId = true;
00914     fileRsp.has_numBlocks = true;
00915     fileRsp.fileId = fileId;
00916     fileRsp.numBlocks = numBlocks;
00917 
00918     DEBUG1("Send FILE_DOWNLOAD_RSP: fileId=%d, numBlocks=%d", fileRsp.fileId, fileRsp.numBlocks);
00919     wifiEventsSendMsg(cisme_MessageType_FILE_DOWNLOAD_RSP, cisme_fileDownloadRspMsg_fields, &fileRsp);
00920 }
00921 
00922 // Send file block
00923 static void wifiEventsSendFileBlockReq(int32_t fileId)
00924 {
00925     blockId++;
00926 
00927     if (blockId > numBlocks) {
00928         ERROR("Excess file block requested");
00929         return;
00930     }
00931 
00932     cisme_fileBlockMsg blockReq = cisme_fileBlockMsg_init_default;
00933     blockReq.has_fileId = true;
00934     blockReq.has_blockId = true;
00935     blockReq.has_blockSize = true;
00936     blockReq.fileId = fileId;
00937     blockReq.blockId = blockId;
00938     blockReq.blockSize = (blockId < numBlocks) ? FILE_BLOCK_SIZE : (fileLen % FILE_BLOCK_SIZE);
00939     blockReq.blockData.funcs.encode = &pbEncodeFileBlock;
00940 
00941     DEBUG1("Send FILE_BLOCK_REQ: fileId=%d, blockId=%d, blockSize=%d",
00942            blockReq.fileId, blockReq.blockId, blockReq.blockSize);
00943     wifiEventsSendMsg(cisme_MessageType_FILE_BLOCK_REQ, cisme_fileBlockMsg_fields, &blockReq);
00944 }
00945 
00946 // Send file action (finish or abort)
00947 static void wifiEventsSendFileActionInd(cisme_MessageType type, int32_t fileId)
00948 {
00949     cisme_fileActionMsg actionMsg = cisme_fileActionMsg_init_default;
00950     actionMsg.has_fileId = true;
00951     actionMsg.fileId = fileId;
00952 
00953     DEBUG1("Send %s: fileId=%d",
00954            (type == cisme_MessageType_FILE_FINISH_IND) ? "FILE_FINISH_IND" : "FILE_ABORT_IND",
00955            actionMsg.fileId);
00956     wifiEventsSendMsg(type, cisme_fileActionMsg_fields, &actionMsg);
00957 }
00958 
00959 // Handle request to download file
00960 static void wifiEventsHandleFileDownloadReq(uint8_t* msg, size_t msgLen)
00961 {
00962     char fileName[FILE_NAME_LENGTH];
00963 
00964     cisme_fileDownloadMsg fileReq = cisme_fileDownloadMsg_init_default;
00965     fileReq.name.funcs.decode = &pbDecodeString;
00966     fileReq.name.arg = fileName;
00967 
00968     pb_istream_t stream = pb_istream_from_buffer(msg, msgLen);
00969     if (!pb_decode(&stream, cisme_fileDownloadMsg_fields, &fileReq)) {
00970         ERROR("Can't decode received message");
00971         return;
00972     }
00973 
00974     DEBUG1("Receive FILE_DOWNLOAD_REQ: name=%s", fileName);
00975 
00976     if (curFile != NULL) {
00977         INFO("New file download request, abort previous one");
00978         fclose(curFile);
00979         wifiEventsSendFileActionInd(cisme_MessageType_FILE_ABORT_IND, fileId);
00980     }
00981 
00982     char dataname[PATH_TO_FILE_LEN];
00983     sprintf(dataname, "%s%s", "/" FSNAME "/Data/", fileName);
00984     curFile = fopen(dataname, "rb");
00985     if (curFile == NULL) {
00986         ERROR("File %s not found", fileName);
00987         return;
00988     }
00989 
00990     fseek(curFile, 0, SEEK_END);
00991     fileLen = ftell(curFile);
00992     rewind(curFile);
00993 
00994     fileId++;
00995     numBlocks = fileLen / FILE_BLOCK_SIZE;
00996     if (fileLen % FILE_BLOCK_SIZE > 0) {
00997         numBlocks++;
00998     }
00999 
01000     wifiEventsSendFileDownloadRsp(fileId, numBlocks);
01001 
01002     blockId = 0;
01003     wifiEventsSendFileBlockReq(fileId);
01004 }
01005 
01006 // Handle response for block transfer
01007 static void wifiEventsHandleFileBlockRsp(uint8_t* msg, size_t msgLen)
01008 {
01009     cisme_fileBlockRspMsg blockRsp = cisme_fileBlockRspMsg_init_default;
01010     pb_istream_t stream = pb_istream_from_buffer(msg, msgLen);
01011 
01012     if (!pb_decode(&stream, cisme_fileBlockRspMsg_fields, &blockRsp)) {
01013         ERROR("Can't decode received message");
01014         return;
01015     }
01016 
01017     if (!blockRsp.has_fileId) {
01018         ERROR("Missing fileId field in FILE_BLOCK_RSP");
01019         return;
01020     }
01021 
01022     if (!blockRsp.has_blockId) {
01023         ERROR("Missing blockId field in FILE_BLOCK_RSP");
01024         return;
01025     }
01026 
01027     DEBUG1("Receive FILE_BLOCK_RSP: fileId=%d, blockId=%d",
01028            blockRsp.fileId, blockRsp.blockId);
01029 
01030     if (curFile == NULL) {
01031         ERROR("No file transfer ongoing");
01032         return;
01033     }
01034 
01035     if (fileId != blockRsp.fileId) {
01036         ERROR("Unknown fileId=%d, expected one:%d", blockRsp.fileId, fileId);
01037 
01038         // Send abort for both files
01039         wifiEventsSendFileActionInd(cisme_MessageType_FILE_ABORT_IND, fileId);
01040         wifiEventsSendFileActionInd(cisme_MessageType_FILE_ABORT_IND, blockRsp.fileId);
01041 
01042         if (curFile != NULL) {
01043             fclose(curFile);
01044             curFile = NULL;
01045         }
01046         return;
01047     }
01048 
01049     if (blockId != blockRsp.blockId) {
01050         ERROR("Unknown blockId=%d, expected one:%d", blockRsp.blockId, blockId);
01051 
01052         // Send abort for both files
01053         wifiEventsSendFileActionInd(cisme_MessageType_FILE_ABORT_IND, fileId);
01054 
01055         if (curFile != NULL) {
01056             fclose(curFile);
01057             curFile = NULL;
01058         }
01059         return;
01060     }
01061 
01062     if (blockId == numBlocks) {
01063         fclose(curFile);
01064         curFile = NULL;
01065         wifiEventsSendFileActionInd(cisme_MessageType_FILE_FINISH_IND, fileId);
01066         INFO("File transfer (%d) finished", fileId);
01067         return;
01068     }
01069 
01070     wifiEventsSendFileBlockReq(fileId);
01071 }
01072 
01073 // Handle file abort
01074 static void wifiEventsHandleFileAbortInd(uint8_t* msg, size_t msgLen)
01075 {
01076     cisme_fileActionMsg actionMsg = cisme_fileActionMsg_init_default;
01077     pb_istream_t stream = pb_istream_from_buffer(msg, msgLen);
01078 
01079     if (!pb_decode(&stream, cisme_fileActionMsg_fields, &actionMsg)) {
01080         ERROR("Can't decode received message");
01081         return;
01082     }
01083 
01084     if (!actionMsg.has_fileId) {
01085         ERROR("Missing fileId field in FILE_ABORT_IND");
01086         return;
01087     }
01088 
01089     DEBUG1("Receive FILE_ABORT_IND: fileId=%d", actionMsg.fileId);
01090 
01091     if (fileId != actionMsg.fileId) {
01092         ERROR("Unknown fileId=%d, expected one:%d", actionMsg.fileId, fileId);
01093         return;
01094     }
01095 
01096     if (curFile == NULL) {
01097         ERROR("No file transfer ongoing");
01098         return;
01099     }
01100 
01101     fclose(curFile);
01102     curFile = NULL;
01103 }
01104 
01105 // Get experiments files
01106 static void wifiEventsHandleGetFilesReq(void)
01107 {
01108     DEBUG1("Receive GET_FILES_REQ");
01109 
01110     // Fill and send response
01111     cisme_filesMsg filesMsg = cisme_filesMsg_init_default;
01112     filesMsg.has_numFiles = true;
01113     filesMsg.numFiles = 0;
01114     filesMsg.names.funcs.encode = pbEncodeFiles;
01115 
01116     DIR* dir = opendir("/msc/data/");
01117     struct dirent* entry = NULL;
01118 
01119     while ((entry = readdir(dir)) != NULL) {
01120         if (strstr(entry->d_name, ".csv") != NULL) {
01121             filesMsg.numFiles++;
01122         }
01123     }
01124 
01125     DEBUG1("Send GET_FILES_RSP: numFiles=%d", filesMsg.numFiles);
01126     wifiEventsSendMsg(cisme_MessageType_GET_FILES_RSP, cisme_filesMsg_fields, &filesMsg);
01127 }
01128 
01129 // Handle request for raw data
01130 static void wifiEventsHandleRawDataReq(void)
01131 {
01132     DEBUG1("Receive RAW_DATA_REQ");
01133 
01134     // Prepare and send response
01135     cisme_rawDataMsg rawMsg = cisme_rawDataMsg_init_default;
01136     rawMsg.has_o2 = true;
01137     rawMsg.has_ph = true;
01138     rawMsg.has_o2Amplitude = true;
01139     rawMsg.has_o2Phase = true;
01140     rawMsg.has_phAdcV = true;
01141     rawMsg.has_temperatureAdcV = true;
01142     rawMsg.has_temperature = true;
01143 
01144     float presensData[PRESENS_RES_LENGTH];
01145     presensGetData(presensData);
01146 
01147     rawMsg.o2Amplitude = presensData[0];
01148     rawMsg.o2Phase = presensData[1];
01149     rawMsg.o2 = presensData[2];
01150     rawMsg.ph = pHCorrected;
01151     rawMsg.phAdcV = pH;
01152     rawMsg.temperatureAdcV = pHT;
01153     rawMsg.temperature = PHTEMP;
01154 
01155     DEBUG1("Send RAW_DATA_RSP: o2Amplitude=%d, o2Phase=%3.2f, o2=%3.0f, pH=%3.2f, pHAdcV=%3.3f, temperatureAdcV=%3.3f, temperature=%1.1f",
01156            rawMsg.o2Amplitude, rawMsg.o2Phase, rawMsg.o2, rawMsg.ph, rawMsg.phAdcV, rawMsg.temperatureAdcV, rawMsg.temperature);
01157     wifiEventsSendMsg(cisme_MessageType_RAW_DATA_RSP, cisme_rawDataMsg_fields, &rawMsg);
01158 }
01159 
01160 // Start pump calibration
01161 static void wifiEventsHandlePumpCalibrationReq(void)
01162 {
01163     DEBUG1("Receive PUMP_CALIBRATION_REQ");
01164  
01165     float a = 0.0;
01166     float b = 0.0;
01167     float c = 0.0;
01168     
01169     calibrationPump(&a, &b, &c);
01170     sendPumpCalibrationRsp(a, b, c);
01171 }
01172  
01173 // Apply pump calibration parameters
01174 static void wifiEventsHandlePumpCalAcceptReq(uint8_t* msg, size_t msgLen)
01175 {
01176     cisme_pumpCalibrationMsg calMsg = cisme_pumpCalibrationMsg_init_default;
01177     pb_istream_t stream = pb_istream_from_buffer(msg, msgLen);
01178  
01179     if (!pb_decode(&stream, cisme_pumpCalibrationMsg_fields, &calMsg)) {
01180         ERROR("Can't decode received message");
01181         return;
01182     }
01183  
01184     DEBUG1("Receive PUMP_CALIBRATION_ACCEPT_REQ: a=%f, b=%f, c=%f", calMsg.a, calMsg.b, calMsg.c);
01185     pumpSetParams(calMsg.a, calMsg.b, calMsg.c);
01186     
01187     // Send response
01188     wifiEventsSendCalAcceptRsp(cisme_CalibrationType_PUMP);
01189 }
01190 
01191 // Handle message from app
01192 static void wifiEventsHandleMsg(void)
01193 {
01194     uint8_t* buffer;
01195     unsigned int msgLen = wifiGetMessage(&buffer);
01196 
01197     if (msgLen == 0) {
01198         return;
01199     }
01200 
01201     cisme_genericMsg genericMsg = cisme_genericMsg_init_default;
01202     PbDecodeMessage message = {NULL, 0};
01203     genericMsg.payload.funcs.decode = pbDecodeMsg;
01204     genericMsg.payload.arg = &message;
01205 
01206     for (size_t ix = 0; ix < msgLen; ix++) {
01207         DEBUG1("0x%x", buffer[ix]);
01208     }
01209 
01210     pb_istream_t stream = pb_istream_from_buffer(buffer, msgLen);
01211 
01212     if (!pb_decode(&stream, cisme_genericMsg_fields, &genericMsg)) {
01213         ERROR("Can't decode received message");
01214         return;
01215     }
01216 
01217     switch (genericMsg.type) {
01218         case cisme_MessageType_INSTRUMENT_ID_REQ:
01219             wifiEventsHandleIdReq();
01220             break;
01221         case cisme_MessageType_START_EXPERIMENT_IND:
01222             wifiEventsHandleStartExpInd(message.msg, message.msgLen);
01223             break;
01224         case cisme_MessageType_NEXT_EXPERIMENT_IND:
01225         case cisme_MessageType_STOP_EXPERIMENT_IND:
01226             wifiEventsHandleActionExpInd(genericMsg.type, message.msg, message.msgLen);
01227             break;
01228         case cisme_MessageType_TEMP_CALIBRATION_REQ:
01229             wifiEventsHandleTempCalibrationReq(message.msg, message.msgLen);
01230             break;
01231         case cisme_MessageType_O2_CALIBRATION_REQ:
01232             wifiEventsHandleO2CalibrationReq(message.msg, message.msgLen);
01233             break;
01234         case cisme_MessageType_PH_CALIBRATION_REQ:
01235             wifiEventsHandlePhCalibrationReq(message.msg, message.msgLen);
01236             break;
01237         case cisme_MessageType_CUR_CALIBRATION_REQ:
01238             wifiEventsHandleCurCalibrationReq(message.msg, message.msgLen);
01239             break;
01240         case cisme_MessageType_TEMP_CALIBRATION_ACCEPT_REQ:
01241             wifiEventsHandleTempCalAcceptReq(message.msg, message.msgLen);
01242             break;
01243         case cisme_MessageType_PH_CALIBRATION_ACCEPT_REQ:
01244             wifiEventsHandlePhCalAcceptReq(message.msg, message.msgLen);
01245             break;
01246         case cisme_MessageType_SET_PUMP_REQ:
01247             wifiEventsHandleSetPumpReq(message.msg, message.msgLen);
01248             break;
01249         case cisme_MessageType_GET_PUMP_REQ:
01250             wifiEventsHandleGetPumpReq();
01251             break;
01252         case cisme_MessageType_SET_LIGHT_REQ:
01253             wifiEventsHandleSetLightReq(message.msg, message.msgLen);
01254             break;
01255         case cisme_MessageType_GET_LIGHT_REQ:
01256             wifiEventsHandleGetLightReq();
01257             break;
01258         case cisme_MessageType_GET_TIME_RSP:
01259             wifiEventsHandleTimeRsp(message.msg, message.msgLen);
01260             break;
01261         case cisme_MessageType_GET_FILES_REQ:
01262             wifiEventsHandleGetFilesReq();
01263             break;
01264         case cisme_MessageType_FILE_DOWNLOAD_REQ:
01265             wifiEventsHandleFileDownloadReq(message.msg, message.msgLen);
01266             break;
01267         case cisme_MessageType_FILE_BLOCK_RSP:
01268             wifiEventsHandleFileBlockRsp(message.msg, message.msgLen);
01269             break;
01270         case cisme_MessageType_FILE_ABORT_IND:
01271             wifiEventsHandleFileAbortInd(message.msg, message.msgLen);
01272             break;
01273         case cisme_MessageType_RAW_DATA_REQ:
01274             wifiEventsHandleRawDataReq();
01275             break;
01276         case cisme_MessageType_PUMP_CALIBRATION_REQ:
01277             wifiEventsHandlePumpCalibrationReq();
01278             break;
01279         case cisme_MessageType_PUMP_CALIBRATION_ACCEPT_REQ:
01280             wifiEventsHandlePumpCalAcceptReq(message.msg, message.msgLen);
01281             break;
01282         default:
01283             ERROR("Unknown message type:%d", genericMsg.type);
01284             break;
01285     }
01286 }
01287 
01288 static void wifiEventsSendFinishExpInd(int32_t id, char* fileName)
01289 {
01290     if (!wifiTcpConnectionActive()) {
01291         return;
01292     }
01293 
01294     cisme_experimentMsg expMsg = cisme_experimentMsg_init_default;
01295     expMsg.has_id = true;
01296     expMsg.id = id;
01297     expMsg.fileName.funcs.encode = &pbEncodeString;
01298     expMsg.fileName.arg = fileName;
01299 
01300     DEBUG1("Send FINISH_EXPERIMENT_IND: id=%d, fileName=%s", expMsg.id, fileName);
01301     wifiEventsSendMsg(cisme_MessageType_FINISH_EXPERIMENT_IND, cisme_experimentMsg_fields, &expMsg);
01302 
01303 }
01304 
01305 void wifiEventsSendErrorsInd(char errors)
01306 {
01307     if (getNoSetBits(errors) == 0) {
01308         return;
01309     }
01310 
01311     cisme_errorMsg errorMsg = cisme_errorMsg_init_default;
01312     errorMsg.has_numErrors = true;
01313     errorMsg.numErrors = getNoSetBits(errors);
01314     errorMsg.errorText.arg = &errors;
01315     errorMsg.errorText.funcs.encode = pbEncodeErrors;
01316 
01317     DEBUG1("Send ERRORS_IND: numErrors=%d", errorMsg.numErrors);
01318     wifiEventsSendMsg(cisme_MessageType_ERRORS_IND, cisme_errorMsg_fields, &errorMsg);
01319 }
01320 
01321 void wifiEventsSendDataExpInd(int32_t step, int32_t timeRemaining, double ph, double o2, double battery, double temperature)
01322 {
01323     if (!wifiTcpConnectionActive()) {
01324         return;
01325     }
01326 
01327     cisme_experimentDataMsg expMsg = cisme_experimentDataMsg_init_default;
01328     expMsg.has_id = true;
01329     expMsg.has_step = true;
01330     expMsg.has_timeRemaining = true;
01331     expMsg.has_ph = true;
01332     expMsg.has_o2 = true;
01333     expMsg.has_battery = true;
01334     expMsg.has_temperature = true;
01335     expMsg.has_lightLevel = true;
01336     expMsg.has_pumpRpm = true;
01337     expMsg.id = currentExpId;
01338     expMsg.step = step;
01339     expMsg.timeRemaining = timeRemaining;
01340     expMsg.ph = ph;
01341     expMsg.o2 = o2;
01342     expMsg.battery = battery;
01343     expMsg.temperature = temperature;
01344     expMsg.lightLevel = lightRead();
01345     expMsg.pumpRpm = pumpSpeed();
01346 
01347     DEBUG1("Send EXPERIMENT_DATA_IND: id=%d, step=%d, timeRemaining=%d, ph=%3.2f, o2=%3.0f, battery=%3.1f, temperature=%2.1f, lightLevel=%d, pumpRpm=%d",
01348            expMsg.id, expMsg.step, expMsg.timeRemaining, expMsg.ph, expMsg.o2, expMsg.battery, expMsg.temperature, expMsg.lightLevel, expMsg.pumpRpm);
01349     wifiEventsSendMsg(cisme_MessageType_EXPERIMENT_DATA_IND, cisme_experimentDataMsg_fields, &expMsg);
01350 
01351 }
01352 
01353 void wifiEventsSendTempCalDataInd(float tempBuffer, float tempVolts)
01354 {
01355     cisme_tempCalibrationDataMsg dataMsg = cisme_tempCalibrationDataMsg_init_default;
01356     dataMsg.has_tempBuffer = true;
01357     dataMsg.tempBuffer = tempBuffer;
01358     dataMsg.has_tempVolts = true;
01359     dataMsg.tempVolts = tempVolts;
01360 
01361     DEBUG1("Send TEMP_CALIBRATION_DATA_IND: tempBuffer=%2.4f, tempVolts=%2.6f", dataMsg.tempBuffer, dataMsg.tempVolts);
01362     wifiEventsSendMsg(cisme_MessageType_TEMP_CALIBRATION_DATA_IND, cisme_tempCalibrationDataMsg_fields, &dataMsg);
01363 }
01364 
01365 void wifiEventsSendPhCalDataInd(float phBuffer, float phVoltsCurrent, float phVoltsAverage)
01366 {
01367     cisme_phCalibrationDataMsg dataMsg = cisme_phCalibrationDataMsg_init_default;
01368     dataMsg.has_phBuffer = true;
01369     dataMsg.phBuffer = phBuffer;
01370     dataMsg.has_phVoltsCurrent = true;
01371     dataMsg.phVoltsCurrent = phVoltsCurrent;
01372     dataMsg.has_phVoltsAverage = true;
01373     dataMsg.phVoltsAverage = phVoltsAverage;
01374 
01375     DEBUG1("Send PH_CALIBRATION_DATA_IND: phBuffer=%2.4f, phVoltsCurrent=%2.6f, phVoltsAverage=%2.6f",
01376            dataMsg.phBuffer, dataMsg.phVoltsCurrent, dataMsg.phVoltsAverage);
01377     wifiEventsSendMsg(cisme_MessageType_PH_CALIBRATION_DATA_IND, cisme_phCalibrationDataMsg_fields, &dataMsg);
01378 }
01379 
01380 void wifiEventsSendPumpCalDataInd(int intensity, int rpm)
01381 {
01382     cisme_pumpCalibrationDataMsg dataMsg = cisme_pumpCalibrationDataMsg_init_default;
01383     dataMsg.has_intensity = true;
01384     dataMsg.intensity = intensity;
01385     dataMsg.has_rpm = true;
01386     dataMsg.rpm = rpm;
01387  
01388     DEBUG1("Send PUMP_CALIBRATION_DATA_IND: intensity=%d, rpm=%d", dataMsg.intensity, dataMsg.rpm);
01389     wifiEventsSendMsg(cisme_MessageType_PUMP_CALIBRATION_DATA_IND, cisme_pumpCalibrationDataMsg_fields, &dataMsg);
01390 }
01391 
01392 void wifiEventsStart(void)
01393 {
01394     bool isTimeRequested = false;
01395 
01396     while(true) {
01397 
01398         if (isExpExecuting && experimentRunUserProgram()) {
01399             INFO("Experiment completed.");
01400             fprintf(currentFile, "Experiment Completed\n");
01401             isExpExecuting = false;
01402             finishExperiment();
01403 
01404             wifiEventsSendFinishExpInd(currentExpId, FileName);
01405         }
01406 
01407         if (!wifiTcpConnectionActive()) {
01408             wait(0.1);
01409             L4=0;
01410             continue;
01411         }
01412 
01413         if (batteryGet() < BATTERY_MIN_LEVEL) {
01414             if (isExpExecuting) {
01415                 fprintf(currentFile, "Experiment Finished due to Low Battery Level\n");
01416                 finishExperiment();
01417                 wifiEventsSendFinishExpInd(currentExpId, FileName);
01418             }
01419 
01420             wifiEventsSendErrorsInd(ERROR_BATTERY_LOW);
01421             lightSet(LIGHT_OFF_INTENSITY);
01422             pumpSet(PUMP_OFF_INTENSITY);
01423             return;
01424         }
01425 
01426         if (!isTimeRequested) {
01427             // Request current time
01428             DEBUG1("Send GET_TIME_REQ");
01429             wifiEventsSendMsg(cisme_MessageType_GET_TIME_REQ, NULL, NULL);
01430             wifiEventsSendErrorsInd(startErrors);
01431             isTimeRequested = true;
01432         }
01433 
01434         wifiEventsSendBeatInd();
01435 
01436         wifiEventsHandleMsg();
01437     }
01438 }
01439 
01440 #endif // USE_WIFI