diff --git a/.gitignore b/.gitignore index 0f214e3..ee741e7 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ drivers/**/.tmp_versions/ user/**/*.o user/show_ip/show_ip +user/event_sensors/event_sensors user/streaming_sensors/streaming_sensors # ModelSim temporary files diff --git a/user/event_sensors/apds9301.cpp b/user/event_sensors/apds9301.cpp index e9d6f81..8430933 100644 --- a/user/event_sensors/apds9301.cpp +++ b/user/event_sensors/apds9301.cpp @@ -6,21 +6,23 @@ #include "fpga.h" #include "tsu.h" +#include "get_ip.h" -struct APDS9301POD { +struct APDS9301POD +{ uint32_t timestamp_lo; uint32_t timestamp_hi; uint16_t value; } __attribute__((packed)); - -std::string APDS9301::getTopic() const { +std::string APDS9301::getTopic() const +{ static const std::string TOPIC_NAME = "compressed/sensors/apds9301"; return TOPIC_NAME; } - -void APDS9301::doProcess(APDS9301Data const &data) { +void APDS9301::doProcess(APDS9301Data const &data) +{ #ifdef NO_SENSORS // nothing to process here return; @@ -30,24 +32,39 @@ void APDS9301::doProcess(APDS9301Data const &data) { // dimm 7-segment display according to the latest light intensity // - static const int SEGMENT_COUNT = 6; + static const int SEGMENT_COUNT = 6; static const std::string CHARACTER_DEVICE = "/dev/sevensegment"; - uint8_t brightness = data.value >> 8; - uint8_t values[SEGMENT_COUNT] = {0}; + float scale = (float)data.value / UINT16_MAX; + uint8_t brightness = (uint8_t)(scale * UINT8_MAX); + if (brightness < 3) + brightness = 3; + + getIPdata_t getIPdata = {0}; + if (mIP_octet < 3) + mIP_octet++; + else + mIP_octet = 0; + memcpy(&getIPdata, get_ip(mIP_octet), sizeof(getIPdata_t)); auto _lck = lockFPGA(); // open character device auto fd = fopen(CHARACTER_DEVICE.c_str(), "wb"); - if (!fd) { + if (!fd) + { std::cerr << "Failed to open character device '" << CHARACTER_DEVICE << "'" << std::endl; return; } // write display values - for (int i = 0; i < SEGMENT_COUNT; ++i) { - if (fputc(values[i], fd) == EOF) { + for (int i = 0; i < SEGMENT_COUNT; ++i) + { + // Convert to binary for driver + getIPdata.hex_values[i] -= '0'; + + if (fputc(getIPdata.hex_values[i], fd) == EOF) + { std::cerr << "Failed to write character (index " << i << ")" << std::endl; fclose(fd); return; @@ -55,23 +72,26 @@ void APDS9301::doProcess(APDS9301Data const &data) { } // write brightness level - if (fputc(brightness, fd) == EOF) { + if (fputc(brightness, fd) == EOF) + { std::cerr << "Failed to write brightness level" << std::endl; fclose(fd); return; } // write enable bits - if (fputc(0xff, fd) == EOF) { + if (fputc(getIPdata.hex_enable, fd) == EOF) + { std::cerr << "Failed to write enable bits" << std::endl; fclose(fd); return; } - (void) fclose(fd); + (void)fclose(fd); } -std::optional APDS9301::doPoll() { +std::optional APDS9301::doPoll() +{ #ifdef NO_SENSORS static int c = 0; @@ -86,37 +106,39 @@ std::optional APDS9301::doPoll() { static const std::string CHARACTER_DEVICE = "/dev/apds9301"; static const int READ_SIZE = sizeof(APDS9301POD); - APDS9301Data results {}; + APDS9301Data results{}; APDS9301POD pod = {}; - // lock fpga device using a lock guard // the result is never used, but it keeps the mutex locked until it goes out of scope auto _lck = lockFPGA(); // open character device auto fd = fopen(CHARACTER_DEVICE.c_str(), "rb"); - if (!fd) { + if (!fd) + { std::cerr << "Failed to open character device '" << CHARACTER_DEVICE << "'" << std::endl; return {}; } - if (fread(&pod, READ_SIZE, 1, fd) != 1) { + if (fread(&pod, READ_SIZE, 1, fd) != 1) + { std::cerr << "Failed to read sensor values" << std::endl; return {}; } - auto timestamp = (((uint64_t) pod.timestamp_hi) << 32) | pod.timestamp_lo; + auto timestamp = (((uint64_t)pod.timestamp_hi) << 32) | pod.timestamp_lo; results.timeStamp = TimeStampingUnit::getResolvedTimeStamp(timestamp); results.value = pod.value; // close character device - (void) fclose(fd); + (void)fclose(fd); return std::make_optional(results); } -std::string APDS9301Data::toJsonString() const { +std::string APDS9301Data::toJsonString() const +{ std::stringstream ss; ss << "{"; ss << "\"ambient_light\":" << value << ","; diff --git a/user/event_sensors/apds9301.h b/user/event_sensors/apds9301.h index dbfac44..ea2e2e3 100644 --- a/user/event_sensors/apds9301.h +++ b/user/event_sensors/apds9301.h @@ -3,15 +3,16 @@ #include "sensors.h" - -struct APDS9301Data : public Serializable { +struct APDS9301Data : public Serializable +{ std::string toJsonString() const override; uint64_t timeStamp; uint16_t value; }; -class APDS9301 : public StreamingSensor { +class APDS9301 : public StreamingSensor +{ public: using StreamingSensor::StreamingSensor; @@ -20,6 +21,9 @@ class APDS9301 : public StreamingSensor { protected: std::optional doPoll() override; void doProcess(APDS9301Data const &data) override; + +private: + int mIP_octet = 0; }; -#endif // APDS9301_H +#endif // APDS9301_H diff --git a/user/event_sensors/get_ip.cpp b/user/event_sensors/get_ip.cpp new file mode 100644 index 0000000..48c1a00 --- /dev/null +++ b/user/event_sensors/get_ip.cpp @@ -0,0 +1,89 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "get_ip.h" + +using namespace std::literals::chrono_literals; + +struct IPv4Address +{ + uint8_t segments[4]; +}; + +IPv4Address getIPfromSystem() +{ + // drop 127.0.0.1 + static const uint32_t LOCAL_IP = 16777343; + IPv4Address result; + + struct ifaddrs *ifAddrStruct = NULL; + getifaddrs(&ifAddrStruct); + + for (auto ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) + { + if (!ifa->ifa_addr) + { + continue; + } + + if (ifa->ifa_addr->sa_family == AF_INET) + { + auto ip = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; + if (ip == LOCAL_IP) + { + continue; + } + + // use the first non-local IP + for (int i = 0; i < 4; ++i) + { + result.segments[i] = static_cast((ip >> (i * 8)) & 0xff); + } + break; + } + } + + if (ifAddrStruct) + { + freeifaddrs(ifAddrStruct); + } + + return result; +} + +getIPdata_t *get_ip(int hex_index) +{ + auto ip = getIPfromSystem(); + + char chars[7] = {0}; + auto s = ip.segments[hex_index]; + snprintf(chars, 6, "%d", s); + + static getIPdata_t data = {0}; + + for (int i = 0; i < SEGMENT_COUNT; ++i) + { + bool isValidChar = (chars[i] >= '0' && chars[i] <= '9'); + data.hex_enable |= (((int)isValidChar) & 1) << (SEGMENT_COUNT - i - 1); + + if (isValidChar) + { + data.hex_values[i] = chars[i]; + } + else + { + data.hex_values[i] = '0'; + } + } + return &data; +} diff --git a/user/event_sensors/get_ip.h b/user/event_sensors/get_ip.h new file mode 100644 index 0000000..6f8937d --- /dev/null +++ b/user/event_sensors/get_ip.h @@ -0,0 +1,15 @@ +#ifndef GET_IP_H +#define GET_IP_H + +static const std::string CHARACTER_DEVICE = "/dev/sevensegment"; +static const int SEGMENT_COUNT = 6; + +struct getIPdata_t +{ + uint8_t hex_values[SEGMENT_COUNT]; + uint8_t hex_enable; +}; + +getIPdata_t *get_ip(int hex_index); + +#endif // GET_IP_H diff --git a/user/event_sensors/main.cpp b/user/event_sensors/main.cpp index f490697..69d639e 100644 --- a/user/event_sensors/main.cpp +++ b/user/event_sensors/main.cpp @@ -1,6 +1,4 @@ #include -#include -#include #include #include @@ -20,6 +18,7 @@ #include "hdc1000.h" #include "mpu9250.h" #include "sensors.h" +#include "get_ip.h" using namespace std::literals::chrono_literals; @@ -83,17 +82,20 @@ void publishData(const std::vector &data, const std::string &topic, mqtt:: // how many burst packets need to be sent? int bursts = std::ceil(1.0 * data.size() / MAX_PACKETS_PER_BURST); - for (int b = 0; b < bursts; b++) { + for (int b = 0; b < bursts; b++) + { // the size of the current burst packet - int size = std::min(MAX_PACKETS_PER_BURST, (int) data.size() - b * MAX_PACKETS_PER_BURST); + int size = std::min(MAX_PACKETS_PER_BURST, (int)data.size() - b * MAX_PACKETS_PER_BURST); msg.str(""); msg << "["; bool first = true; - for (int i = 0; i < size; i++) { + for (int i = 0; i < size; i++) + { auto &v = data[b * MAX_PACKETS_PER_BURST + i]; - if (!first) { + if (!first) + { msg << ","; } first = false; @@ -110,8 +112,9 @@ void publishData(const std::vector &data, const std::string &topic, mqtt:: } } -template -void publishSensorData(SENSOR &sensor, mqtt::client &client) { +template +void publishSensorData(SENSOR &sensor, mqtt::client &client) +{ auto pollingData = sensor.getQueue(); auto eventData = sensor.getEventQueue(); @@ -129,12 +132,14 @@ std::optional getTrustStore(const std::string &certPath) static const std::string FALLBACK_CERT = "/etc/SmartSystemsLab/ca.crt"; std::ifstream f(certPath); - if (f) { + if (f) + { return certPath; } f.open(FALLBACK_CERT); - if (f) { + if (f) + { std::cout << "Using fallback certificate" << std::endl; return FALLBACK_CERT; } @@ -143,10 +148,10 @@ std::optional getTrustStore(const std::string &certPath) return std::nullopt; } - -int main(int argc, char *argv[]) { - static const std::string SERVER_URI = "ssl://193.170.192.224:8883"; - static const std::string CLIENT_ID = "event_sensors"; +int main(int argc, char *argv[]) +{ + static const std::string SERVER_URI = "193.170.192.224:1883"; + static const std::string CLIENT_ID = "event_sensors"; static const int DEFAULT_THRESHOLD = 12000; // @@ -154,33 +159,42 @@ int main(int argc, char *argv[]) { // int threshold = DEFAULT_THRESHOLD; - if (argc > 2) { + if (argc > 2) + { std::cerr << "Usage: " << argv[0] << " []" << std::endl; return -1; - } else if (argc == 2) { - try { + } + else if (argc == 2) + { + try + { size_t idx = 0; threshold = std::stoi(argv[1], &idx); - if (idx < strlen(argv[1])) { + if (idx < strlen(argv[1])) + { throw std::invalid_argument(argv[1]); } - } catch (const std::invalid_argument &ex) { + } + catch (const std::invalid_argument &ex) + { std::cerr << "Argument '" << argv[1] << "' cannot be parsed as an integer" << std::endl; return -1; } } - // // Check operation mode // #ifndef NO_SENSORS std::cout << "Operation mode: actual sensors" << std::endl; - try { + try + { initFPGA("event_sensors"); - } catch (const std::string &s) { + } + catch (const std::string &s) + { std::cerr << "Failed to initialize FPGA: " << s << std::endl; return -1; } @@ -188,23 +202,11 @@ int main(int argc, char *argv[]) { std::cout << "Operation mode: dummy data" << std::endl; #endif - // // Setup MQTT client // mqtt::client client(SERVER_URI, CLIENT_ID); - mqtt::ssl_options sslOptions; - auto trustStoreOpt = getTrustStore("ca.crt"); - if (!trustStoreOpt.has_value()) { - return -1; - } - sslOptions.set_trust_store(trustStoreOpt.value()); - - mqtt::connect_options options; - options.set_ssl(sslOptions); - - client.connect(options); - + client.connect(); // // Setup sensors @@ -219,12 +221,12 @@ int main(int argc, char *argv[]) { sensorThreads.emplace_back(std::bind(&MPU9250::startPolling, &mpu9250)); sensorThreads.emplace_back(std::bind(&APDS9301::startPolling, &apds9301)); - // // Every second publish all available sensor data at once // auto iterationEnd = std::chrono::high_resolution_clock::now(); - while (true) { + while (true) + { iterationEnd += std::chrono::milliseconds(1000); // std::cout << "HDC1000: "; @@ -244,7 +246,8 @@ int main(int argc, char *argv[]) { mpu9250.stop(); apds9301.stop(); - for (auto &&t: sensorThreads) { + for (auto &&t : sensorThreads) + { t.join(); } return 0;