aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomain Forlot <romain.forlot@iot.bzh>2017-02-17 09:10:10 +0000
committerRomain Forlot <romain.forlot@iot.bzh>2017-02-20 11:14:55 +0000
commit860d6bd4a829ee5aca50b93122474c9bf68fff9d (patch)
tree9439480025436f103c40ba7e15e9a21bd3a51dfc
parent6f6364f74a4c454d096b0525bdb7563783ee80b7 (diff)
Rename header file to hpp.
Change-Id: I399e0c0f39b18e63e254825b6322faf77896a264 Signed-off-by: Romain Forlot <romain.forlot@iot.bzh>
-rw-r--r--src/can-decoder.cpp44
-rw-r--r--src/can-decoder.hpp (renamed from src/can-decoder.h)28
-rw-r--r--src/can-signals.hpp (renamed from src/can-signals.h)0
-rw-r--r--src/can-utils.cpp83
-rw-r--r--src/can-utils.hpp (renamed from src/can-utils.h)89
-rw-r--r--src/can_decode_message.cpp125
-rw-r--r--src/can_reader.cpp2
-rw-r--r--src/low-can-binding.cpp2
-rw-r--r--src/obd2.hpp (renamed from src/obd2.h)0
-rw-r--r--src/timer.hpp (renamed from src/timer.h)0
10 files changed, 200 insertions, 173 deletions
diff --git a/src/can-decoder.cpp b/src/can-decoder.cpp
index 000db2a..0c8c803 100644
--- a/src/can-decoder.cpp
+++ b/src/can-decoder.cpp
@@ -15,23 +15,20 @@
* limitations under the License.
*/
-Decoder::Decoder
+decoder_t::decoder_t()
+ : decoded_value{false, openxc_DynamicField_Type_STRING, false, "", false, 0, false, false}
{
- decoded_value = { .has_type = false,
- .has_numeric_value = false,
- .has_boolean_value = false,
- .has_string_value = false };
}
-float Decoder::parseSignalBitfield(CanSignal* signal, const CanMessage* message)
+float decoder_t::parseSignalBitfield(const CanSignal& signal, const CanMessage& message)
{
return bitfield_parse_float(message->data, CAN_MESSAGE_SIZE,
signal->bitPosition, signal->bitSize, signal->factor,
signal->offset);
}
-openxc_DynamicField Decoder::noopDecoder(CanSignal* signal,
- CanSignal* signals, int signalCount, float value, bool* send)
+openxc_DynamicField decoder_t::noopDecoder(const CanSignal& signal,
+ const CanSignal& signals, float value, bool* send)
{
decoded_value = { .has_type = true,
.type = openxc_DynamicField_Type_NUM,
@@ -40,8 +37,8 @@ openxc_DynamicField Decoder::noopDecoder(CanSignal* signal,
return decoded_value;
}
-openxc_DynamicField Decoder::booleanDecoder(CanSignal* signal,
- CanSignal* signals, int signalCount, float value, bool* send)
+openxc_DynamicField decoder_t::booleanDecoder(const CanSignal& signal,
+ const CanSignal& signals, float value, bool* send)
{
decoded_value = { .has_type = true,
.type = openxc_DynamicField_Type_BOOL,
@@ -50,16 +47,18 @@ openxc_DynamicField Decoder::booleanDecoder(CanSignal* signal,
return decoded_value;
}
-openxc_DynamicField Decoder::ignoreDecoder(CanSignal* signal,
- CanSignal* signals, int signalCount, float value, bool* send)
+openxc_DynamicField decoder_t::ignoreDecoder(const CanSignal& signal,
+ const CanSignal& signals, float value, bool* send)
{
- *send = false;
+ if(send)
+ *send = false;
+
openxc_DynamicField decoded_value = {0};
return decoded_value;
}
-openxc_DynamicField Decoder::stateDecoder(CanSignal* signal,
- CanSignal* signals, int signalCount, float value, bool* send)
+openxc_DynamicField decoder_t::stateDecoder(const CanSignal& signal,
+ const CanSignal& signals, float value, bool* send)
{
openxc_DynamicField decoded_value = {0};
decoded_value.has_type = true;
@@ -68,26 +67,25 @@ openxc_DynamicField Decoder::stateDecoder(CanSignal* signal,
const CanSignalState* signalState = lookupSignalState(value, signal);
if(signalState != NULL) {
- strcpy(decoded_value.string_value, signalState->name);
+ ::strcpy(decoded_value.string_value, signalState->name);
} else {
*send = false;
}
return decoded_value;
}
-openxc_DynamicField Decoder::decodeSignal(CanSignal* signal,
- float value, CanSignal* signals, int signalCount, bool* send)
+openxc_DynamicField decoder_t::decodeSignal(const CanSignal& signal,
+ float value, const CanSignal& signals, bool* send)
{
SignalDecoder decoder = signal->decoder == NULL ?
noopDecoder : signal->decoder;
openxc_DynamicField decoded_value = decoder(signal, signals,
- signalCount, value, send);
+ value, send);
return decoded_value;
}
-openxc_DynamicField Decoder::decodeSignal(CanSignal* signal,
- const CanMessage* message, CanSignal* signals, int signalCount,
- bool* send) {
+openxc_DynamicField decoder_t::decodeSignal(const CanSignal& signal,
+ const CanMessage& message, const CanSignal& signals, bool* send) {
float value = parseSignalBitfield(signal, message);
- return decodeSignal(signal, value, signals, signalCount, send);
+ return decodeSignal(signal, value, signals, send);
} \ No newline at end of file
diff --git a/src/can-decoder.h b/src/can-decoder.hpp
index 3754bae..b6234b5 100644
--- a/src/can-decoder.h
+++ b/src/can-decoder.hpp
@@ -34,7 +34,7 @@ class decoder_t
* Returns the raw value of the signal parsed as a bitfield from the given byte
* array.
*/
- float parseSignalBitfield(CanSignal* signal, const CanMessage* message);
+ float parseSignalBitfield(const CanSignal& signal, const CanMessage& message);
/* Public: Find and return the corresponding string state for a CAN signal's
* raw integer value.
@@ -53,8 +53,8 @@ class decoder_t
* the signal. If an equivalent isn't found, send is sent to false and the
* return value is undefined.
*/
- openxc_DynamicField stateDecoder(CanSignal* signal, CanSignal* signals,
- int signalCount, float value, bool* send);
+ openxc_DynamicField stateDecoder(const CanSignal& signal, const CanSignal& signals,
+ float value, bool* send);
/* Public: Coerces a numerical value to a boolean.
*
@@ -72,8 +72,8 @@ class decoder_t
* is 0.0, otherwise true. The 'send' argument will not be modified as this
* decoder always succeeds.
*/
- openxc_DynamicField booleanDecoder(CanSignal* signal, CanSignal* signals,
- int signalCount, float value, bool* send);
+ openxc_DynamicField booleanDecoder(const CanSignal& signal, const CanSignal& signals,
+ float value, bool* send);
/* Public: Update the metadata for a signal and the newly received value.
*
@@ -91,8 +91,8 @@ class decoder_t
*
* The return value is undefined.
*/
- openxc_DynamicField ignoreDecoder(CanSignal* signal, CanSignal* signals,
- int signalCount, float value, bool* send);
+ openxc_DynamicField ignoreDecoder(const CanSignal& signal, const CanSignal& signals,
+ float value, bool* send);
/* Public: Wrap a raw CAN signal value in a DynamicField without modification.
*
@@ -110,8 +110,8 @@ class decoder_t
* its numeric value. The 'send' argument will not be modified as this decoder
* always succeeds.
*/
- openxc_DynamicField noopDecoder(CanSignal* signal, CanSignal* signals,
- int signalCount, float value, bool* send);
+ openxc_DynamicField noopDecoder(const CanSignal& signal, const CanSignal& signals,
+ float value, bool* send);
/* Public: Parse a signal from a CAN message and apply any required
* transforations to get a human readable value.
@@ -129,18 +129,18 @@ class decoder_t
* The decoder returns an openxc_DynamicField, which may contain a number,
* string or boolean. If 'send' is false, the return value is undefined.
*/
- openxc_DynamicField decodeSignal(CanSignal* signal,
- const CanMessage* message, CanSignal* signals, int signalCount,
+ openxc_DynamicField decodeSignal(const CanSignal& signal,
+ const CanMessage& message, const CanSignal& signals,
bool* send);
/* Public: Decode a transformed, human readable value from an raw CAN signal
* already parsed from a CAN message.
*
- * This is the same as decodeSignal(CanSignal*, CanMessage*, CanSignal*, int,
+ * This is the same as decodeSignal(const CanSignal&, CanMessage*, const CanSignal&, int,
* bool*) but you must parse the bitfield value of the signal from the CAN
* message yourself. This is useful if you need that raw value for something
* else.
*/
- openxc_DynamicField decodeSignal(CanSignal* signal, float value,
- CanSignal* signals, int signalCount, bool* send);
+ openxc_DynamicField decodeSignal(const CanSignal& signal, float value,
+ const CanSignal& signals, bool* send);
} \ No newline at end of file
diff --git a/src/can-signals.h b/src/can-signals.hpp
index f34c743..f34c743 100644
--- a/src/can-signals.h
+++ b/src/can-signals.hpp
diff --git a/src/can-utils.cpp b/src/can-utils.cpp
index e978cae..e41230b 100644
--- a/src/can-utils.cpp
+++ b/src/can-utils.cpp
@@ -23,12 +23,12 @@
*
*********************************************************************************/
-can_bus_t::can_bus_t(afb_binding_interface *itf, const std:string &dev_name)
- : interface{itf}, deviceName{dev_name}
+can_bus_dev_t::can_bus_dev_t(afb_binding_interface *itf, const std:string &dev_name)
+ : interface{itf}, deviceName{dev_name}
{
}
-int can_bus_t::open()
+int can_bus_dev_t::open()
{
const int canfd_on = 1;
struct ifreq ifr;
@@ -81,14 +81,14 @@ int can_bus_t::open()
return -1;
}
-int can_bus_t::close()
+int can_bus_dev_t::close()
{
::close(can_socket_);
can_socket_ = -1;
}
-canfd_frame can_bus_t::can_read()
+canfd_frame can_bus_dev_t::read()
{
ssize_t nbytes;
//int maxdlen;
@@ -124,6 +124,19 @@ canfd_frame can_bus_t::can_read()
return canfd_frame;
}
+/*
+ * Return is_running_ bool
+ */
+bool can_bus_dev_t::is_running()
+{
+ return is_running_;
+}
+
+can_bus_t::can_bus_t(afb_binding_interface *itf, const std:string &dev_name)
+ : interface{itf}
+{
+}
+
void can_bus_t::start_threads()
{
th_reading_ = std::thread(can_reader, interface, socket, can_message_q_);
@@ -134,11 +147,33 @@ void can_bus_t::start_threads()
}
/*
- * Return is_running_ bool
+ * Get a CanMessage from can_message_q and return it
+ * then point to the next CanMessage in queue.
+ *
+ * Return the next queue element or NULL if queue is empty.
*/
-bool can_bus_t::is_running()
+can_message_t can_bus_dev_t::next_can_message()
{
- return is_running_;
+ if(! can_message_q_.empty())
+ {
+ can_message_t can_msg = can_message_q_.front();
+ can_message_q_.pop()
+ return &can_msg;
+ }
+ has_can_message_ = false;
+}
+
+/**
+ * @return has_can_message_ bool
+ */
+bool can_bus_dev_t::has_can_message() const
+{
+ return has_can_message_;
+}
+
+void can_bus_dev_t::push_new_can_message(const can_message_t& can_msg)
+{
+ can_message_q_.push(can_msg);
}
/*
@@ -172,36 +207,6 @@ int can_bus_t::send_can_message(can_message_t &can_msg)
}
/*
- * Get a CanMessage from can_message_q and return it
- * then point to the next CanMessage in queue.
- *
- * Return the next queue element or NULL if queue is empty.
- */
-can_message_t* can_bus_t::next_can_message()
-{
- if(! can_message_q_.empty())
- {
- can_message_t can_msg = can_message_q_.front();
- can_message_q_.pop()
- return &can_msg;
- }
- has_can_message_ = false;
-}
-
-/**
- * @return has_can_message_ bool
- */
-bool can_bus_t::has_can_message() const
-{
- return has_can_message_;
-}
-
-void can_bus_t::insert_new_can_message(can_message_t &can_msg)
-{
- can_message_q_.push(can_msg);
-}
-
-/*
* Get a VehicleMessage from vehicle_message_q and return it
* then point to the next VehicleMessage in queue.
*
@@ -219,7 +224,7 @@ openxc_VehicleMessage* can_bus_t::next_vehicle_message()
has_vehicle_message_ = false;
}
-void can_bus_t::insert_new_vehicle_message(openxc_VehicleMessage *v_msg)
+void can_bus_t::push_new_vehicle_message(const openxc_VehicleMessage& v_msg)
{
vehicle_message_q_.push(v_msg);
has_vehicle_message_ = true;
diff --git a/src/can-utils.h b/src/can-utils.hpp
index 1676392..da5f81c 100644
--- a/src/can-utils.h
+++ b/src/can-utils.hpp
@@ -30,27 +30,6 @@
#define CAN_ACTIVE_TIMEOUT_S 30
-#define QUEUE_DECLARE(type, max_length) \
-static const int queue_##type##_max_length = max_length; \
-static const int queue_##type##_max_internal_length = max_length + 1; \
-typedef struct queue_##type##_s { \
- int head; \
- int tail; \
- type elements[max_length + 1]; \
-} queue_##type; \
-\
-bool queue_##type##_push(queue_##type* queue, type value); \
-\
-type queue_##type##_pop(queue_##type* queue); \
-\
-type queue_##type##_peek(queue_##type* queue); \
-void queue_##type##_init(queue_##type* queue); \
-int queue_##type##_length(queue_##type* queue); \
-int queue_##type##_available(queue_##type* queue); \
-bool queue_##type##_full(queue_##type* queue); \
-bool queue_##type##_empty(queue_##type* queue); \
-void queue_##type##_snapshot(queue_##type* queue, type* snapshot, int max);
-
/* Public: The type signature for a CAN signal decoder.
*
* A SignalDecoder transforms a raw floating point CAN signal into a number,
@@ -69,57 +48,79 @@ void queue_##type##_snapshot(queue_##type* queue, type* snapshot, int max);
typedef openxc_DynamicField (*SignalDecoder)(struct CanSignal* signal,
CanSignal* signals, int signalCount, float value, bool* send);
-/* Public: The type signature for a CAN signal encoder.
+/**
+ * @brief: The type signature for a CAN signal encoder.
*
* A SignalEncoder transforms a number, string or boolean into a raw floating
* point value that fits in the CAN signal.
*
- * signal - The CAN signal to encode.
- * value - The dynamic field to encode.
- * send - An output parameter. If the encoding failed or the CAN signal should
+ * @params[signal] - The CAN signal to encode.
+ * @params[value] - The dynamic field to encode.
+ * @params[send] - An output parameter. If the encoding failed or the CAN signal should
* not be encoded for some other reason, this will be flipped to false.
*/
typedef uint64_t (*SignalEncoder)(struct CanSignal* signal,
openxc_DynamicField* value, bool* send);
-/*
- * CanBus represent a can device definition gotten from configuraiton file
+/**
+ * @brief Object representing a can device. Handle opening, closing and reading on the
+ * socket. This is the low level object to be use by can_bus_t.
+ *
+ * @params[*interface_] - afb_binding_interface to the binder. Used to log messages
+ * @params[device_name_] - name of the linux device handling the can bus. Generally vcan0, can0, etc.
+ *
*/
-class can_bus_t {
+class can_bus_dev_t {
private:
- afb_binding_interface *interface_;
-
- /* Got from conf file */
- std::string device_name;
+ std::string device_name_;
+ int can_socket_;
int can_socket_;
bool is_fdmode_on_;
struct sockaddr_can txAddress_;
+ bool has_can_message_;
+ std::queue <can_message_t> can_message_q_;
+
std::thread th_reading_;
bool is_running_;
+
+ public:
+ int open();
+ int close();
+ bool is_running();
+
+ can_message_t* next_can_message();
+ void push_new_can_message(const can_message_t& can_msg);
+}
+
+
+/**
+ * @brief Object used to handle decoding and manage event queue to be pushed.
+ *
+ * @params[*interface_] - afb_binding_interface to the binder. Used to log messages
+ * @params[conf_file_ifstream_] - stream of configuration file used to initialize
+ * can_bus_dev_t objects.
+ */
+class can_bus_t {
+ private:
+ afb_binding_interface *interface_;
+
+ std::vector<can_bus_dev_t> devices;
+
std::thread th_decoding_;
std::thread th_pushing_;
- std::queue <can_message_t> can_message_q_;
+ bool has_vehicle_message_;
std::queue <openxc_VehicleMessage> vehicle_message_q_;
public:
- int open();
- int close();
-
void start_threads();
- bool is_running();
int send_can_message(can_message_t can_msg);
- can_message_t* next_can_message();
- void insert_new_can_message(can_message_t &can_msg);
- bool has_can_message_;
-
- openxc_VehicleMessage* next_vehicle_message();
- void insert_new_vehicle_message(openxc_VehicleMessage *v_msg);
- bool has_vehicle_message_;
+ openxc_VehicleMessage& next_vehicle_message();
+ void push_new_vehicle_message(const openxc_VehicleMessage& v_msg);
};
/* A compact representation of a single CAN message, meant to be used in in/out
diff --git a/src/can_decode_message.cpp b/src/can_decode_message.cpp
index 6bb6459..7e20f88 100644
--- a/src/can_decode_message.cpp
+++ b/src/can_decode_message.cpp
@@ -23,8 +23,8 @@
#include <afb/afb-binding.h>
-#include "can-utils.h"
-#include "can-decoder.h"
+#include "can-utils.hpp"
+#include "can-decoder.hpp"
#include "openxc.pb.h"
union DynamicField
@@ -36,36 +36,35 @@ union DynamicField
void can_decode_message(can_bus_t &can_bus)
{
- can_message_t *can_message;
+ can_message_t can_message;
std:vector <CanSignal> signals;
std:vector <CanSignal>::iterator signals_i;
openxc_VehicleMessage vehicle_message;
openxc_DynamicField search_key, ret;
+ bool send = true;
decoder_t decoder();
-
while(true)
{
if(can_message = can_bus.next_can_message())
{
/* First we have to found which CanSignal is */
- DynamicField signal_id = (double)can_message.get_id();
- search_key = build_DynamicField(openxc_DynamicField_Type_NUM, signal_id)
+ search_key = build_DynamicField(openxc_DynamicField_Type::openxc_DynamicField_Type_NUM, (double)can_message.get_id())
- signals = find_signals(search_key);
+ signals = find_can_signals(search_key);
/* Decoding the message ! Don't kill the messenger ! */
- for(signals_i=signals.begin(); signal_i != signals.end(); signals_i++)
- {
- subscribed_signals_i = subscribed_signals.find(signals_i);
+ for(const auto& sig : signals)
+ {
+ subscribed_signals_i = subscribed_signals.find(sig);
if(subscribed_signals_i != subscribed_signals.end() &&
afb_event_is_valid(subscribed_signals_i->second))
{
- ret = decoder.decodeSignal(&sig, can_message, SIGNALS, SIGNALS.size(), true);
+ ret = decoder.decodeSignal(sig, can_message, getSignals(), &send);
- s_message = build_SimpleMessage(subscribed_signals_i->first->genericName, ret);
+ s_message = build_SimpleMessage(sig.genericName, ret);
vehicle_message = build_VehicleMessage_with_SimpleMessage(openxc_DynamicField_Type::openxc_DynamicField_Type_NUM, s_message);
vehicle_message_q.push(vehicle_message);
@@ -79,69 +78,93 @@ void can_decode_message(can_bus_t &can_bus)
* Build a specific VehicleMessage containing a SimpleMessage.
*/
openxc_VehicleMessage build_VehicleMessage_with_SimpleMessage(openxc_DynamicField_Type type,
- openxc_SimpleMessage message)
+ const openxc_SimpleMessage& message)
{
struct timeb t_msec;
long long int timestamp_msec;
+
+ openxc_VehicleMessage v = {0};
+
if(!ftime(&t_msec))
{
timestamp_msec = ((long long int) t_msec.time) * 1000ll +
(long long int) t_msec.millitm;
- return openxc_VehicleMessage v = {.has_type = true,
- .type = openxc_VehicleMessage_Type::openxc_VehicleMessage_Type_SIMPLE,
- .has_simple_message = true,
- .simple_message = message,
- .has_timestamp = true,
- .timestamp = timestamp_msec};
+ v.has_type = true:
+ v.type = openxc_VehicleMessage_Type::openxc_VehicleMessage_Type_SIMPLE;
+ v.has_simple_message = true;
+ v.simple_message = message;
+ v.has_timestamp = true;
+ v.timestamp = timestamp_msec;
+
+ return v;
}
- return openxc_VehicleMessage v = {.has_type = true,
- .type = openxc_VehicleMessage_Type::openxc_VehicleMessage_Type_SIMPLE,
- .has_simple_message = true,
- .simple_message = message};
+ v.has_type = true,
+ v.type = openxc_VehicleMessage_Type::openxc_VehicleMessage_Type_SIMPLE;
+ v.has_simple_message = true;
+ v.simple_message = message;
+
+ return v;
}
/*
* Build an openxc_SimpleMessage associating a name to an openxc_DynamicField
*/
-openxc_SimpleMessage build_SimpleMessage(std:string name, openxc_DynamicField value)
+openxc_SimpleMessage build_SimpleMessage(const std::string& name, const openxc_DynamicField& value)
{
- return openxc_SimpleMessage s = {.has_name = true,
- .name = name,
- .has_value = true,
- .value = value};
+
+ openxc_SimpleMessage s = {0};
+
+ s.has_name = true;
+ ::strncpy(s.name, name.c_str(), 100);
+ s.has_value = true;
+ s.value = value;
+
+ return s;
}
-
+/*
+ * Build an openxc_DynamicField depending what we pass as argument
+ */
+openxc_DynamicField build_DynamicField(const std::string& value)
+{
+ openxc_DynamicField d = {0}
+ d.has_type = true;
+ d.type = openxc_DynamicField_Type_STRING;
+
+ d.has_string_value = true;
+ ::strncpy(d.string_value, value.c_tr(), 100);
+
+ return d;
}
/*
- * Build an openxc_DynamicField using its type and an union.
- * Why do not use of union in first place anyway...
+ * Build an openxc_DynamicField depending what we pass as argument
*/
-openxc_DynamicField build_DynamicField(openxc_DynamicField_Type type, DynamicField field)
+openxc_DynamicField build_DynamicField(double value)
{
- openxc_DynamicField d = {.has_type = true,
- .type = type};
+ openxc_DynamicField d = {0}
+ d.has_type = true;
+ d.type = openxc_DynamicField_Type_NUM;
- switch(type)
- {
- case openxc_DynamicField_Type_BOOL:
- d.has_boolean_value = true;
- d.boolean_value = field;
- break;
- case openxc_DynamicField_Type_NUM:
- d.has_numeric_value = true;
- d.numeric_value = field;
- break;
- case openxc_DynamicField_Type_STRING:
- d.has_string_value = true;
- strcpy(d.string_value, field);
- break;
- default:
- return nullptr;
- }
+ d.has_numeric_value = true;
+ d.numeric_value = field;
+
+ return d;
+}
+/*
+ * Build an openxc_DynamicField depending what we pass as argument
+ */
+openxc_DynamicField build_DynamicField(bool value)
+{
+ openxc_DynamicField d = {0}
+ d.has_type = true;
+ d.type = openxc_DynamicField_Type_BOOL;
+
+ d.has_boolean_value = true;
+ d.boolean_value = field;
+
return d;
} \ No newline at end of file
diff --git a/src/can_reader.cpp b/src/can_reader.cpp
index aab47b6..a8c5cf6 100644
--- a/src/can_reader.cpp
+++ b/src/can_reader.cpp
@@ -30,6 +30,6 @@ void can_reader(can_bus_t &can_bus)
while(can_bus.is_running())
{
can_message.convert_from_canfd_frame(canbus.read());
- can_bus.insert_new_can_message(can_message);
+ can_bus.push_new_can_message(can_message);
}
} \ No newline at end of file
diff --git a/src/low-can-binding.cpp b/src/low-can-binding.cpp
index d5c116f..b895adc 100644
--- a/src/low-can-binding.cpp
+++ b/src/low-can-binding.cpp
@@ -40,7 +40,7 @@
#include <afb/afb-binding.h>
#include <afb/afb-service-itf.h>
-#include "obd2.h"
+#include "obd2.hpp"
/*
* Interface between the daemon and the binding
diff --git a/src/obd2.h b/src/obd2.hpp
index cd362c7..cd362c7 100644
--- a/src/obd2.h
+++ b/src/obd2.hpp
diff --git a/src/timer.h b/src/timer.hpp
index 76eb51d..76eb51d 100644
--- a/src/timer.h
+++ b/src/timer.hpp