Skip to content
This repository has been archived by the owner on Mar 23, 2024. It is now read-only.

remote transceiver #43

Merged
merged 3 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions lib/cmn_hdrs/shared_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,31 @@
constexpr unsigned int MAX_LOCAL_TO_REMOTE_PAYLOAD_SIZE_BYTES = 270;
constexpr unsigned int MAX_REMOTE_TO_LOCAL_PAYLOAD_SIZE_BYTES = 340;

constexpr int NUM_BATTERIES = 2;
constexpr int NUM_WIND_SENSORS = 2;

/****** Upper and lower bounds ******/
// latitude and longitude

/***** Bounds for Latitude and Longitude ******/
constexpr float LAT_LBND = -90.0;
constexpr float LAT_UBND = 90.0;
constexpr float LON_LBND = -180.0;
constexpr float LON_UBND = 180.0;
// boat speed
constexpr float SPEED_LBND = -10.0; // arbitrary number
constexpr float SPEED_UBND = 10.0; //arbitrary number
// boat heading

/***** Bounds for Speed ******/
constexpr float SPEED_LBND = -10.0; // Placeholder number
constexpr float SPEED_UBND = 10.0; // Placeholder number

/***** Bounds for Heading ******/
constexpr float HEADING_LBND = 0.0;
constexpr float HEADING_UBND = 360.0;

/***** Bounds for Battery ******/
constexpr float VOLT_LBND = 0.5; // Placeholder number
constexpr float VOLT_UBND = 250.0; // Placeholder number
constexpr float CURRENT_LBND = -200.0; // Placeholder number
constexpr float CURRENT_UBND = 200.0; // Placeholder number

/***** Bounds for Wind Sensor ******/
constexpr int DIRECTION_LBND = -180;
constexpr int DIRECTION_UBND = 179;
4 changes: 2 additions & 2 deletions lib/protofiles/sensors.proto
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ message Sensors

message Wind
{
float speed = 1;
uint32 angle = 2;
float speed = 1;
int32 direction = 2;
}

message Battery
Expand Down
21 changes: 21 additions & 0 deletions projects/remote_transceiver/inc/sailbot_db.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,25 @@ class SailbotDB
* @return false on failure
*/
bool storeAis(const ProtoList<Polaris::Sensors::Ais> & ais_ships_pb);

/**
* @brief Adds a generic sensor to the database flow
*
* @return True if sensor is added, false otherwise
*/
bool storeGenericSensor(const ProtoList<Polaris::Sensors::Generic> & generic_pb);

/**
* @brief Adds a battery sensor to the database flow
*
* @return True if sensor is added, false otherwise
*/
bool storeBatteries(const ProtoList<Polaris::Sensors::Battery> & battery_pb);

/**
* @brief Adds a wind sensor to the database flow
*
* @return True if sensor is added, false otherwise
*/
bool storeWindSensor(const ProtoList<Polaris::Sensors::Wind> & wind_pb);
};
43 changes: 42 additions & 1 deletion projects/remote_transceiver/src/sailbot_db.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ bool SailbotDB::testConnection()

bool SailbotDB::storeSensors(const Sensors & sensors_pb)
{
return storeGps(sensors_pb.gps()) && storeAis(sensors_pb.ais_ships());
return storeGps(sensors_pb.gps()) && storeAis(sensors_pb.ais_ships()) &&
storeGenericSensor(sensors_pb.data_sensors()) && storeBatteries(sensors_pb.batteries()) &&
storeWindSensor(sensors_pb.wind_sensors());
}

// END PUBLIC
Expand Down Expand Up @@ -74,4 +76,43 @@ bool SailbotDB::storeAis(const ProtoList<Sensors::Ais> & ais_ships_pb)
return static_cast<bool>(ais_coll.insert_one(ais_ships_doc.view()));
}

bool SailbotDB::storeGenericSensor(const ProtoList<Sensors::Generic> & generic_pb)
{
mongocxx::collection generic_coll = db_[COLLECTION_DATA_SENSORS];
bstream::document doc_builder{};
auto generic_doc_arr = doc_builder << "data_sensors" << bstream::open_array;
for (const Sensors::Generic & generic : generic_pb) {
generic_doc_arr = generic_doc_arr << bstream::open_document << "id" << static_cast<int16_t>(generic.id())
<< "data" << static_cast<int64_t>(generic.data()) << bstream::close_document;
}
DocVal generic_doc = generic_doc_arr << bstream::close_array << bstream::finalize;
return static_cast<bool>(generic_coll.insert_one(generic_doc.view()));
}

bool SailbotDB::storeBatteries(const ProtoList<Sensors::Battery> & battery_pb)
{
mongocxx::collection batteries_coll = db_[COLLECTION_BATTERIES];
bstream::document doc_builder{};
auto batteries_doc_arr = doc_builder << "batteries" << bstream::open_array;
for (const Sensors::Battery & battery : battery_pb) {
batteries_doc_arr = batteries_doc_arr << bstream::open_document << "voltage" << battery.voltage() << "current"
<< battery.current() << bstream::close_document;
}
DocVal batteries_doc = batteries_doc_arr << bstream::close_array << bstream::finalize;
return static_cast<bool>(batteries_coll.insert_one(batteries_doc.view()));
}

bool SailbotDB::storeWindSensor(const ProtoList<Sensors::Wind> & wind_pb)
{
mongocxx::collection wind_coll = db_[COLLECTION_WIND_SENSORS];
bstream::document doc_builder{};
auto wind_doc_arr = doc_builder << "wind_sensors" << bstream::open_array;
for (const Sensors::Wind & wind_sensor : wind_pb) {
wind_doc_arr = wind_doc_arr << bstream::open_document << "speed" << wind_sensor.speed() << "direction"
<< static_cast<int16_t>(wind_sensor.direction()) << bstream::close_document;
}
DocVal wind_doc = wind_doc_arr << bstream::close_array << bstream::finalize;
return static_cast<bool>(wind_coll.insert_one(wind_doc.view()));
}

// END PRIVATE
160 changes: 145 additions & 15 deletions projects/remote_transceiver/test/test_remote_transceiver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,44 +9,47 @@
#include "sensors.pb.h"
#include "shared_constants.h"

static constexpr int NUM_AIS_SHIPS = 15;
static constexpr auto MONGODB_CONN_STR = "mongodb://localhost:27017";
static constexpr int NUM_AIS_SHIPS = 15; // arbitrary number
static constexpr int NUM_GENERIC_SENSORS = 5; // arbitrary number
static constexpr auto MONGODB_CONN_STR = "mongodb://localhost:27017";

using Polaris::Sensors;

/**
* Child class of SailbotDB that includes additional database utility functions to help testing
*/
//Child class of SailbotDB that includes additional database utility functions to help testing
class TestDB : public SailbotDB
{
public:
static constexpr const char * TEST_DB = "test";

TestDB() : SailbotDB(TEST_DB, MONGODB_CONN_STR) {}

/**
* @brief Delete all documents in all collections
*/
void cleanDB()
{
mongocxx::collection gps_coll = db_[COLLECTION_GPS];
mongocxx::collection ais_coll = db_[COLLECTION_AIS_SHIPS];
mongocxx::collection gps_coll = db_[COLLECTION_GPS];
mongocxx::collection ais_coll = db_[COLLECTION_AIS_SHIPS];
mongocxx::collection generic_coll = db_[COLLECTION_DATA_SENSORS];
mongocxx::collection batteries_coll = db_[COLLECTION_BATTERIES];
mongocxx::collection wind_coll = db_[COLLECTION_WIND_SENSORS];

gps_coll.delete_many(bsoncxx::builder::basic::make_document());
ais_coll.delete_many(bsoncxx::builder::basic::make_document());
generic_coll.delete_many(bsoncxx::builder::basic::make_document());
batteries_coll.delete_many(bsoncxx::builder::basic::make_document());
wind_coll.delete_many(bsoncxx::builder::basic::make_document());
}

/**
* @brief Read all sensors from the TestDB
*
* @return Sensors object
* @return Sensors objects: gps, ais, generic, batteries, wind
*/
Sensors dumpSensors()
{
Sensors sensors;

// Protobuf handles freeing of dynamically allocated objects automatically
// NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks)

// gps
mongocxx::collection gps_coll = db_[COLLECTION_GPS];
mongocxx::cursor gps_docs = gps_coll.find({});
EXPECT_EQ(gps_coll.count_documents({}), 1) << "Error: TestDB should only have one document per collection";
Expand All @@ -58,6 +61,7 @@ class TestDB : public SailbotDB
gps->set_speed(static_cast<float>(gps_doc["speed"].get_double().value));
gps->set_heading(static_cast<float>(gps_doc["heading"].get_double().value));

// ais ships
mongocxx::collection ais_coll = db_[COLLECTION_AIS_SHIPS];
mongocxx::cursor ais_docs = ais_coll.find({});
EXPECT_EQ(ais_coll.count_documents({}), 1) << "Error: TestDB should only have one document per collection";
Expand All @@ -72,8 +76,43 @@ class TestDB : public SailbotDB
}
EXPECT_EQ(sensors.ais_ships().size(), NUM_AIS_SHIPS) << "Size mismatch when reading AIS ships from DB";

return sensors;
// generic sensor
mongocxx::collection generic_coll = db_[COLLECTION_DATA_SENSORS];
mongocxx::cursor generic_sensor_doc = generic_coll.find({});
EXPECT_EQ(generic_coll.count_documents({}), 1) << "Error: TestDB should only have one document per collection";
bsoncxx::document::view generic_doc = *(generic_sensor_doc.begin());
for (bsoncxx::array::element generic_doc : generic_doc["data_sensors"].get_array().value) {
Sensors::Generic * generic = sensors.add_data_sensors();
generic->set_id(static_cast<uint8_t>(generic_doc["id"].get_int32().value));
generic->set_data(static_cast<uint64_t>(generic_doc["data"].get_int64().value));
}

// battery
mongocxx::collection batteries_coll = db_[COLLECTION_BATTERIES];
mongocxx::cursor batteries_data_doc = batteries_coll.find({});
EXPECT_EQ(batteries_coll.count_documents({}), 1)
<< "Error: TestDB should only have one document per collection";
bsoncxx::document::view batteries_doc = *(batteries_data_doc.begin());
for (bsoncxx::array::element batteries_doc : batteries_doc["batteries"].get_array().value) {
Sensors::Battery * battery = sensors.add_batteries();
battery->set_voltage(static_cast<float>(batteries_doc["voltage"].get_double().value));
battery->set_current(static_cast<float>(batteries_doc["current"].get_double().value));
}
EXPECT_EQ(sensors.batteries().size(), NUM_BATTERIES) << "Size mismatch when reading batteries from DB";

// wind sensor
mongocxx::collection wind_coll = db_[COLLECTION_WIND_SENSORS];
mongocxx::cursor wind_sensors_doc = wind_coll.find({});
EXPECT_EQ(wind_coll.count_documents({}), 1) << "Error: TestDB should only have one document per collection";
bsoncxx::document::view wind_doc = *(wind_sensors_doc.begin());
for (bsoncxx::array::element wind_doc : wind_doc["wind_sensors"].get_array().value) {
Sensors::Wind * wind = sensors.add_wind_sensors();
wind->set_speed(static_cast<float>(wind_doc["speed"].get_double().value));
wind->set_direction(static_cast<int16_t>(wind_doc["direction"].get_int32().value));
}
EXPECT_EQ(sensors.wind_sensors().size(), NUM_WIND_SENSORS) << "Size mismatch when reading batteries from DB";

return sensors;
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
}
};
Expand All @@ -91,7 +130,7 @@ class TestRemoteTransceiver : public ::testing::Test
};

/**
* @brief Generate random GPS data
* @brief generate random GPS data
*
* @return pointer to generated GPS data
*/
Expand All @@ -111,6 +150,11 @@ Sensors::Gps * genRandGpsData()
return gps_data;
}

/**
* @brief generate random ais ships data
*
* @param ais_ship pointer to generated ais data
*/
void genRandAisData(Sensors::Ais * ais_ship)
{
std::uniform_int_distribution<uint32_t> id_dist(0, UINT32_MAX);
Expand All @@ -126,6 +170,48 @@ void genRandAisData(Sensors::Ais * ais_ship)
ais_ship->set_heading(heading_dist(g_mt));
}

/**
* @brief generate random generic sensor data
*
* @param generic_sensor pointer to generated generic sensor data
*/
void genRandGenericSensorData(Sensors::Generic * generic_sensor)
{
std::uniform_int_distribution<uint8_t> id_generic(0, UINT8_MAX);
std::uniform_int_distribution<uint64_t> data_generic(0, UINT64_MAX);

generic_sensor->set_id(id_generic(g_mt));
generic_sensor->set_data(data_generic(g_mt));
}

/**
* @brief generate random battery data
*
* @param battery pointer to generated battery data
*/
void genRandBatteriesData(Sensors::Battery * battery)
{
std::uniform_real_distribution<float> voltage_battery(VOLT_LBND, VOLT_UBND);
std::uniform_real_distribution<float> current_battery(CURRENT_LBND, CURRENT_UBND);

battery->set_voltage(voltage_battery(g_mt));
battery->set_current(current_battery(g_mt));
}

/**
* @brief generate random wind sensors data
*
* @param wind_data pointer to generated wind sensors data
*/
void genRandWindData(Sensors::Wind * wind_data)
{
std::uniform_real_distribution<float> speed_wind(SPEED_LBND, SPEED_UBND);
std::uniform_int_distribution<int> direction_wind(DIRECTION_LBND, DIRECTION_UBND);

wind_data->set_speed(speed_wind(g_mt));
wind_data->set_direction(direction_wind(g_mt));
}

/**
* @brief Generate random data for all sensors
*
Expand All @@ -136,11 +222,30 @@ Sensors genRandSensors()
Sensors sensors;
// Protobuf handles freeing of dynamically allocated objects automatically
// NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks)

// gps
sensors.set_allocated_gps(genRandGpsData());
// TODO(): Polaris should be included as one of the AIS ships

// ais ships, TODO(): Polaris should be included as one of the AIS ships
for (int i = 0; i < NUM_AIS_SHIPS; i++) {
genRandAisData(sensors.add_ais_ships());
}

// generic sensors
for (int i = 0; i < NUM_GENERIC_SENSORS; i++) {
genRandGenericSensorData(sensors.add_data_sensors());
}

// batteries
for (int i = 0; i < NUM_BATTERIES; i++) {
genRandBatteriesData(sensors.add_batteries());
}

// wind sensors
for (int i = 0; i < NUM_WIND_SENSORS; i++) {
genRandWindData(sensors.add_wind_sensors());
}

return sensors;
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
}
Expand Down Expand Up @@ -168,6 +273,7 @@ TEST_F(TestRemoteTransceiver, TestStoreSensors)
EXPECT_FLOAT_EQ(dumped_sensors.gps().speed(), rand_sensors.gps().speed());
EXPECT_FLOAT_EQ(dumped_sensors.gps().heading(), rand_sensors.gps().heading());

// ais ships
// Array size checking done in dumpSensors
for (int i = 0; i < NUM_AIS_SHIPS; i++) {
const Sensors::Ais & dumped_ais_ships = dumped_sensors.ais_ships(i);
Expand All @@ -178,4 +284,28 @@ TEST_F(TestRemoteTransceiver, TestStoreSensors)
EXPECT_FLOAT_EQ(dumped_ais_ships.speed(), rand_ais_ships.speed());
EXPECT_FLOAT_EQ(dumped_ais_ships.heading(), rand_ais_ships.heading());
}

// generic sensors
for (int i = 0; i < NUM_GENERIC_SENSORS; i++) {
const Sensors::Generic & dumped_data_sensors = dumped_sensors.data_sensors(i);
const Sensors::Generic & rand_data_sensors = rand_sensors.data_sensors(i);
EXPECT_EQ(dumped_data_sensors.id(), rand_data_sensors.id());
EXPECT_EQ(dumped_data_sensors.data(), rand_data_sensors.data());
}

// batteries
for (int i = 0; i < NUM_BATTERIES; i++) {
const Sensors::Battery & dumped_batteries = dumped_sensors.batteries(i);
const Sensors::Battery & rand_batteries = rand_sensors.batteries(i);
EXPECT_EQ(dumped_batteries.voltage(), rand_batteries.voltage());
EXPECT_EQ(dumped_batteries.current(), rand_batteries.current());
}

// wind sensors
for (int i = 0; i < NUM_WIND_SENSORS; i++) {
const Sensors::Wind & dumped_wind_sensors = dumped_sensors.wind_sensors(i);
const Sensors::Wind & rand_wind_sensors = rand_sensors.wind_sensors(i);
EXPECT_EQ(dumped_wind_sensors.speed(), rand_wind_sensors.speed());
EXPECT_EQ(dumped_wind_sensors.direction(), rand_wind_sensors.direction());
}
}