#include "j1939_db.hpp" #include "parsers.hpp" #include #define FMT_HEADER_ONLY #include void initJ1939Database(sqlite::database &db) { db << R"( CREATE TABLE IF NOT EXISTS pgns ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, pgn INTEGER UNIQUE, pg_label TEXT, pg_acronym TEXT, pg_descr TEXT, edp INTEGER, dp INTEGER, pf INTEGER, ps INTEGER, pg_datalen INTEGER, pg_priority INTEGER ); )"; db << R"( CREATE TABLE IF NOT EXISTS spns ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, pgn INTEGER, spn INTEGER UNIQUE, spn_name TEXT, spn_pos TEXT, spn_length INTEGER, resolution REAL, offset REAL, data_range TEXT, min_value REAL, max_value REAL, units TEXT, slot_id TEXT, slot_name TEXT, spn_type TEXT ); )"; db << R"( CREATE TABLE IF NOT EXISTS spn_fragments ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, spn INTEGER, pgn INTEGER, byte_offset INTEGER, bit_offset INTEGER, size INTEGER ); )"; db << "PRAGMA journal_mode = OFF"; db << "PRAGMA synchronous = OFF"; db << "PRAGMA foreign_keys = ON;"; } std::string buildPgnInsertSql() { const auto &pgn_mapping = J1939MappingTables::pgn(); std::string cols, placeholders; for (const auto &[k, v] : pgn_mapping) { if (!cols.empty()) { cols += ", "; placeholders += ", "; } cols += std::get<1u>(v); placeholders += "?"; } return fmt::format("INSERT OR REPLACE INTO pgns ({}) VALUES ({})", cols, placeholders); } std::string buildSpnInsertSql() { const auto &spn_mapping = J1939MappingTables::spn(); std::string cols = "pgn", placeholders = "?"; for (const auto &[k, v] : spn_mapping) { cols += ", "; placeholders += ", "; if (std::get<1u>(v) == "data_range") { cols += "min_value, max_value"; placeholders += "?, ?"; } else { cols += std::get<1u>(v); placeholders += "?"; } } return fmt::format("INSERT OR REPLACE INTO spns ({}) VALUES ({})", cols, placeholders); } void insertJ1939Row(sqlite::database &db, const std::string &pgn_insert_sql, const std::string &spn_insert_sql, std::map &pgn_row_map, std::map &spn_row_map) { const auto &pgn_mapping = J1939MappingTables::pgn(); const auto &spn_mapping = J1939MappingTables::spn(); // Insert PGN try { auto ps = db << pgn_insert_sql; for (const auto &[k, v] : pgn_mapping) { ps << pgn_row_map[std::get<1u>(v).data()]; } ps.execute(); } catch (const sqlite::sqlite_exception &e) { if (e.get_extended_code() != SQLITE_CONSTRAINT_UNIQUE) throw; } // Insert SPN struct { bool parts_inserted_flag = false; double min = 0.0, max = 0.0; size_t size_bits = 0u; } calc; // Pre-compute size_bits { auto it = spn_mapping.find("SPN Length"); if (it != spn_mapping.end()) { auto size = parsers::parseSpnSize(spn_row_map[std::get<1u>(it->second).data()]); calc.size_bits = size.has_value() ? size.value().size_bits : 0u; } } for (const auto &[k, v] : spn_row_map) { try { auto ps = db << spn_insert_sql; ps << pgn_row_map["pgn"]; for (const auto &[k, v] : spn_mapping) { if (std::get<1u>(v) == "data_range") { auto range = parsers::parseSpnDataRange(spn_row_map[std::get<1u>(v).data()]); if (range.has_value()) { calc.min = range.value().min; calc.max = range.value().max; ps << range.value().min << range.value().max; } else { ps << nullptr << nullptr; } } else if (std::get<1u>(v) == "offset") { auto offset = parsers::parseSpnOffset(spn_row_map[std::get<1u>(v).data()]); ps << (offset.has_value() ? offset.value().offset : 0.0); } else if (std::get<1u>(v) == "spn_length") { auto size = parsers::parseSpnSize(spn_row_map[std::get<1u>(v).data()]); calc.size_bits = size.has_value() ? size.value().size_bits : 0u; ps << calc.size_bits; } else if (std::get<1u>(v) == "resolution") { double calculated = (calc.max - calc.min) / (std::pow(2.0, calc.size_bits) - 1.0); if (std::fabs(calculated - 1.0) < 1e-9) { ps << calculated; } else { auto resolution = parsers::parseSpnResolution(spn_row_map[std::get<1u>(v).data()]); ps << (resolution.has_value() ? resolution.value().resolution : 1.0); } } else { ps << spn_row_map[std::get<1u>(v).data()]; } } ps.execute(); // Insert SPN fragments if (!calc.parts_inserted_flag) { auto size = parsers::parseSpnSize(spn_row_map[std::get<1u>(spn_mapping.at("SPN Length")).data()]); if (size.has_value()) { auto spn_fragments = parsers::parseSpnPosition( size.value().size_bits, spn_row_map[std::get<1u>(spn_mapping.at("SPN Position in PG")).data()]); if (spn_fragments.has_value()) { auto spn = std::stoll(spn_row_map["spn"]); for (const auto &part : spn_fragments.value().spn_fragments) { db << R"(INSERT OR REPLACE INTO spn_fragments (spn, pgn, byte_offset, bit_offset, size) VALUES (?, ?, ?, ?, ?);)" << spn << std::stoll(pgn_row_map["pgn"]) << part.byte_offset << part.bit_offset << part.size; } calc.parts_inserted_flag = true; } } } } catch (const sqlite::sqlite_exception &e) { if (e.get_extended_code() != SQLITE_CONSTRAINT_UNIQUE) throw; } } }