OVMS3/OVMS.V3/components/dbc/src/dbc.cpp

1432 lines
28 KiB
C++

/*
; Project: Open Vehicle Monitor System
; Date: 14th March 2017
;
; Changes:
; 1.0 Initial release
;
; (C) 2011 Michael Stegen / Stegen Electronics
; (C) 2011-2017 Mark Webb-Johnson
; (C) 2011 Sonny Chen @ EPRO/DX
;
; Permission is hereby granted, free of charge, to any person obtaining a copy
; of this software and associated documentation files (the "Software"), to deal
; in the Software without restriction, including without limitation the rights
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
; copies of the Software, and to permit persons to whom the Software is
; furnished to do so, subject to the following conditions:
;
; The above copyright notice and this permission notice shall be included in
; all copies or substantial portions of the Software.
;
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
; THE SOFTWARE.
*/
#include "ovms_log.h"
static const char *TAG = "dbc";
#include <algorithm>
#include <list>
#include <vector>
#include <sstream>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "dbc.h"
#include "dbc_tokeniser.hpp"
#include "dbc_parser.hpp"
#ifdef CONFIG_OVMS
#include "ovms_config.h"
#endif // #ifdef CONFIG_OVMS
// N.B. The conditions on CONFIG_OVMS are to allow this module to be
// compiled and tested outside the OVMS subsystem.
////////////////////////////////////////////////////////////////////////
// Helper functions
static inline uint64_t
dbc_extract_bits(uint8_t *candata, unsigned int bpos, unsigned int align, unsigned int shifter, unsigned int pos)
{
uint64_t val = (uint64_t)candata[bpos/8];
unsigned int mask = (1 << shifter) - 1;
return ((val >> align) & mask) << pos;
}
static uint64_t
dbc_extract_bits_little_endian(uint8_t *candata, unsigned int bpos, unsigned int bits)
{
unsigned int pos, aligner, shifter;
uint64_t val = 0;
pos = 0;
while (bits > 0)
{
aligner = bpos % 8;
shifter = 8 - aligner;
shifter = MIN(shifter, bits);
val |= dbc_extract_bits(candata, bpos, aligner, shifter, pos);
pos += shifter;
bpos += shifter;
bits -= shifter;
}
return val;
}
static uint64_t
dbc_extract_bits_big_endian(uint8_t *candata, unsigned int bpos, unsigned int bits)
{
unsigned int pos, aligner, slicer;
uint64_t val = 0;
pos = bits;
while (bits > 0)
{
slicer = (bpos % 8) + 1;
slicer = MIN(slicer, bits);
aligner = ((bpos % 8) + 1) - slicer;
pos -= slicer;
val |= dbc_extract_bits(candata, bpos, aligner, slicer, pos);
bpos = ((bpos / 8) + 1) * 8 + 7;
bits -= slicer;
}
return val;
}
uint32_t dbcMessageIdFromString(const char* id)
{
uint32_t msgid = 0;
uint32_t mask = 0;
if (*id == 's')
{ mask = 0; id++; }
else if (*id == 'e')
{ mask = 0x80000000; id++; }
msgid = (uint32_t)strtoul(id, NULL, 0);
return msgid | mask;
}
////////////////////////////////////////////////////////////////////////
// dbcComment...
dbcCommentTable::dbcCommentTable()
{
}
dbcCommentTable::~dbcCommentTable()
{
EmptyContent();
}
void dbcCommentTable::AddComment(std::string comment)
{
m_entrymap.push_back(comment);
}
void dbcCommentTable::AddComment(const char* comment)
{
m_entrymap.push_back(std::string(comment));
}
void dbcCommentTable::RemoveComment(std::string comment)
{
m_entrymap.remove(comment);
}
bool dbcCommentTable::HasComment(std::string comment)
{
auto it = std::find(m_entrymap.begin(), m_entrymap.end(), comment);
return (it != m_entrymap.end());
}
void dbcCommentTable::EmptyContent()
{
m_entrymap.clear();
}
void dbcCommentTable::WriteFile(dbcOutputCallback callback,
void* param,
std::string prefix)
{
for (dbcCommentList_t::iterator it=m_entrymap.begin();
it != m_entrymap.end();
++it)
{
callback(param,prefix.c_str());
callback(param,it->c_str());
callback(param,"\"\n");
}
}
////////////////////////////////////////////////////////////////////////
// dbcNewSymbol...
dbcNewSymbolTable::dbcNewSymbolTable()
{
}
dbcNewSymbolTable::~dbcNewSymbolTable()
{
EmptyContent();
}
void dbcNewSymbolTable::AddSymbol(std::string symbol)
{
m_entrymap.push_back(symbol);
}
void dbcNewSymbolTable::AddSymbol(const char* symbol)
{
m_entrymap.push_back(std::string(symbol));
}
void dbcNewSymbolTable::RemoveSymbol(std::string symbol)
{
m_entrymap.remove(symbol);
}
bool dbcNewSymbolTable::HasSymbol(std::string symbol)
{
auto it = std::find(m_entrymap.begin(), m_entrymap.end(), symbol);
return (it != m_entrymap.end());
}
void dbcNewSymbolTable::EmptyContent()
{
m_entrymap.clear();
}
int dbcNewSymbolTable::GetCount()
{
return m_entrymap.size();
}
void dbcNewSymbolTable::WriteFile(dbcOutputCallback callback, void* param)
{
callback(param,"NS_ :");
for (dbcNewSymbolList_t::iterator it=m_entrymap.begin();
it != m_entrymap.end();
++it)
{
callback(param," ");
callback(param,it->c_str());
}
callback(param,"\n\n");
}
////////////////////////////////////////////////////////////////////////
// dbcNode...
dbcNode::dbcNode()
{
}
dbcNode::dbcNode(std::string name)
{
m_name = name;
}
dbcNode::dbcNode(const char* name)
{
m_name = std::string(name);
}
dbcNode::~dbcNode()
{
}
void dbcNode::AddComment(std::string comment)
{
m_comments.AddComment(comment);
}
void dbcNode::AddComment(const char* comment)
{
m_comments.AddComment(std::string(comment));
}
void dbcNode::RemoveComment(std::string comment)
{
m_comments.RemoveComment(comment);
}
bool dbcNode::HasComment(std::string comment)
{
return m_comments.HasComment(comment);
}
const std::string& dbcNode::GetName()
{
return m_name;
}
void dbcNode::SetName(const std::string& name)
{
m_name = name;
}
void dbcNode::SetName(const char* name)
{
m_name = std::string(name);
}
dbcNodeTable::dbcNodeTable()
{
}
dbcNodeTable::~dbcNodeTable()
{
EmptyContent();
}
void dbcNodeTable::AddNode(dbcNode* node)
{
m_entrymap[node->GetName()] = node;
}
void dbcNodeTable::RemoveNode(dbcNode* node, bool free)
{
m_entrymap.erase(node->GetName());
if (free) delete node;
}
dbcNode* dbcNodeTable::FindNode(std::string name)
{
auto search = m_entrymap.find(name);
if (search != m_entrymap.end())
return search->second;
else
return NULL;
}
int dbcNodeTable::GetCount()
{
return m_entrymap.size();
}
void dbcNodeTable::EmptyContent()
{
for (auto it = m_entrymap.begin(); it != m_entrymap.end(); it++)
{
delete it->second;
}
m_entrymap.clear();
}
void dbcNodeTable::WriteFile(dbcOutputCallback callback, void* param)
{
callback(param, "BU_ :");
for (dbcNodeEntry_t::iterator it = m_entrymap.begin();
it != m_entrymap.end();
it++)
{
callback(param," ");
callback(param, it->second->GetName().c_str());
}
callback(param,"\n\n");
}
void dbcNodeTable::WriteFileComments(dbcOutputCallback callback, void* param)
{
std::string prefix;
for (dbcNodeEntry_t::iterator it=m_entrymap.begin();
it != m_entrymap.end();
++it)
{
prefix = std::string("CM_ BU_ ");
prefix.append(it->second->GetName());
prefix.append(" \"");
it->second->m_comments.WriteFile(callback, param, prefix);
}
}
////////////////////////////////////////////////////////////////////////
// dbcBitTiming...
dbcBitTiming::dbcBitTiming()
{
m_baudrate = 0;
m_btr1 = 0;
m_btr2 = 0;
}
dbcBitTiming::~dbcBitTiming()
{
m_baudrate = 0;
m_btr1 = 0;
m_btr2 = 0;
}
void dbcBitTiming::EmptyContent()
{
}
uint32_t dbcBitTiming::GetBaudRate()
{
return m_baudrate;
}
uint32_t dbcBitTiming::GetBTR1()
{
return m_btr1;
}
uint32_t dbcBitTiming::GetBTR2()
{
return m_btr2;
}
void dbcBitTiming::SetBaud(const uint32_t baudrate, const uint32_t btr1, const uint32_t btr2)
{
m_baudrate = baudrate;
m_btr1 = btr1;
m_btr2 = btr2;
}
void dbcBitTiming::WriteFile(dbcOutputCallback callback, void* param)
{
callback(param, "BS_ : ");
if (m_baudrate != 0)
{
char buf[64];
sprintf(buf,"%u:%u,%u",m_baudrate,m_btr1,m_btr2);
callback(param, buf);
}
callback(param, "\n\n");
}
////////////////////////////////////////////////////////////////////////
// dbcValueTable...
dbcValueTable::dbcValueTable()
{
}
dbcValueTable::dbcValueTable(std::string name)
{
m_name = name;
}
dbcValueTable::dbcValueTable(const char* name)
{
m_name = std::string(name);
}
void dbcValueTable::AddValue(uint32_t id, std::string value)
{
m_entrymap[id] = value;
}
void dbcValueTable::AddValue(uint32_t id, const char* value)
{
m_entrymap[id] = std::string(value);
}
void dbcValueTable::RemoveValue(uint32_t id)
{
auto search = m_entrymap.find(id);
if (search != m_entrymap.end())
m_entrymap.erase(search);
}
bool dbcValueTable::HasValue(uint32_t id)
{
auto search = m_entrymap.find(id);
return (search != m_entrymap.end());
}
std::string dbcValueTable::GetValue(uint32_t id)
{
auto search = m_entrymap.find(id);
if (search != m_entrymap.end())
return search->second;
else
return std::string("");
}
const std::string& dbcValueTable::GetName()
{
return m_name;
}
void dbcValueTable::SetName(const std::string& name)
{
m_name = name;
}
void dbcValueTable::SetName(const char* name)
{
m_name = std::string(name);
}
int dbcValueTable::GetCount()
{
return m_entrymap.size();
}
dbcValueTable::~dbcValueTable()
{
EmptyContent();
}
void dbcValueTable::EmptyContent()
{
m_entrymap.clear();
}
void dbcValueTable::WriteFile(dbcOutputCallback callback, void* param, const char* prefix)
{
if (prefix != NULL)
{
callback(param,prefix);
}
else
{
callback(param, "VAL_TABLE_ ");
callback(param, m_name.c_str());
}
for (dbcValueTableEntry_t::iterator it = m_entrymap.begin();
it != m_entrymap.end();
it++)
{
char buf[40];
sprintf(buf," %d \"",it->first);
callback(param,buf);
callback(param,it->second.c_str());
callback(param,"\"");
}
callback(param,";\n");
}
dbcValueTableTable::dbcValueTableTable()
{
}
dbcValueTableTable::~dbcValueTableTable()
{
EmptyContent();
}
void dbcValueTableTable::AddValueTable(std::string name, dbcValueTable* vt)
{
m_entrymap[name] = vt;
}
void dbcValueTableTable::AddValueTable(const char* name, dbcValueTable* vt)
{
m_entrymap[std::string(name)] = vt;
}
void dbcValueTableTable::RemoveValueTable(std::string name, bool free)
{
auto search = m_entrymap.find(name);
if (search != m_entrymap.end())
{
if (free) delete search->second;
m_entrymap.erase(search);
}
}
dbcValueTable* dbcValueTableTable::FindValueTable(std::string name)
{
auto search = m_entrymap.find(name);
if (search != m_entrymap.end())
return search->second;
else
return NULL;
}
void dbcValueTableTable::EmptyContent()
{
dbcValueTableTableEntry_t::iterator it=m_entrymap.begin();
while (it!=m_entrymap.end())
{
delete it->second;
++it;
}
m_entrymap.clear();
}
void dbcValueTableTable::WriteFile(dbcOutputCallback callback, void* param)
{
if (m_entrymap.size() > 0)
{
for (dbcValueTableTableEntry_t::iterator itt = m_entrymap.begin();
itt != m_entrymap.end();
itt++)
itt->second->WriteFile(callback, param, NULL);
callback(param, "\n");
}
}
////////////////////////////////////////////////////////////////////////
// dbcSignal
dbcSignal::dbcSignal()
{
m_start_bit = 0;
m_signal_size = 0;
m_metric = NULL;
}
dbcSignal::dbcSignal(std::string name)
{
m_start_bit = 0;
m_signal_size = 0;
m_name = name;
m_metric = MyMetrics.Find(name.c_str());
}
dbcSignal::~dbcSignal()
{
}
void dbcSignal::AddReceiver(std::string receiver)
{
m_receivers.push_back(receiver);
}
void dbcSignal::RemoveReceiver(std::string receiver)
{
m_receivers.remove(receiver);
}
bool dbcSignal::HasReceiver(std::string receiver)
{
auto it = std::find(m_receivers.begin(), m_receivers.end(), receiver);
return (it != m_receivers.end());
}
void dbcSignal::AddComment(std::string comment)
{
m_comments.AddComment(comment);
}
void dbcSignal::AddComment(const char* comment)
{
m_comments.AddComment(comment);
}
void dbcSignal::RemoveComment(std::string comment)
{
m_comments.RemoveComment(comment);
}
bool dbcSignal::HasComment(std::string comment)
{
return m_comments.HasComment(comment);
}
void dbcSignal::AddValue(uint32_t id, std::string value)
{
m_values.AddValue(id,value);
}
void dbcSignal::RemoveValue(uint32_t id)
{
m_values.RemoveValue(id);
}
bool dbcSignal::HasValue(uint32_t id)
{
return m_values.HasValue(id);
}
std::string dbcSignal::GetValue(uint32_t id)
{
return m_values.GetValue(id);
}
const std::string& dbcSignal::GetName()
{
return m_name;
}
void dbcSignal::SetName(const std::string& name)
{
m_name = name;
std::string mappedname(name);
std::replace( mappedname.begin(), mappedname.end(), '_', '.');
m_metric = MyMetrics.Find(mappedname.c_str());
}
void dbcSignal::SetName(const char* name)
{
SetName(std::string(name));
}
bool dbcSignal::IsMultiplexor()
{
return (m_mux.multiplexed == DBC_MUX_MULTIPLEXOR);
}
bool dbcSignal::IsMultiplexSwitch()
{
return (m_mux.multiplexed == DBC_MUX_MULTIPLEXED);
}
void dbcSignal::SetMultiplexor()
{
m_mux.multiplexed = DBC_MUX_MULTIPLEXOR;
}
uint32_t dbcSignal::GetMultiplexSwitchvalue()
{
return m_mux.switchvalue;
}
bool dbcSignal::SetMultiplexed(const uint32_t switchvalue)
{
if (m_mux.multiplexed == DBC_MUX_MULTIPLEXOR)
{
return false;
}
else
{
m_mux.multiplexed = DBC_MUX_MULTIPLEXED;
m_mux.switchvalue = switchvalue;
return true;
}
}
bool dbcSignal::ClearMultiplexed()
{
if (m_mux.multiplexed == DBC_MUX_MULTIPLEXOR)
{
return false;
}
else
{
m_mux.multiplexed = DBC_MUX_NONE;
m_mux.switchvalue = 0;
return true;
}
}
int dbcSignal::GetStartBit()
{
return m_start_bit;
}
int dbcSignal::GetSignalSize()
{
return m_signal_size;
}
dbcByteOrder_t dbcSignal::GetByteOrder()
{
return m_byte_order;
}
dbcValueType_t dbcSignal::GetValueType()
{
return m_value_type;
}
dbcNumber dbcSignal::GetFactor()
{
return m_factor;
}
dbcNumber dbcSignal::GetOffset()
{
return m_offset;
}
dbcNumber dbcSignal::GetMinimum()
{
return m_minimum;
}
dbcNumber dbcSignal::GetMaximum()
{
return m_maximum;
}
void dbcSignal::SetStartSize(const int startbit, const int size)
{
m_start_bit = startbit;
m_signal_size = size;
}
void dbcSignal::SetByteOrder(const dbcByteOrder_t order)
{
m_byte_order = order;
}
void dbcSignal::SetValueType(const dbcValueType_t type)
{
m_value_type = type;
}
void dbcSignal::SetFactorOffset(const dbcNumber factor, const dbcNumber offset)
{
m_factor = factor;
m_offset = offset;
}
void dbcSignal::SetFactorOffset(const double factor, const double offset)
{
m_factor = factor;
m_offset = offset;
}
void dbcSignal::SetMinMax(const dbcNumber minimum, const dbcNumber maximum)
{
m_minimum = minimum;
m_maximum = maximum;
}
void dbcSignal::SetMinMax(const double minimum, const double maximum)
{
m_minimum = minimum;
m_maximum = maximum;
}
const std::string& dbcSignal::GetUnit()
{
return m_unit;
}
void dbcSignal::SetUnit(const std::string& unit)
{
m_unit = unit;
}
void dbcSignal::SetUnit(const char* unit)
{
m_unit = std::string(unit);
}
void dbcSignal::Encode(dbcNumber* source, CAN_frame_t* msg)
{
// TODO: An efficient encoding of the signal
}
dbcNumber dbcSignal::Decode(CAN_frame_t* msg)
{
uint64_t val;
dbcNumber result;
if (m_byte_order == DBC_BYTEORDER_BIG_ENDIAN)
val = dbc_extract_bits_big_endian(msg->data.u8,m_start_bit,m_signal_size);
else
val = dbc_extract_bits_little_endian(msg->data.u8,m_start_bit,m_signal_size);
if (m_value_type == DBC_VALUETYPE_UNSIGNED)
result.Cast((uint32_t)val, DBC_NUMBER_INTEGER_UNSIGNED);
else {
int32_t signed_val = sign_extend<uint32_t, int32_t>((uint32_t)val, m_signal_size-1);
result.Cast(static_cast<uint32_t>(signed_val), DBC_NUMBER_INTEGER_SIGNED);
}
// Apply factor and offset
if (!(m_factor == 1))
{
result = (result * m_factor);
}
if (!(m_offset == 0))
{
result = (result + m_offset);
}
return result;
}
void dbcSignal::AssignMetric(OvmsMetric* metric)
{
m_metric = metric;
}
OvmsMetric* dbcSignal::GetMetric()
{
return m_metric;
}
void dbcSignal::WriteFile(dbcOutputCallback callback, void* param)
{
std::ostringstream ss;
ss << " SG_ ";
ss << m_name;
switch (m_mux.multiplexed)
{
case DBC_MUX_MULTIPLEXOR:
ss << " M";
break;
case DBC_MUX_MULTIPLEXED:
{
ss << " m";
ss << m_mux.switchvalue;
}
break;
default:
break;
}
ss << " : ";
ss << m_start_bit;
ss << '|';
ss << m_signal_size;
ss << '@';
ss << ((m_byte_order == DBC_BYTEORDER_BIG_ENDIAN)?"0":"1");
ss << ((m_value_type == DBC_VALUETYPE_SIGNED)?"- ":"+ ");
ss << '(';
ss << m_factor;
ss << ',';
ss << m_offset;
ss << ") [";
ss << m_minimum;
ss << '|';
ss << m_maximum;
ss << "] \"";
ss << m_unit;
ss << "\" ";
bool first=true;
for (std::string receiver : m_receivers)
{
if (!first) { ss << ","; }
ss << receiver;
first=false;
}
ss << "\n";
callback(param, ss.str().c_str());
}
void dbcSignal::WriteFileComments(dbcOutputCallback callback,
void* param,
std::string messageid)
{
std::string prefix("CM_ SG_ ");
prefix.append(messageid);
prefix.append(" ");
prefix.append(m_name);
prefix.append(" \"");
m_comments.WriteFile(callback, param, prefix);
}
void dbcSignal::WriteFileValues(dbcOutputCallback callback,
void* param,
std::string messageid)
{
if (m_values.GetCount()>0)
{
std::ostringstream ss;
ss << "VAL_ ";
ss << messageid;
ss << " ";
ss << m_name;
std::string prefix = ss.str();
m_values.WriteFile(callback, param, prefix.c_str());
}
}
////////////////////////////////////////////////////////////////////////
// dbcMessage...
dbcMessage::dbcMessage()
{
m_id = 0;
m_size = 0;
m_multiplexor = NULL;
}
dbcMessage::dbcMessage(uint32_t id)
{
m_size = 0;
m_multiplexor = NULL;
m_id = id;
}
dbcMessage::~dbcMessage()
{
}
void dbcMessage::AddComment(const std::string& comment)
{
m_comments.AddComment(comment);
}
void dbcMessage::AddComment(const char* comment)
{
m_comments.AddComment(comment);
}
void dbcMessage::RemoveComment(const std::string& comment)
{
m_comments.RemoveComment(comment);
}
bool dbcMessage::HasComment(const std::string& comment)
{
return m_comments.HasComment(comment);
}
void dbcMessage::AddSignal(dbcSignal* signal)
{
m_signals.push_back(signal);
}
void dbcMessage::RemoveSignal(dbcSignal* signal, bool free)
{
m_signals.remove(signal);
if (free) delete signal;
}
void dbcMessage::RemoveAllSignals(bool free)
{
for (dbcSignal* signal : m_signals)
{
if (free) delete signal;
}
m_signals.clear();
}
dbcSignal* dbcMessage::FindSignal(std::string name)
{
for (dbcSignal* signal : m_signals)
{
if (signal->GetName().compare(name)==0) return signal;
}
return NULL;
}
void dbcMessage::Count(int* signals, int* bits, int* covered)
{
*bits = m_size*8;
*signals = 0;
*covered = 0;
for (dbcSignal* signal : m_signals)
{
*signals += 1;
*covered += signal->GetSignalSize();
}
}
uint32_t dbcMessage::GetID()
{
return m_id;
}
CAN_frame_format_t dbcMessage::GetFormat()
{
return ((m_id & 0x80000000) == 0)?CAN_frame_std:CAN_frame_ext;
}
bool dbcMessage::IsExtended()
{
return ((m_id & 0x80000000) != 0);
}
bool dbcMessage::IsStandard()
{
return ((m_id & 0x80000000) == 0);
}
void dbcMessage::SetID(const uint32_t id)
{
m_id = id;
}
int dbcMessage::GetSize()
{
return m_size;
}
void dbcMessage::SetSize(const int size)
{
m_size = size;
}
const std::string& dbcMessage::GetName()
{
return m_name;
}
void dbcMessage::SetName(const std::string& name)
{
m_name = name;
}
void dbcMessage::SetName(const char* name)
{
m_name = std::string(name);
}
const std::string& dbcMessage::GetTransmitterNode()
{
return m_transmitter_node;
}
void dbcMessage::SetTransmitterNode(std::string node)
{
m_transmitter_node = node;
}
void dbcMessage::SetTransmitterNode(const char* node)
{
m_transmitter_node = std::string(node);
}
bool dbcMessage::IsMultiplexor()
{
return (m_multiplexor != NULL);
}
dbcSignal* dbcMessage::GetMultiplexorSignal()
{
return m_multiplexor;
}
void dbcMessage::SetMultiplexorSignal(dbcSignal* signal)
{
m_multiplexor = signal;
if (signal != NULL)
{
signal->SetMultiplexor();
}
}
void dbcMessage::WriteFile(dbcOutputCallback callback, void* param)
{
std::ostringstream ss;
ss << "BO_ ";
ss << m_id;
ss << " ";
ss << m_name;
ss << ": ";
ss << m_size;
ss << " ";
ss << m_transmitter_node;
ss << "\n";
callback(param, ss.str().c_str());
for (dbcSignal* signal : m_signals)
{
signal->WriteFile(callback, param);
}
callback(param, "\n");
}
void dbcMessage::WriteFileComments(dbcOutputCallback callback, void* param)
{
std::ostringstream ss;
ss << m_id;
std::string id(ss.str());
std::string prefix("CM_ BO_ ");
prefix.append(id);
prefix.append(" \"");
m_comments.WriteFile(callback, param, prefix);
for (dbcSignal* s : m_signals)
{
s->WriteFileComments(callback, param, id);
}
}
void dbcMessage::WriteFileValues(dbcOutputCallback callback, void* param)
{
std::ostringstream ss;
ss << m_id;
std::string id(ss.str());
for (dbcSignal* s : m_signals)
{
s->WriteFileValues(callback, param, id);
}
}
dbcMessageTable::dbcMessageTable()
{
}
dbcMessageTable::~dbcMessageTable()
{
EmptyContent();
}
void dbcMessageTable::AddMessage(uint32_t id, dbcMessage* message)
{
m_entrymap[id] = message;
}
void dbcMessageTable::RemoveMessage(uint32_t id, bool free)
{
auto search = m_entrymap.find(id);
if (search != m_entrymap.end())
{
if (free) delete search->second;
m_entrymap.erase(search);
}
}
dbcMessage* dbcMessageTable::FindMessage(uint32_t id)
{
auto search = m_entrymap.find(id);
if (search != m_entrymap.end())
return search->second;
else
return NULL;
}
dbcMessage* dbcMessageTable::FindMessage(CAN_frame_format_t format, uint32_t id)
{
if (format == CAN_frame_ext)
id |= 0x80000000;
else
id &= 0x7FFFFFFF;
auto search = m_entrymap.find(id);
if (search != m_entrymap.end())
return search->second;
else
return NULL;
}
void dbcMessageTable::Count(int* messages, int* signals, int* bits, int* covered)
{
*messages = 0;
*signals = 0;
*bits = 0;
*covered = 0;
for (dbcMessageEntry_t::iterator itt = m_entrymap.begin();
itt != m_entrymap.end();
itt++)
{
*messages += 1;
int ms,mb,mc;
itt->second->Count(&ms, &mb, &mc);
*signals += ms;
*bits += mb;
*covered += mc;
}
}
void dbcMessageTable::EmptyContent()
{
dbcMessageEntry_t::iterator it=m_entrymap.begin();
while (it!=m_entrymap.end())
{
delete it->second;
++it;
}
m_entrymap.clear();
}
void dbcMessageTable::WriteFile(dbcOutputCallback callback, void* param)
{
for (dbcMessageEntry_t::iterator itt = m_entrymap.begin();
itt != m_entrymap.end();
itt++)
itt->second->WriteFile(callback, param);
}
void dbcMessageTable::WriteFileComments(dbcOutputCallback callback, void* param)
{
for (dbcMessageEntry_t::iterator it=m_entrymap.begin();
it != m_entrymap.end();
++it)
{
it->second->WriteFileComments(callback, param);
}
for (dbcMessageEntry_t::iterator it=m_entrymap.begin();
it != m_entrymap.end();
++it)
{
it->second->WriteFileValues(callback, param);
}
}
void dbcMessageTable::WriteSummary(dbcOutputCallback callback, void* param)
{
for (dbcMessageEntry_t::iterator itt = m_entrymap.begin();
itt != m_entrymap.end();
itt++)
itt->second->WriteFile(callback, param);
}
////////////////////////////////////////////////////////////////////////
// dbcfile
dbcfile::dbcfile()
{
m_locks = 0;
}
dbcfile::~dbcfile()
{
FreeAllocations();
}
void dbcfile::FreeAllocations()
{
m_version.clear();
m_newsymbols.EmptyContent();
m_bittiming.EmptyContent();
m_nodes.EmptyContent();
m_values.EmptyContent();
m_messages.EmptyContent();
m_comments.EmptyContent();
}
bool dbcfile::LoadFile(const char* name, const char* path, FILE* fd)
{
FreeAllocations();
m_name = std::string(name);
#ifdef CONFIG_OVMS
if (MyConfig.ProtectedPath(path))
{
ESP_LOGW(TAG,"Path %s is protected",path);
return false;
}
#endif // #ifdef CONFIG_OVMS
void yyrestart(FILE *input_file);
int yyparse (void *YYPARSE_PARAM);
bool result;
m_path = path;
if (fd == NULL)
{
fd = fopen(path, "r");
if (!fd)
{
ESP_LOGW(TAG,"Could not open %s for reading",path);
return false;
}
FILE *yyin = fd;
yyrestart(yyin);
result = (yyparse ((void *)this) == 0);
fclose(fd);
}
else
{
fseek(fd,0,SEEK_SET);
FILE *yyin = fd;
yyrestart(yyin);
result = (yyparse ((void *)this) == 0);
fseek(fd,0,SEEK_SET);
}
return result;
}
bool dbcfile::LoadString(const char* name, const char* source, size_t length)
{
FreeAllocations();
m_name = std::string(name);
void yyrestart(FILE *input_file);
int yyparse (void *YYPARSE_PARAM);
YY_BUFFER_STATE buffer = yy_scan_bytes(source, length);
bool result = (yyparse (this) == 0);
yy_delete_buffer(buffer);
return result;
}
void dbcfile::WriteFile(dbcOutputCallback callback, void* param)
{
callback(param,"VERSION \"");
callback(param,m_version.c_str());
callback(param,"\"\n\n");
m_newsymbols.WriteFile(callback, param);
m_bittiming.WriteFile(callback, param);
m_nodes.WriteFile(callback, param);
m_values.WriteFile(callback, param);
m_messages.WriteFile(callback, param);
m_comments.WriteFile(callback, param, std::string("CM_ \""));
m_nodes.WriteFileComments(callback, param);
m_messages.WriteFileComments(callback, param);
}
void dbcfile::WriteSummary(dbcOutputCallback callback, void* param)
{
callback(param,"Path: ");
callback(param,m_path.c_str());
callback(param,"\n");
callback(param,"Version: ");
callback(param,m_version.c_str());
callback(param,"\n\n");
m_messages.WriteSummary(callback, param);
}
std::string dbcfile::Status()
{
std::ostringstream ss;
int messages, signals, bits, covered;
m_messages.Count(&messages, &signals, &bits, &covered);
if (m_version.length() > 0)
{
ss << m_version;
ss << ": ";
}
ss << messages;
ss << " message(s), ";
ss << signals;
ss << " signal(s)";
if (covered>0)
{
ss << ", ";
ss << (int)(covered*100)/bits;
ss << "% coverage";
}
ss << ", ";
ss << m_locks;
ss << " lock(s)";
return ss.str();
}
std::string dbcfile::GetName()
{
return m_name;
}
std::string dbcfile::GetPath()
{
return m_path;
}
std::string dbcfile::GetVersion()
{
return m_version;
}
void dbcfile::LockFile()
{
m_locks++;
}
void dbcfile::UnlockFile()
{
m_locks--;
}
bool dbcfile::IsLocked()
{
return (m_locks > 0);
}