180 lines
5.6 KiB
C++
180 lines
5.6 KiB
C++
#include "j1939_db.hpp"
|
|
#include "parsers.hpp"
|
|
|
|
#include <cmath>
|
|
|
|
#define FMT_HEADER_ONLY
|
|
#include <fmt/format.h>
|
|
|
|
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<std::string, std::string> &pgn_row_map, std::map<std::string, std::string> &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;
|
|
}
|
|
}
|
|
}
|