Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 lightSet(50); 00465 } else { 00466 lightSet(LIGHT_OFF_INTENSITY); 00467 } 00468 00469 if (tempMsg.pumpSpeed) { 00470 pumpSet(50); 00471 } else { 00472 pumpSet(PUMP_OFF_INTENSITY); 00473 } 00474 00475 float bValue = calibrationTemperature(tempMsg.temperature); 00476 00477 // Send response 00478 wifiEventsSendTempCalibrationRsp(bValue); 00479 } 00480 00481 // Apply O2 calibration parameters 00482 static void wifiEventsHandleO2CalibrationReq(uint8_t* msg, size_t msgLen) 00483 { 00484 cisme_o2CalibrationMsg o2Msg = cisme_o2CalibrationMsg_init_default; 00485 pb_istream_t stream = pb_istream_from_buffer(msg, msgLen); 00486 00487 if (!pb_decode(&stream, cisme_o2CalibrationMsg_fields, &o2Msg)) { 00488 ERROR("Can't decode received message"); 00489 return; 00490 } 00491 00492 if (!o2Msg.has_pressure) { 00493 ERROR("Missing pressure field in O2_CALIBRATION_REQ"); 00494 return; 00495 } 00496 00497 if (!o2Msg.has_led) { 00498 ERROR("Missing led field in O2_CALIBRATION_REQ"); 00499 return; 00500 } 00501 00502 if (!o2Msg.has_phase1) { 00503 ERROR("Missing phase1 field in O2_CALIBRATION_REQ"); 00504 return; 00505 } 00506 00507 if (!o2Msg.has_temperature1) { 00508 ERROR("Missing temperature1 field in O2_CALIBRATION_REQ"); 00509 return; 00510 } 00511 00512 if (!o2Msg.has_phase2) { 00513 ERROR("Missing phase2 field in O2_CALIBRATION_REQ"); 00514 return; 00515 } 00516 00517 if (!o2Msg.has_temperature2) { 00518 ERROR("Missing temperature2 field in O2_CALIBRATION_REQ"); 00519 return; 00520 } 00521 00522 DEBUG1("Receive O2_CALIBRATION_REQ: pressure=%1.2f, led=%1.2f, phase1=%1.2f, temperature1=%1.2f, phase2=%1.2f, temperature2=%1.2f", 00523 o2Msg.pressure, o2Msg.led, o2Msg.phase1, o2Msg.temperature1, o2Msg.phase2, o2Msg.temperature2); 00524 00525 // Set parameters 00526 PresCal = o2Msg.pressure; 00527 PhaseCal1 = o2Msg.phase1; 00528 TempCal1 = o2Msg.temperature1; 00529 PhaseCal2 = o2Msg.phase2; 00530 TempCal2 = o2Msg.temperature2; 00531 LEDCurrent = o2Msg.led; 00532 00533 // Apply parameters 00534 calibrationO2(); 00535 00536 // Send response 00537 DEBUG1("Send O2_CALIBRATION_RSP: pressure=%1.2f, led=%1.2f, phase1=%1.2f, temperature1=%1.2f, phase2=%1.2f, temperature2=%1.2f", 00538 o2Msg.pressure, o2Msg.led, o2Msg.phase1, o2Msg.temperature1, o2Msg.phase2, o2Msg.temperature2); 00539 wifiEventsSendMsg(cisme_MessageType_O2_CALIBRATION_RSP, cisme_o2CalibrationMsg_fields, &o2Msg); 00540 } 00541 00542 // Handle request to calibrate PH 00543 static void wifiEventsHandlePhCalibrationReq(uint8_t* msg, size_t msgLen) 00544 { 00545 cisme_phCalibrationMsg phMsg = cisme_phCalibrationMsg_init_default; 00546 pb_istream_t stream = pb_istream_from_buffer(msg, msgLen); 00547 00548 if (!pb_decode(&stream, cisme_phCalibrationMsg_fields, &phMsg)) { 00549 ERROR("Can't decode received message"); 00550 return; 00551 } 00552 00553 if (!phMsg.has_ph) { 00554 ERROR("Missing ph field in PH_CALIBRATION_REQ"); 00555 return; 00556 } 00557 00558 DEBUG1("Receive PH_CALIBRATION_REQ: ph=%2.3f, lightLevel=%d, pumpSpeed=%d", 00559 phMsg.ph, phMsg.lightLevel, phMsg.pumpSpeed); 00560 00561 // Set light and pump intensity 00562 if (phMsg.lightLevel) { 00563 lightSet(50); 00564 } else { 00565 lightSet(LIGHT_OFF_INTENSITY); 00566 } 00567 00568 if (phMsg.pumpSpeed) { 00569 pumpSet(intensity); 00570 } else { 00571 pumpSet(PUMP_OFF_INTENSITY); 00572 } 00573 00574 // Allocate response 00575 cisme_phCalibrationRspMsg phRsp = cisme_phCalibrationRspMsg_init_default; 00576 phRsp.has_phBuffer = true; 00577 phRsp.has_phTemp = true; 00578 phRsp.has_slope = true; 00579 phRsp.has_eo = true; 00580 phRsp.phBuffer = phMsg.ph; 00581 00582 calibrationPh(phRsp.phBuffer, &phRsp.phTemp, &phRsp.slope, &phRsp.eo, NULL); 00583 00584 // Send response 00585 DEBUG1("Send PH_CALIBRATION_RSP: ph=%2.3f, phTemp=%2.3f, slope=%2.6f, eo=%2.6f", 00586 phRsp.phBuffer, phRsp.phTemp, phRsp.slope, phRsp.eo); 00587 wifiEventsSendMsg(cisme_MessageType_PH_CALIBRATION_RSP, cisme_phCalibrationRspMsg_fields, &phRsp); 00588 } 00589 00590 // Send current PH parameters 00591 static void wifiEventsSendCurCalPh(void) 00592 { 00593 cisme_phCalibrationRspMsg phRsp = cisme_phCalibrationRspMsg_init_default; 00594 phRsp.has_phBuffer = true; 00595 phRsp.has_phTemp = true; 00596 phRsp.has_slope = true; 00597 phRsp.has_eo = true; 00598 phRsp.phBuffer = PHBUFFERF; 00599 phRsp.phTemp = PHTEMPF; 00600 phRsp.slope = MSINGLEPT; 00601 phRsp.eo = EOSINGLEPT; 00602 00603 // Send response 00604 DEBUG1("Send PH_CALIBRATION_RSP: ph=%2.3f, phTemp=%2.3f, slope=%2.6f, eo=%2.6f", 00605 phRsp.phBuffer, phRsp.phTemp, phRsp.slope, phRsp.eo); 00606 wifiEventsSendMsg(cisme_MessageType_PH_CALIBRATION_RSP, cisme_phCalibrationRspMsg_fields, &phRsp); 00607 } 00608 00609 // Send current O2 parameters 00610 static void wifiEventsSendCurCalO2(void) 00611 { 00612 cisme_o2CalibrationMsg o2Msg = cisme_o2CalibrationMsg_init_default; 00613 o2Msg.has_pressure = true; 00614 o2Msg.has_phase1 = true; 00615 o2Msg.has_temperature1 = true; 00616 o2Msg.has_phase2 = true; 00617 o2Msg.has_temperature2 = true; 00618 o2Msg.has_led = true; 00619 o2Msg.pressure = PresCal; 00620 o2Msg.phase1 = PhaseCal1; 00621 o2Msg.temperature1 = TempCal1; 00622 o2Msg.phase2 = PhaseCal2; 00623 o2Msg.temperature2 = TempCal2; 00624 o2Msg.led = LEDCurrent; 00625 00626 // Send response 00627 DEBUG1("Send O2_CALIBRATION_RSP: pressure=%1.2f, led=%1.2f, phase1=%1.2f, temperature1=%1.2f, phase2=%1.2f, temperature2=%1.2f", 00628 o2Msg.pressure, o2Msg.led, o2Msg.phase1, o2Msg.temperature1, o2Msg.phase2, o2Msg.temperature2); 00629 wifiEventsSendMsg(cisme_MessageType_O2_CALIBRATION_RSP, cisme_o2CalibrationMsg_fields, &o2Msg); 00630 } 00631 00632 static void sendPumpCalibrationRsp(float aValue, float bValue, float cValue) 00633 { 00634 cisme_pumpCalibrationMsg rspMsg = cisme_pumpCalibrationMsg_init_default; 00635 rspMsg.has_a = true; 00636 rspMsg.has_b = true; 00637 rspMsg.has_c = true; 00638 rspMsg.a = aValue; 00639 rspMsg.b = bValue; 00640 rspMsg.c = cValue; 00641 00642 DEBUG1("Send PUMP_CALIBRATION_RSP: a=%f, b=%f, c=%f", rspMsg.a, rspMsg.b, rspMsg.c); 00643 wifiEventsSendMsg(cisme_MessageType_PUMP_CALIBRATION_RSP, cisme_pumpCalibrationMsg_fields, &rspMsg); 00644 } 00645 00646 // Handle request to get current calibrated parameters 00647 static void wifiEventsHandleCurCalibrationReq(uint8_t* msg, size_t msgLen) 00648 { 00649 cisme_currentCalibrationMsg calMsg = cisme_currentCalibrationMsg_init_default; 00650 pb_istream_t stream = pb_istream_from_buffer(msg, msgLen); 00651 00652 if (!pb_decode(&stream, cisme_currentCalibrationMsg_fields, &calMsg)) { 00653 ERROR("Can't decode received message"); 00654 return; 00655 } 00656 00657 if (!calMsg.has_type) { 00658 calMsg.type = cisme_CalibrationType_PH; 00659 } 00660 00661 DEBUG1("Receive CUR_CALIBRATION_REQ: type=%d", calMsg.type); 00662 00663 switch(calMsg.type) { 00664 case cisme_CalibrationType_PH: 00665 wifiEventsSendCurCalPh(); 00666 break; 00667 case cisme_CalibrationType_TEMPERATURE: 00668 wifiEventsSendTempCalibrationRsp(B); 00669 break; 00670 case cisme_CalibrationType_O2: 00671 wifiEventsSendCurCalO2(); 00672 break; 00673 case cisme_CalibrationType_PUMP: { 00674 float a = 0.0; 00675 float b = 0.0; 00676 float c = 0.0; 00677 pumpGetParams(&a, &b, &c); 00678 sendPumpCalibrationRsp(a, b, c); 00679 break; 00680 } 00681 default: 00682 break; 00683 } 00684 } 00685 00686 // Send calibration accept response 00687 static void wifiEventsSendCalAcceptRsp(cisme_CalibrationType type) 00688 { 00689 cisme_currentCalibrationMsg calMsg = cisme_currentCalibrationMsg_init_default; 00690 calMsg.has_type = true; 00691 calMsg.type = type; 00692 00693 DEBUG1("Send CALIBRATION_ACCEPT_RSP: type=%d", calMsg.type); 00694 wifiEventsSendMsg(cisme_MessageType_CALIBRATION_ACCEPT_RSP, cisme_currentCalibrationMsg_fields, &calMsg); 00695 } 00696 00697 // Handle request to save temperature parameters 00698 static void wifiEventsHandleTempCalAcceptReq(uint8_t* msg, size_t msgLen) 00699 { 00700 cisme_tempCalibrationRspMsg tempMsg = cisme_tempCalibrationRspMsg_init_default; 00701 pb_istream_t stream = pb_istream_from_buffer(msg, msgLen); 00702 00703 if (!pb_decode(&stream, cisme_tempCalibrationRspMsg_fields, &tempMsg)) { 00704 ERROR("Can't decode received message"); 00705 return; 00706 } 00707 00708 if (!tempMsg.has_bValue) { 00709 ERROR("Missing bValue field in TEMP_CALIBRATION_ACCEPT_REQ"); 00710 return; 00711 } 00712 00713 DEBUG1("Receive TEMP_CALIBRATION_ACCEPT_REQ: bValue=%2.6f", tempMsg.bValue); 00714 00715 calibrationTemperatureSave(tempMsg.bValue); 00716 00717 // Send response 00718 wifiEventsSendCalAcceptRsp(cisme_CalibrationType_TEMPERATURE); 00719 } 00720 00721 // Handle request to save PH parameters 00722 static void wifiEventsHandlePhCalAcceptReq(uint8_t* msg, size_t msgLen) 00723 { 00724 cisme_phCalibrationRspMsg phMsg = cisme_phCalibrationRspMsg_init_default; 00725 pb_istream_t stream = pb_istream_from_buffer(msg, msgLen); 00726 00727 if (!pb_decode(&stream, cisme_phCalibrationRspMsg_fields, &phMsg)) { 00728 ERROR("Can't decode received message"); 00729 return; 00730 } 00731 00732 if (!phMsg.has_phBuffer) { 00733 ERROR("Missing phBuffer field in PH_CALIBRATION_ACCEPT_REQ"); 00734 return; 00735 } 00736 00737 if (!phMsg.has_slope) { 00738 ERROR("Missing slope field in PH_CALIBRATION_ACCEPT_REQ"); 00739 return; 00740 } 00741 00742 if (!phMsg.has_phTemp) { 00743 ERROR("Missing phTemp field in PH_CALIBRATION_ACCEPT_REQ"); 00744 return; 00745 } 00746 00747 if (!phMsg.has_eo) { 00748 ERROR("Missing eo field in PH_CALIBRATION_ACCEPT_REQ"); 00749 return; 00750 } 00751 00752 DEBUG1("Receive PH_CALIBRATION_ACCEPT_REQ: ph=%2.3f, phTemp=%2.3f, slope=%2.6f, eo=%2.6f", 00753 phMsg.phBuffer, phMsg.phTemp, phMsg.slope, phMsg.eo); 00754 00755 PHBUFFERF = (float)phMsg.phBuffer; 00756 PHTEMPF = (float)phMsg.phTemp; 00757 PHTEMPKF = (float)(phMsg.phTemp + 273.15); 00758 PHVOLTSF = (float)(phMsg.eo + phMsg.slope * phMsg.phBuffer); 00759 MSINGLEPT = (float)phMsg.slope; 00760 EOSINGLEPT = (float)phMsg.eo; 00761 00762 // Send response 00763 wifiEventsSendCalAcceptRsp(cisme_CalibrationType_PH); 00764 00765 // Save parameters and restart board 00766 calibrationPhSave(); 00767 } 00768 00769 // Start experiment 00770 static void wifiEventsHandleStartExpInd(uint8_t* msg, size_t msgLen) 00771 { 00772 cisme_startExperimentMsg expMsg = cisme_startExperimentMsg_init_default; 00773 static char receivedPrefix[256] = {0}; 00774 00775 pb_istream_t stream = pb_istream_from_buffer(msg, msgLen); 00776 if (!pb_decode(&stream, cisme_startExperimentMsg_fields, &expMsg)) { 00777 ERROR("Can't decode received message"); 00778 return; 00779 } 00780 00781 if (!expMsg.has_id) { 00782 ERROR("Missing id field in START_EXPERIMENT_IND"); 00783 return; 00784 } 00785 00786 if (!expMsg.has_stepsCount) { 00787 ERROR("Missing stepsCount field in START_EXPERIMENT_IND"); 00788 return; 00789 } 00790 00791 if (!expMsg.has_salinity) { 00792 ERROR("Missing salinity field in START_EXPERIMENT_IND"); 00793 return; 00794 } 00795 00796 DEBUG1("Receive START_EXPERIMENT_IND: id=%d, experiment=%d, stepsCount=%d, salinity=%d, pumpSpeed=%d repeats=%d", 00797 expMsg.id, expMsg.experiment, expMsg.stepsCount, expMsg.salinity, expMsg.pumpSpeed, expMsg.repeats); 00798 00799 if (isExpExecuting == true && expMsg.id != currentExpId) { 00800 ERROR("Received START_EXPERIMENT_IND with expMsg.id=%d, but already executing experiment id=%d", 00801 expMsg.id, currentExpId); 00802 return; 00803 } 00804 00805 if (expMsg.stepsCount * (1 + expMsg.repeats) > MAX_STEPS_NO) { 00806 expMsg.repeats = (MAX_STEPS_NO / expMsg.stepsCount) - 1; 00807 ERROR("User wants too many steps. Count of repeats decreased to: %d", expMsg.repeats); 00808 } 00809 00810 for (int ix = 0; ix < expMsg.stepsCount * (1 + expMsg.repeats); ix++) { 00811 pgm[ix][0] = expMsg.pumpSpeed; 00812 } 00813 00814 // Decode steps 00815 uint8_t stepIx = 0; 00816 expMsg.steps.funcs.decode = &pbDecodeProgramSteps; 00817 expMsg.steps.arg = &stepIx; 00818 00819 expMsg.filePrefix.funcs.decode = & pbDecodeString; 00820 expMsg.filePrefix.arg = receivedPrefix; 00821 00822 stream = pb_istream_from_buffer(msg, msgLen); 00823 if (!pb_decode(&stream, cisme_startExperimentMsg_fields, &expMsg)) { 00824 ERROR("Can't decode received message"); 00825 return; 00826 } 00827 00828 if (strcmp(receivedPrefix, "") != 0) { 00829 /* User wants some prefix for the file name.*/ 00830 strncpy(FilePrefix, receivedPrefix, FILE_PREFIX_LENGTH); 00831 DEBUG1("User wants prefix:%s", FilePrefix); 00832 } 00833 00834 Salinity = expMsg.salinity; 00835 numberofprograms = expMsg.stepsCount; 00836 currentExpId = expMsg.id; 00837 isExpExecuting = true; 00838 MeasurementTypeVal = PGM; 00839 00840 if (expMsg.has_repeats && expMsg.experiment >= cisme_startExperimentMsg_ExperimentType_RESPIRATION && 00841 expMsg.experiment < cisme_startExperimentMsg_ExperimentType_MULTI && 00842 expMsg.repeats > 0) { 00843 for (int repeatIx = 0; repeatIx < expMsg.repeats; repeatIx++) { 00844 memcpy(&(pgm[numberofprograms * (repeatIx + 1)]), pgm, sizeof(float) * 20 * numberofprograms); 00845 } 00846 00847 numberofprograms *= expMsg.repeats + 1; 00848 } 00849 00850 experimentPrepareUserProgram(); 00851 } 00852 00853 // Handle experiment action (next step or stop) 00854 static void wifiEventsHandleActionExpInd(cisme_MessageType type, uint8_t* msg, size_t msgLen) 00855 { 00856 cisme_experimentMsg expMsg = cisme_experimentMsg_init_default; 00857 00858 pb_istream_t stream = pb_istream_from_buffer(msg, msgLen); 00859 if (!pb_decode(&stream, cisme_experimentMsg_fields, &expMsg)) { 00860 ERROR("Can't decode received message"); 00861 return; 00862 } 00863 00864 if (!expMsg.has_id) { 00865 ERROR("Missing id field in %s", 00866 (type == cisme_MessageType_NEXT_EXPERIMENT_IND) ? "NEXT_EXPERIMENT_IND" : "STOP_EXPERIMENT_IND"); 00867 return; 00868 } 00869 00870 if (isExpExecuting == false) { 00871 /* Not ERROR because this can happen if the message will be received when experiment already finished. */ 00872 INFO("Unexpected actionExpInd. We are not executing experiment right now."); 00873 return; 00874 } 00875 00876 if (expMsg.id != currentExpId) { 00877 ERROR("Unexpected expId received. Received expId=%d currentExpId=%d", expMsg.id, currentExpId); 00878 return; 00879 } 00880 00881 switch (type) { 00882 case cisme_MessageType_NEXT_EXPERIMENT_IND: 00883 SwitchMode = 1; 00884 INFO("Experiment switched by user."); 00885 fprintf(currentFile,"User Advanced Step\n"); 00886 break; 00887 case cisme_MessageType_STOP_EXPERIMENT_IND: 00888 00889 INFO("User Ended Experiment"); 00890 fprintf(currentFile,"User Ended Experiment\n"); 00891 isExpExecuting = false; 00892 00893 finishExperiment(); 00894 00895 wifiEventsSendFinishExpInd(currentExpId, FileName); 00896 break; 00897 default: 00898 ERROR("Unexpected message type received:%d", type); 00899 return; 00900 } 00901 } 00902 00903 // Send file download response 00904 static void wifiEventsSendFileDownloadRsp(int32_t fileId, int32_t numBlocks) 00905 { 00906 cisme_fileDownloadRspMsg fileRsp = cisme_fileDownloadRspMsg_init_default; 00907 fileRsp.has_fileId = true; 00908 fileRsp.has_numBlocks = true; 00909 fileRsp.fileId = fileId; 00910 fileRsp.numBlocks = numBlocks; 00911 00912 DEBUG1("Send FILE_DOWNLOAD_RSP: fileId=%d, numBlocks=%d", fileRsp.fileId, fileRsp.numBlocks); 00913 wifiEventsSendMsg(cisme_MessageType_FILE_DOWNLOAD_RSP, cisme_fileDownloadRspMsg_fields, &fileRsp); 00914 } 00915 00916 // Send file block 00917 static void wifiEventsSendFileBlockReq(int32_t fileId) 00918 { 00919 blockId++; 00920 00921 if (blockId > numBlocks) { 00922 ERROR("Excess file block requested"); 00923 return; 00924 } 00925 00926 cisme_fileBlockMsg blockReq = cisme_fileBlockMsg_init_default; 00927 blockReq.has_fileId = true; 00928 blockReq.has_blockId = true; 00929 blockReq.has_blockSize = true; 00930 blockReq.fileId = fileId; 00931 blockReq.blockId = blockId; 00932 blockReq.blockSize = (blockId < numBlocks) ? FILE_BLOCK_SIZE : (fileLen % FILE_BLOCK_SIZE); 00933 blockReq.blockData.funcs.encode = &pbEncodeFileBlock; 00934 00935 DEBUG1("Send FILE_BLOCK_REQ: fileId=%d, blockId=%d, blockSize=%d", 00936 blockReq.fileId, blockReq.blockId, blockReq.blockSize); 00937 wifiEventsSendMsg(cisme_MessageType_FILE_BLOCK_REQ, cisme_fileBlockMsg_fields, &blockReq); 00938 } 00939 00940 // Send file action (finish or abort) 00941 static void wifiEventsSendFileActionInd(cisme_MessageType type, int32_t fileId) 00942 { 00943 cisme_fileActionMsg actionMsg = cisme_fileActionMsg_init_default; 00944 actionMsg.has_fileId = true; 00945 actionMsg.fileId = fileId; 00946 00947 DEBUG1("Send %s: fileId=%d", 00948 (type == cisme_MessageType_FILE_FINISH_IND) ? "FILE_FINISH_IND" : "FILE_ABORT_IND", 00949 actionMsg.fileId); 00950 wifiEventsSendMsg(type, cisme_fileActionMsg_fields, &actionMsg); 00951 } 00952 00953 // Handle request to download file 00954 static void wifiEventsHandleFileDownloadReq(uint8_t* msg, size_t msgLen) 00955 { 00956 char fileName[FILE_NAME_LENGTH]; 00957 00958 cisme_fileDownloadMsg fileReq = cisme_fileDownloadMsg_init_default; 00959 fileReq.name.funcs.decode = &pbDecodeString; 00960 fileReq.name.arg = fileName; 00961 00962 pb_istream_t stream = pb_istream_from_buffer(msg, msgLen); 00963 if (!pb_decode(&stream, cisme_fileDownloadMsg_fields, &fileReq)) { 00964 ERROR("Can't decode received message"); 00965 return; 00966 } 00967 00968 DEBUG1("Receive FILE_DOWNLOAD_REQ: name=%s", fileName); 00969 00970 if (curFile != NULL) { 00971 INFO("New file download request, abort previous one"); 00972 fclose(curFile); 00973 wifiEventsSendFileActionInd(cisme_MessageType_FILE_ABORT_IND, fileId); 00974 } 00975 00976 char dataname[PATH_TO_FILE_LEN]; 00977 sprintf(dataname, "%s%s", "/" FSNAME "/Data/", fileName); 00978 curFile = fopen(dataname, "rb"); 00979 if (curFile == NULL) { 00980 ERROR("File %s not found", fileName); 00981 return; 00982 } 00983 00984 fseek(curFile, 0, SEEK_END); 00985 fileLen = ftell(curFile); 00986 rewind(curFile); 00987 00988 fileId++; 00989 numBlocks = fileLen / FILE_BLOCK_SIZE; 00990 if (fileLen % FILE_BLOCK_SIZE > 0) { 00991 numBlocks++; 00992 } 00993 00994 wifiEventsSendFileDownloadRsp(fileId, numBlocks); 00995 00996 blockId = 0; 00997 wifiEventsSendFileBlockReq(fileId); 00998 } 00999 01000 // Handle response for block transfer 01001 static void wifiEventsHandleFileBlockRsp(uint8_t* msg, size_t msgLen) 01002 { 01003 cisme_fileBlockRspMsg blockRsp = cisme_fileBlockRspMsg_init_default; 01004 pb_istream_t stream = pb_istream_from_buffer(msg, msgLen); 01005 01006 if (!pb_decode(&stream, cisme_fileBlockRspMsg_fields, &blockRsp)) { 01007 ERROR("Can't decode received message"); 01008 return; 01009 } 01010 01011 if (!blockRsp.has_fileId) { 01012 ERROR("Missing fileId field in FILE_BLOCK_RSP"); 01013 return; 01014 } 01015 01016 if (!blockRsp.has_blockId) { 01017 ERROR("Missing blockId field in FILE_BLOCK_RSP"); 01018 return; 01019 } 01020 01021 DEBUG1("Receive FILE_BLOCK_RSP: fileId=%d, blockId=%d", 01022 blockRsp.fileId, blockRsp.blockId); 01023 01024 if (curFile == NULL) { 01025 ERROR("No file transfer ongoing"); 01026 return; 01027 } 01028 01029 if (fileId != blockRsp.fileId) { 01030 ERROR("Unknown fileId=%d, expected one:%d", blockRsp.fileId, fileId); 01031 01032 // Send abort for both files 01033 wifiEventsSendFileActionInd(cisme_MessageType_FILE_ABORT_IND, fileId); 01034 wifiEventsSendFileActionInd(cisme_MessageType_FILE_ABORT_IND, blockRsp.fileId); 01035 01036 if (curFile != NULL) { 01037 fclose(curFile); 01038 curFile = NULL; 01039 } 01040 return; 01041 } 01042 01043 if (blockId != blockRsp.blockId) { 01044 ERROR("Unknown blockId=%d, expected one:%d", blockRsp.blockId, blockId); 01045 01046 // Send abort for both files 01047 wifiEventsSendFileActionInd(cisme_MessageType_FILE_ABORT_IND, fileId); 01048 01049 if (curFile != NULL) { 01050 fclose(curFile); 01051 curFile = NULL; 01052 } 01053 return; 01054 } 01055 01056 if (blockId == numBlocks) { 01057 fclose(curFile); 01058 curFile = NULL; 01059 wifiEventsSendFileActionInd(cisme_MessageType_FILE_FINISH_IND, fileId); 01060 INFO("File transfer (%d) finished", fileId); 01061 return; 01062 } 01063 01064 wifiEventsSendFileBlockReq(fileId); 01065 } 01066 01067 // Handle file abort 01068 static void wifiEventsHandleFileAbortInd(uint8_t* msg, size_t msgLen) 01069 { 01070 cisme_fileActionMsg actionMsg = cisme_fileActionMsg_init_default; 01071 pb_istream_t stream = pb_istream_from_buffer(msg, msgLen); 01072 01073 if (!pb_decode(&stream, cisme_fileActionMsg_fields, &actionMsg)) { 01074 ERROR("Can't decode received message"); 01075 return; 01076 } 01077 01078 if (!actionMsg.has_fileId) { 01079 ERROR("Missing fileId field in FILE_ABORT_IND"); 01080 return; 01081 } 01082 01083 DEBUG1("Receive FILE_ABORT_IND: fileId=%d", actionMsg.fileId); 01084 01085 if (fileId != actionMsg.fileId) { 01086 ERROR("Unknown fileId=%d, expected one:%d", actionMsg.fileId, fileId); 01087 return; 01088 } 01089 01090 if (curFile == NULL) { 01091 ERROR("No file transfer ongoing"); 01092 return; 01093 } 01094 01095 fclose(curFile); 01096 curFile = NULL; 01097 } 01098 01099 // Get experiments files 01100 static void wifiEventsHandleGetFilesReq(void) 01101 { 01102 DEBUG1("Receive GET_FILES_REQ"); 01103 01104 // Fill and send response 01105 cisme_filesMsg filesMsg = cisme_filesMsg_init_default; 01106 filesMsg.has_numFiles = true; 01107 filesMsg.numFiles = 0; 01108 filesMsg.names.funcs.encode = pbEncodeFiles; 01109 01110 DIR* dir = opendir("/msc/data/"); 01111 struct dirent* entry = NULL; 01112 01113 while ((entry = readdir(dir)) != NULL) { 01114 if (strstr(entry->d_name, ".csv") != NULL) { 01115 filesMsg.numFiles++; 01116 } 01117 } 01118 01119 DEBUG1("Send GET_FILES_RSP: numFiles=%d", filesMsg.numFiles); 01120 wifiEventsSendMsg(cisme_MessageType_GET_FILES_RSP, cisme_filesMsg_fields, &filesMsg); 01121 } 01122 01123 // Handle request for raw data 01124 static void wifiEventsHandleRawDataReq(void) 01125 { 01126 DEBUG1("Receive RAW_DATA_REQ"); 01127 01128 // Prepare and send response 01129 cisme_rawDataMsg rawMsg = cisme_rawDataMsg_init_default; 01130 rawMsg.has_o2 = true; 01131 rawMsg.has_ph = true; 01132 rawMsg.has_o2Amplitude = true; 01133 rawMsg.has_o2Phase = true; 01134 rawMsg.has_phAdcV = true; 01135 rawMsg.has_temperatureAdcV = true; 01136 rawMsg.has_temperature = true; 01137 01138 float presensData[PRESENS_RES_LENGTH]; 01139 presensGetData(presensData); 01140 01141 rawMsg.o2Amplitude = presensData[0]; 01142 rawMsg.o2Phase = presensData[1]; 01143 rawMsg.o2 = presensData[2]; 01144 rawMsg.ph = pHCorrected; 01145 rawMsg.phAdcV = pH; 01146 rawMsg.temperatureAdcV = pHT; 01147 rawMsg.temperature = PHTEMP; 01148 01149 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", 01150 rawMsg.o2Amplitude, rawMsg.o2Phase, rawMsg.o2, rawMsg.ph, rawMsg.phAdcV, rawMsg.temperatureAdcV, rawMsg.temperature); 01151 wifiEventsSendMsg(cisme_MessageType_RAW_DATA_RSP, cisme_rawDataMsg_fields, &rawMsg); 01152 } 01153 01154 // Start pump calibration 01155 static void wifiEventsHandlePumpCalibrationReq(void) 01156 { 01157 DEBUG1("Receive PUMP_CALIBRATION_REQ"); 01158 01159 float a = 0.0; 01160 float b = 0.0; 01161 float c = 0.0; 01162 01163 calibrationPump(&a, &b, &c); 01164 sendPumpCalibrationRsp(a, b, c); 01165 } 01166 01167 // Apply pump calibration parameters 01168 static void wifiEventsHandlePumpCalAcceptReq(uint8_t* msg, size_t msgLen) 01169 { 01170 cisme_pumpCalibrationMsg calMsg = cisme_pumpCalibrationMsg_init_default; 01171 pb_istream_t stream = pb_istream_from_buffer(msg, msgLen); 01172 01173 if (!pb_decode(&stream, cisme_pumpCalibrationMsg_fields, &calMsg)) { 01174 ERROR("Can't decode received message"); 01175 return; 01176 } 01177 01178 DEBUG1("Receive PUMP_CALIBRATION_ACCEPT_REQ: a=%f, b=%f, c=%f", calMsg.a, calMsg.b, calMsg.c); 01179 pumpSetParams(calMsg.a, calMsg.b, calMsg.c); 01180 01181 // Send response 01182 wifiEventsSendCalAcceptRsp(cisme_CalibrationType_PUMP); 01183 } 01184 01185 // Handle message from app 01186 static void wifiEventsHandleMsg(void) 01187 { 01188 uint8_t* buffer; 01189 unsigned int msgLen = wifiGetMessage(&buffer); 01190 01191 if (msgLen == 0) { 01192 return; 01193 } 01194 01195 cisme_genericMsg genericMsg = cisme_genericMsg_init_default; 01196 PbDecodeMessage message = {NULL, 0}; 01197 genericMsg.payload.funcs.decode = pbDecodeMsg; 01198 genericMsg.payload.arg = &message; 01199 01200 for (size_t ix = 0; ix < msgLen; ix++) { 01201 DEBUG1("0x%x", buffer[ix]); 01202 } 01203 01204 pb_istream_t stream = pb_istream_from_buffer(buffer, msgLen); 01205 01206 if (!pb_decode(&stream, cisme_genericMsg_fields, &genericMsg)) { 01207 ERROR("Can't decode received message"); 01208 return; 01209 } 01210 01211 switch (genericMsg.type) { 01212 case cisme_MessageType_INSTRUMENT_ID_REQ: 01213 wifiEventsHandleIdReq(); 01214 break; 01215 case cisme_MessageType_START_EXPERIMENT_IND: 01216 wifiEventsHandleStartExpInd(message.msg, message.msgLen); 01217 break; 01218 case cisme_MessageType_NEXT_EXPERIMENT_IND: 01219 case cisme_MessageType_STOP_EXPERIMENT_IND: 01220 wifiEventsHandleActionExpInd(genericMsg.type, message.msg, message.msgLen); 01221 break; 01222 case cisme_MessageType_TEMP_CALIBRATION_REQ: 01223 wifiEventsHandleTempCalibrationReq(message.msg, message.msgLen); 01224 break; 01225 case cisme_MessageType_O2_CALIBRATION_REQ: 01226 wifiEventsHandleO2CalibrationReq(message.msg, message.msgLen); 01227 break; 01228 case cisme_MessageType_PH_CALIBRATION_REQ: 01229 wifiEventsHandlePhCalibrationReq(message.msg, message.msgLen); 01230 break; 01231 case cisme_MessageType_CUR_CALIBRATION_REQ: 01232 wifiEventsHandleCurCalibrationReq(message.msg, message.msgLen); 01233 break; 01234 case cisme_MessageType_TEMP_CALIBRATION_ACCEPT_REQ: 01235 wifiEventsHandleTempCalAcceptReq(message.msg, message.msgLen); 01236 break; 01237 case cisme_MessageType_PH_CALIBRATION_ACCEPT_REQ: 01238 wifiEventsHandlePhCalAcceptReq(message.msg, message.msgLen); 01239 break; 01240 case cisme_MessageType_SET_PUMP_REQ: 01241 wifiEventsHandleSetPumpReq(message.msg, message.msgLen); 01242 break; 01243 case cisme_MessageType_GET_PUMP_REQ: 01244 wifiEventsHandleGetPumpReq(); 01245 break; 01246 case cisme_MessageType_SET_LIGHT_REQ: 01247 wifiEventsHandleSetLightReq(message.msg, message.msgLen); 01248 break; 01249 case cisme_MessageType_GET_LIGHT_REQ: 01250 wifiEventsHandleGetLightReq(); 01251 break; 01252 case cisme_MessageType_GET_TIME_RSP: 01253 wifiEventsHandleTimeRsp(message.msg, message.msgLen); 01254 break; 01255 case cisme_MessageType_GET_FILES_REQ: 01256 wifiEventsHandleGetFilesReq(); 01257 break; 01258 case cisme_MessageType_FILE_DOWNLOAD_REQ: 01259 wifiEventsHandleFileDownloadReq(message.msg, message.msgLen); 01260 break; 01261 case cisme_MessageType_FILE_BLOCK_RSP: 01262 wifiEventsHandleFileBlockRsp(message.msg, message.msgLen); 01263 break; 01264 case cisme_MessageType_FILE_ABORT_IND: 01265 wifiEventsHandleFileAbortInd(message.msg, message.msgLen); 01266 break; 01267 case cisme_MessageType_RAW_DATA_REQ: 01268 wifiEventsHandleRawDataReq(); 01269 break; 01270 case cisme_MessageType_PUMP_CALIBRATION_REQ: 01271 wifiEventsHandlePumpCalibrationReq(); 01272 break; 01273 case cisme_MessageType_PUMP_CALIBRATION_ACCEPT_REQ: 01274 wifiEventsHandlePumpCalAcceptReq(message.msg, message.msgLen); 01275 break; 01276 default: 01277 ERROR("Unknown message type:%d", genericMsg.type); 01278 break; 01279 } 01280 } 01281 01282 static void wifiEventsSendFinishExpInd(int32_t id, char* fileName) 01283 { 01284 if (!wifiTcpConnectionActive()) { 01285 return; 01286 } 01287 01288 cisme_experimentMsg expMsg = cisme_experimentMsg_init_default; 01289 expMsg.has_id = true; 01290 expMsg.id = id; 01291 expMsg.fileName.funcs.encode = &pbEncodeString; 01292 expMsg.fileName.arg = fileName; 01293 01294 DEBUG1("Send FINISH_EXPERIMENT_IND: id=%d, fileName=%s", expMsg.id, fileName); 01295 wifiEventsSendMsg(cisme_MessageType_FINISH_EXPERIMENT_IND, cisme_experimentMsg_fields, &expMsg); 01296 01297 } 01298 01299 void wifiEventsSendErrorsInd(char errors) 01300 { 01301 if (getNoSetBits(errors) == 0) { 01302 return; 01303 } 01304 01305 cisme_errorMsg errorMsg = cisme_errorMsg_init_default; 01306 errorMsg.has_numErrors = true; 01307 errorMsg.numErrors = getNoSetBits(errors); 01308 errorMsg.errorText.arg = &errors; 01309 errorMsg.errorText.funcs.encode = pbEncodeErrors; 01310 01311 DEBUG1("Send ERRORS_IND: numErrors=%d", errorMsg.numErrors); 01312 wifiEventsSendMsg(cisme_MessageType_ERRORS_IND, cisme_errorMsg_fields, &errorMsg); 01313 } 01314 01315 void wifiEventsSendDataExpInd(int32_t step, int32_t timeRemaining, double ph, double o2, double battery, double temperature) 01316 { 01317 if (!wifiTcpConnectionActive()) { 01318 return; 01319 } 01320 01321 cisme_experimentDataMsg expMsg = cisme_experimentDataMsg_init_default; 01322 expMsg.has_id = true; 01323 expMsg.has_step = true; 01324 expMsg.has_timeRemaining = true; 01325 expMsg.has_ph = true; 01326 expMsg.has_o2 = true; 01327 expMsg.has_battery = true; 01328 expMsg.has_temperature = true; 01329 expMsg.has_lightLevel = true; 01330 expMsg.has_pumpRpm = true; 01331 expMsg.id = currentExpId; 01332 expMsg.step = step; 01333 expMsg.timeRemaining = timeRemaining; 01334 expMsg.ph = ph; 01335 expMsg.o2 = o2; 01336 expMsg.battery = battery; 01337 expMsg.temperature = temperature; 01338 expMsg.lightLevel = lightRead(); 01339 expMsg.pumpRpm = pumpSpeed(); 01340 01341 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", 01342 expMsg.id, expMsg.step, expMsg.timeRemaining, expMsg.ph, expMsg.o2, expMsg.battery, expMsg.temperature, expMsg.lightLevel, expMsg.pumpRpm); 01343 wifiEventsSendMsg(cisme_MessageType_EXPERIMENT_DATA_IND, cisme_experimentDataMsg_fields, &expMsg); 01344 01345 } 01346 01347 void wifiEventsSendTempCalDataInd(float tempBuffer, float tempVolts) 01348 { 01349 cisme_tempCalibrationDataMsg dataMsg = cisme_tempCalibrationDataMsg_init_default; 01350 dataMsg.has_tempBuffer = true; 01351 dataMsg.tempBuffer = tempBuffer; 01352 dataMsg.has_tempVolts = true; 01353 dataMsg.tempVolts = tempVolts; 01354 01355 DEBUG1("Send TEMP_CALIBRATION_DATA_IND: tempBuffer=%2.4f, tempVolts=%2.6f", dataMsg.tempBuffer, dataMsg.tempVolts); 01356 wifiEventsSendMsg(cisme_MessageType_TEMP_CALIBRATION_DATA_IND, cisme_tempCalibrationDataMsg_fields, &dataMsg); 01357 } 01358 01359 void wifiEventsSendPhCalDataInd(float phBuffer, float phVoltsCurrent, float phVoltsAverage) 01360 { 01361 cisme_phCalibrationDataMsg dataMsg = cisme_phCalibrationDataMsg_init_default; 01362 dataMsg.has_phBuffer = true; 01363 dataMsg.phBuffer = phBuffer; 01364 dataMsg.has_phVoltsCurrent = true; 01365 dataMsg.phVoltsCurrent = phVoltsCurrent; 01366 dataMsg.has_phVoltsAverage = true; 01367 dataMsg.phVoltsAverage = phVoltsAverage; 01368 01369 DEBUG1("Send PH_CALIBRATION_DATA_IND: phBuffer=%2.4f, phVoltsCurrent=%2.6f, phVoltsAverage=%2.6f", 01370 dataMsg.phBuffer, dataMsg.phVoltsCurrent, dataMsg.phVoltsAverage); 01371 wifiEventsSendMsg(cisme_MessageType_PH_CALIBRATION_DATA_IND, cisme_phCalibrationDataMsg_fields, &dataMsg); 01372 } 01373 01374 void wifiEventsSendPumpCalDataInd(int intensity, int rpm) 01375 { 01376 cisme_pumpCalibrationDataMsg dataMsg = cisme_pumpCalibrationDataMsg_init_default; 01377 dataMsg.has_intensity = true; 01378 dataMsg.intensity = intensity; 01379 dataMsg.has_rpm = true; 01380 dataMsg.rpm = rpm; 01381 01382 DEBUG1("Send PUMP_CALIBRATION_DATA_IND: intensity=%d, rpm=%d", dataMsg.intensity, dataMsg.rpm); 01383 wifiEventsSendMsg(cisme_MessageType_PUMP_CALIBRATION_DATA_IND, cisme_pumpCalibrationDataMsg_fields, &dataMsg); 01384 } 01385 01386 void wifiEventsStart(void) 01387 { 01388 bool isTimeRequested = false; 01389 01390 while(true) { 01391 01392 if (isExpExecuting && experimentRunUserProgram()) { 01393 INFO("Experiment completed."); 01394 fprintf(currentFile, "Experiment Completed\n"); 01395 isExpExecuting = false; 01396 finishExperiment(); 01397 01398 wifiEventsSendFinishExpInd(currentExpId, FileName); 01399 } 01400 01401 if (!wifiTcpConnectionActive()) { 01402 wait(0.1); 01403 continue; 01404 } 01405 01406 if (batteryGet() < BATTERY_MIN_LEVEL) { 01407 if (isExpExecuting) { 01408 fprintf(currentFile, "Experiment Finished due to Low Battery Level\n"); 01409 finishExperiment(); 01410 wifiEventsSendFinishExpInd(currentExpId, FileName); 01411 } 01412 01413 wifiEventsSendErrorsInd(ERROR_BATTERY_LOW); 01414 lightSet(LIGHT_OFF_INTENSITY); 01415 pumpSet(PUMP_OFF_INTENSITY); 01416 return; 01417 } 01418 01419 if (!isTimeRequested) { 01420 // Request current time 01421 DEBUG1("Send GET_TIME_REQ"); 01422 wifiEventsSendMsg(cisme_MessageType_GET_TIME_REQ, NULL, NULL); 01423 wifiEventsSendErrorsInd(startErrors); 01424 isTimeRequested = true; 01425 } 01426 01427 wifiEventsSendBeatInd(); 01428 01429 wifiEventsHandleMsg(); 01430 } 01431 } 01432 01433 #endif // USE_WIFI
Generated on Tue Sep 27 2022 18:47:00 by
1.7.2