#include // write() #include #include #include #include #include #include #include #include #include #include #include #include "pigpio.h" #include #include "mtx2/mtx2.h" #include "nmea/nmea.h" #include "ublox/ublox_cmds.h" #include "ublox/ublox.h" #include "ds18b20/ds18b20.h" #include "ssdv_t.h" #include "cli.h" #include "GLOB.h" #include "gps_distance_t.h" #include "async_log_t.h" #include "pulse_t.h" const char* C_RED = "\033[1;31m"; const char* C_GREEN = "\033[1;32m"; const char* C_MAGENTA = "\033[1;35m"; const char* C_OFF = "\033[0m"; bool G_RUN = true; // keep threads running // value written to /dev/watchdog // '1' enables watchdog // 'V' disables watchdog std::atomic_char G_WATCHDOG_V{'1'}; char _hex(char Character) { char _hexTable[] = "0123456789ABCDEF"; return _hexTable[int(Character)]; } // UKHAS Sentence CRC std::string CRC(std::string i_str) { using std::string; unsigned int CRC = 0xffff; // unsigned int xPolynomial = 0x1021; for (size_t i = 0; i < i_str.length(); i++) { CRC ^= (((unsigned int)i_str[i]) << 8); for (int j=0; j<8; j++) { if (CRC & 0x8000) CRC = (CRC << 1) ^ 0x1021; else CRC <<= 1; } } string result; result += _hex((CRC >> 12) & 15); result += _hex((CRC >> 8) & 15); result += _hex((CRC >> 4) & 15); result += _hex(CRC & 15); return result; } zmq::message_t make_zmq_reply(const std::string& i_msg_str) { auto& G = GLOB::get(); if(i_msg_str == "nmea_current") { std::string reply_str = G.nmea_current().json(); reply_str.pop_back(); reply_str += ",'fixAge':" + std::to_string(G.gps_fix_age()) + "}"; zmq::message_t reply( reply_str.size() ); memcpy( (void*) reply.data(), reply_str.c_str(), reply_str.size() ); return reply; } else if(i_msg_str == "nmea_last_valid") { std::string reply_str = G.nmea_last_valid().json(); reply_str.pop_back(); reply_str += ",'fixAge':" + std::to_string(G.gps_fix_age()) + "}"; zmq::message_t reply( reply_str.size() ); memcpy( (void*) reply.data(), reply_str.c_str(), reply_str.size() ); return reply; } else if(i_msg_str == "dynamics") { std::string reply_str("{"); for(auto& dyn_name : G.dynamics_keys()) reply_str += "'" + dyn_name + "':" + G.dynamics_get(dyn_name).json() + ","; reply_str.pop_back(); // last comma reply_str += "}"; zmq::message_t reply( reply_str.size() ); memcpy( (void*) reply.data(), reply_str.c_str(), reply_str.size() ); return reply; } else if(i_msg_str == "flight_state") { std::string reply_str("{'flight_state':"); switch( G.flight_state_get() ) { case flight_state_t::kUnknown: reply_str += "'kUnknown'"; break; case flight_state_t::kStandBy: reply_str += "'kStandBy'"; break; case flight_state_t::kAscend: reply_str += "'kAscend'"; break; case flight_state_t::kDescend: reply_str += "'kDescend'"; break; case flight_state_t::kFreefall: reply_str += "'kFreefall'"; break; case flight_state_t::kLanded: reply_str += "'kLanded'"; break; } reply_str += "}"; zmq::message_t reply( reply_str.size() ); memcpy( (void*) reply.data(), reply_str.c_str(), reply_str.size() ); return reply; } else { zmq::message_t reply( 7 ); memcpy( (void*) reply.data(), "UNKNOWN", 7 ); return reply; } } void watchdog_reset() { char v = G_WATCHDOG_V.load(); // std::cout<<"watchdog_reset "< ublox_data = uBLOX_read_msg(uBlox_i2c_fd); // typical blocking time: 0/1/1.2 seconds const string nmea_str = NMEA_get_last_msg(ublox_data.data(), ublox_data.size()); // cout< 30 ) { current_nmea.lat = GLOB::get().cli.lat + 0.0001 * (GLOB::get().runtime_secs_ - 30); current_nmea.lon = GLOB::get().cli.lon + 0.0001 * (GLOB::get().runtime_secs_ - 30); current_nmea.alt = GLOB::get().cli.alt + 35000.0 * abs(sin(3.1415 * float(GLOB::get().runtime_secs_-30) / 300)); } else { current_nmea.lat = GLOB::get().cli.lat; current_nmea.lon = GLOB::get().cli.lon; current_nmea.alt = GLOB::get().cli.alt; } GLOB::get().nmea_set(current_nmea); GLOB::get().gps_fix_now(); // typical time since uBlox msg read to here is under 1 millisecond GLOB::get().dynamics_add("alt", std::chrono::steady_clock::now(), current_nmea.alt); this_thread::sleep_for(chrono::seconds(1)); } }; // GPS thread. uBLOX or faked // LOG.log("main.log", "GPS thread start"); function gps_loop(ublox_loop); if(G.cli.testgps) gps_loop = function(fake_gps_loop); std::thread ublox_thread( gps_loop ); // DS18B20 temp sensor // const string ds18b20_device = find_ds18b20_device(); if(ds18b20_device == "") { cerr<(chrono::steady_clock::now() - START_TIME).count(); const nmea_t nmea = GLOB::get().nmea_last_valid(); const auto dist_from_home = calc_gps_distance( nmea.lat, nmea.lon, nmea.alt, GLOB::get().cli.lat, GLOB::get().cli.lon, 0); const auto alt = GLOB::get().dynamics_get("alt"); const auto dAltAvg = alt.dVdT_avg(); flight_state_t flight_state = flight_state_t::kUnknown; if(nmea.valid()) { if( abs(dist_from_home.dist_line_) < 200 and abs(dAltAvg) <= 3 ) flight_state = flight_state_t::kStandBy; else if( abs(dist_from_home.dist_line_) > 2000 and abs(dAltAvg) <= 3 and alt.val() < 2000 ) flight_state = flight_state_t::kLanded; else if(dAltAvg < -15) flight_state = flight_state_t::kFreefall; else if(dAltAvg < 0) flight_state = flight_state_t::kDescend; else if(dAltAvg >= 0) flight_state = flight_state_t::kAscend; } // cout< REBOOT // const bool use_watchdog = G.cli.watchdog; std::thread pulse_watch_thread([&LOG, &PULSE, use_watchdog]() { if(not use_watchdog) return; LOG.log("main.log", "PULSE watch thread start"); while(G_RUN) { this_thread::sleep_for(chrono::seconds(3)); auto age_proc = PULSE.get_oldest_ping_age(); float age_secs = float(std::get<0>(age_proc)) / 1e6; std::string proc = std::get<1>(age_proc); if(age_secs<15) { watchdog_reset(); } else { cout<<"PULSE: WATCHDOG RESET HOLD !!! process:"<; if(!res.has_value()) continue; string msg_str( (char*)msg.data(), msg.size() ); zmq_socket.send( make_zmq_reply(msg_str), zmq::send_flags::none ); } }); // read last emited message ID and resume from that number int msg_id = 0; FILE* msgid_fh = fopen("./tracker.msgid", "r"); if(msgid_fh) { fscanf(msgid_fh, "%d", &msg_id); msg_id += 10; // on power failure, last msg_id could be not written to disk fclose(msgid_fh); cout<<"Resume message ID "<(GLOB::get().runtime_secs_); // Sensors: tlmtr_stream<<","<