#define __SMALLFILE__ std::string(__FILE__).substr(std::string(__FILE__).rfind("/")+1)
AbstractRoutingEngine *m_re;
-uint16_t Obd2Amb::velocity = 0;
-double Obd2Amb::fuelConsumptionOldTime = 0;
-
+std::list<ObdPid*> Obd2Amb::supportedPidsList;
+Obd2Amb *obd2AmbInstance = new Obd2Amb;
int calledPersecond = 0;
}
}
+
+void connect(obdLib* obd, std::string device, std::string strbaud)
+{
+ //printf("First: %s\nSecond: %s\n",req->arg.substr(0,req->arg.find(':')).c_str(),req->arg.substr(req->arg.find(':')+1).c_str());
+ std::string port = device;
+ int baud = boost::lexical_cast<int>(strbaud);
+ obd->openPort(port.c_str(),baud);
+
+ obd->sendObdRequestString("ATZ\r",4,&replyVector,500,3);
+ for (unsigned int i=0;i<replyVector.size();i++)
+ {
+ reply += replyVector[i];
+ }
+ if (reply.find("ELM") == -1)
+ {
+ //No reply found
+ //printf("Error!\n");
+ DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error resetting ELM\n";
+ }
+ else
+ {
+ //printf("Reply to reset: %s\n",reply.c_str());
+ }
+ if (!sendElmCommand(obd,"ATSP0"))
+ {
+ //printf("Error sending echo\n");
+ DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error setting auto protocol"<<endl;
+ }
+ if (!sendElmCommand(obd,"ATE0"))
+ {
+ //printf("Error sending echo\n");
+ DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off echo"<<endl;
+ }
+ if (!sendElmCommand(obd,"ATH0"))
+ {
+ //printf("Error sending headers off\n");
+ DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off headers"<<endl;
+ }
+ if (!sendElmCommand(obd,"ATL0"))
+ {
+ //printf("Error turning linefeeds off\n");
+ DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off linefeeds"<<endl;
+ }
+}
+
void threadLoop(gpointer data)
{
GAsyncQueue *privCommandQueue = g_async_queue_ref(((OBD2Source*)data)->commandQueue);
obd->setCommsCallback([](const char* mssg, void* data) { DebugOut(6)<<mssg<<endl; },NULL);
obd->setDebugCallback([](const char* mssg, void* data, obdLib::DebugLevel debugLevel) { DebugOut(debugLevel)<<mssg<<endl; },NULL);
- std::list<std::string> reqList;
- std::list<std::string> repeatReqList;
- std::map<std::string,std::string> commandMap;
- std::vector<unsigned char> replyVector;
+ std::list<ObdPid*> reqList;
+ std::list<ObdPid*> repeatReqList;
+ ObdPid::ByteArray replyVector;
std::string reply;
while (true)
{
{
//printf("Got request!\n");
DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Got single shot request!"<<endl;
- ObdRequest *req = (ObdRequest*)query;
- repeatReqList.push_back(req->req);
- delete req;
+ ObdPid *req = (ObdPid*)query;
+ repeatReqList.push_back(req);
}
query = g_async_queue_try_pop(privSubscriptionAddQueue);
if (query != nullptr)
{
- ObdRequest *req = (ObdRequest*)query;
+ ObdPid *req = (ObdPid*)query;
DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Got subscription request for "<<req->req<<endl;
- reqList.push_back(req->req);
- delete req;
+ reqList.push_back(req);
}
query = g_async_queue_try_pop(privCommandQueue);
if (query != nullptr)
{
- ObdRequest *req = (ObdRequest*)query;
+ ObdPid *req = (ObdPid*)query;
//commandMap[req->req] = req->arg;
//printf("Command: %s\n",req->req.c_str());
- DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Command:" << req->req << endl;
- if (req->req == "connect")
+ DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Command:" << req->property << endl;
+ if (req->property == "connect")
{
- //printf("First: %s\nSecond: %s\n",req->arg.substr(0,req->arg.find(':')).c_str(),req->arg.substr(req->arg.find(':')+1).c_str());
- std::string port = req->arg.substr(0,req->arg.find(':'));
- int baud = boost::lexical_cast<int>(req->arg.substr(req->arg.find(':')+1));
- obd->openPort(port.c_str(),baud);
-
- obd->sendObdRequestString("ATZ\r",4,&replyVector,500,3);
- for (unsigned int i=0;i<replyVector.size();i++)
- {
- reply += replyVector[i];
- }
- if (reply.find("ELM") == -1)
- {
- //No reply found
- //printf("Error!\n");
- DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error resetting ELM\n";
- }
- else
- {
- //printf("Reply to reset: %s\n",reply.c_str());
- }
- if (!sendElmCommand(obd,"ATSP0"))
- {
- //printf("Error sending echo\n");
- DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error setting auto protocol"<<endl;
- }
- if (!sendElmCommand(obd,"ATE0"))
- {
- //printf("Error sending echo\n");
- DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off echo"<<endl;
- }
- if (!sendElmCommand(obd,"ATH0"))
- {
- //printf("Error sending headers off\n");
- DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off headers"<<endl;
- }
- if (!sendElmCommand(obd,"ATL0"))
- {
- //printf("Error turning linefeeds off\n");
- DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off linefeeds"<<endl;
- }
+ connect(obd);
}
delete req;
}
while(gpointer retval = g_async_queue_try_pop(src->responseQueue))
{
- ObdReply *reply = (ObdReply*)retval;
+ ObdPid *reply = (ObdPid*)retval;
- Obd2Amb obd2amb;
+ AbstractPropertyType* value = VehicleProperty::getPropertyTypeForPropertyNameValue(reply->property, reply->value);
+ src->updateProperty(reply->property, value);
- if(obd2amb.propertyPidMap.count(reply->property) != 0)
- {
- std::string convValue = reply->reply;
-
- if(obd2amb.propertyConversionMap.count(reply->property))
- {
- convValue = obd2amb.propertyConversionMap[reply->property](reply->reply);
- }
-
-
- AbstractPropertyType* value = VehicleProperty::getPropertyTypeForPropertyNameValue(reply->property, convValue);
- src->updateProperty(reply->property, value);
- }
/*if (reply->req == "05")
{
else throw std::runtime_error("Device Error");
}
- ObdRequest *requ = new ObdRequest();
- requ->req = "connect";
- requ->arg = port + ":" + baud;
- g_async_queue_push(commandQueue,requ);
+ connect(obd, port, baud);
+ g_thread_new("mythread",(GThreadFunc)&threadLoop,this);
+ g_idle_add(updateProperties, this);
}
OBD2Source::OBD2Source(AbstractRoutingEngine *re, map<string, string> config) : AbstractSource(re, config)
m_re = re;
Obd2Amb obd2amb;
+ obd = new obdLib();
- for(auto itr = obd2amb.propertyPidMap.begin(); itr != obd2amb.propertyPidMap.end(); itr++)
+ for(auto itr = obd2amb.supportedPidsList.begin(); itr != obd2amb.supportedPidsList.end(); itr++)
{
- m_supportedProperties.push_back((*itr).first);
+ m_supportedProperties.push_back((*itr)->property);
}
re->setSupported(supported(), this);
subscriptionRemoveQueue = g_async_queue_new();
responseQueue = g_async_queue_new();
singleShotQueue = g_async_queue_new();
- g_thread_new("mythread",(GThreadFunc)&threadLoop,this);
setConfiguration(config);
-
- //AsyncQueueWatcher * watcher = new AsyncQueueWatcher(responseQueue, (AsyncQueueWatcherCallback) updateProperties, this);
-
- //g_timeout_add(1,updateProperties, this);
- g_idle_add(updateProperties, this);
- //g_timeout_add(1000,calcCPS,NULL);
-
}
PropertyList OBD2Source::supported()
return;
}
- Obd2Amb obd2amb;
- ObdRequest *requ = new ObdRequest();
- requ->req = obd2amb.propertyPidMap[property];
- g_async_queue_push(subscriptionAddQueue,requ);
+
+ ObdPid *pid = Obd2Amb::createPidforProperty(property);
+ g_async_queue_push(subscriptionAddQueue,pid);
}
}
return;
}
- Obd2Amb obd2amb;
- ObdRequest *requ = new ObdRequest();
- requ->property = property;
- requ->req = obd2amb.propertyPidMap[property];
- g_async_queue_push(subscriptionRemoveQueue,requ);
+ ObdPid *pid = Obd2Amb::createPidforProperty(property);
+ g_async_queue_push(subscriptionRemoveQueue,pid);
}
return;
}
- Obd2Amb obd2amb;
- ObdRequest *requ = new ObdRequest();
- requ->property = property;
- requ->req = obd2amb.propertyPidMap[property];
+ ObdPid* requ = Obd2Amb::createPidforProperty(property);
g_async_queue_push(singleShotQueue,requ);
}
#include "obdlib.h"
#include <glib.h>
-
-class ObdRequest
-{
-public:
- VehicleProperty::Property property;
- std::string req;
- std::string arg;
-};
-
-class ObdReply
-{
-public:
- VehicleProperty::Property property;
- std::string req;
- std::string reply;
-};
-
+#include "obdpid.h"
class Obd2Amb
{
typedef function<std::string (std::string)> ConversionFunction;
+
Obd2Amb()
{
- propertyPidMap[VehicleProperty::VehicleSpeed] = "010D1\r";
- propertyPidMap[VehicleProperty::EngineSpeed] = "010C1\r";
- propertyPidMap[VehicleProperty::MassAirFlow] = "01101\r";
- propertyPidMap[VehicleProperty::AirIntakeTemperature] = "010F1\r";
- propertyPidMap[VehicleProperty::ThrottlePosition] = "01111\r";
- propertyPidMap[VehicleProperty::BatteryVoltage] = "ATRV\r";
- propertyPidMap[VehicleProperty::EngineCoolantTemperature] = "0105a\r";
- propertyPidMap[VehicleProperty::EngineLoad] = "01041/r";
- propertyPidMap[VehicleProperty::VIN] = "0902/r";
- propertyPidMap[VehicleProperty::WMI] = "0902/r";
- propertyPidMap[VehicleProperty::EngineOilTemperature] = "015C1\r";
- propertyPidMap[VehicleProperty::InteriorTemperature] = "01461\r";
- propertyPidMap[VehicleProperty::FuelConsumption] = "01101\r";
-
-
-
- propertyConversionMap[VehicleProperty::VehicleSpeed] = [](std::string input)
- {
- ///velocity is used in other equations. We'll save it off in a static variable:
- stringstream vssConvert(input);
-
- vssConvert>>velocity;
-
- return input;
- };
-
- propertyConversionMap[VehicleProperty::WMI] = [](std::string input)
- {
- return input.substr(0,3);
- };
+ supportedPidsList.push_back(new VehicleSpeedPid());
+ supportedPidsList.push_back(new EngineSpeedPid());
+ supportedPidsList.push_back(new MassAirFlowPid());
+ supportedPidsList.push_back(new VinPid());
+ supportedPidsList.push_back(new WmiPid());
+ supportedPidsList.push_back(new FuelConsumptionPid());
+ supportedPidsList.push_back(new EngineCoolantPid());
+ }
- propertyConversionMap[VehicleProperty::FuelConsumption] = [](std::string input)
+ static ObdPid* createPidforProperty(VehicleProperty::Property property)
+ {
+ for(auto itr = supportedPidsList.begin(); itr != supportedPidsList.end(); itr++)
{
- double maf;
- stringstream mafConvert(input);
-
- mafConvert>>maf;
-
- mafConvert<<1 / (14.75 * 6.26) * maf * 0/60;
-
- return mafConvert.str();
- };
-
-
-
+ if((*itr)->property == property)
+ {
+ ObdPid* obj = *itr;
+ return obj->create();
+ }
+ }
}
-
-
- map<VehicleProperty::Property, std::string> propertyPidMap;
- map<VehicleProperty::Property, ConversionFunction> propertyConversionMap;
-
-private:
-
- static uint16_t velocity;
- static double fuelConsumptionOldTime;
+ static std::list<ObdPid*> supportedPidsList;
};
class OBD2Source : public AbstractSource
std::string m_port;
map<VehicleProperty::Property,AsyncPropertyReply*> propertyReplyMap;
void updateProperty(VehicleProperty::Property property,AbstractPropertyType *value);
+ obdLib * obd;
+
private:
PropertyList m_supportedProperties;
GMutex *threadQueueMutex;
--- /dev/null
+#ifndef _OBDPID_H__H_H_
+#define _OBDPID_H__H_H_
+
+#include <vector>
+#include <string>
+#include <vehicleproperty.h>
+#include <time.h>
+
+class ObdPid
+{
+public:
+ typedef std::vector<unsigned char> ByteArray;
+
+ ObdPid(VehicleProperty::Property prop, std::string p, int i)
+ :property(prop), pid(p), id(i), type(0x41)
+ {
+
+ }
+
+ virtual ObdPid* create() = 0;
+
+ virtual void parse(ByteArray replyVector) = 0;
+
+ VehicleProperty::Property property;
+ std::string pid;
+ int id;
+ int type;
+ std::string value;
+};
+
+template <class T>
+class CopyMe: public ObdPid
+{
+public:
+
+ CopyMe(VehicleProperty::Property prop, std::string p, int i)
+ :ObdPid(prop, p, i)
+ {
+
+ }
+
+ ObdPid* create()
+ {
+ return new T();
+ }
+};
+
+
+class VehicleSpeedPid: public CopyMe<VehicleSpeedPid>
+{
+public:
+
+ VehicleSpeedPid()
+ :CopyMe(VehicleProperty::VehicleSpeed, "010D1\r", 0x0D)
+ {
+
+ }
+
+ void parse(ByteArray replyVector)
+ {
+ int mph = replyVector[2];
+ value = boost::lexical_cast<std::string>(mph);
+ }
+};
+
+class EngineSpeedPid: public CopyMe<EngineSpeedPid>
+{
+public:
+
+ EngineSpeedPid()
+ :CopyMe(VehicleProperty::VehicleSpeed,"010C1\r",0x0D)
+ {
+
+ }
+
+ void parse(ByteArray replyVector)
+ {
+ double rpm = ((replyVector[2] << 8) + replyVector[3]) / 4.0;
+ value = boost::lexical_cast<std::string>(rpm);
+ }
+};
+
+class EngineCoolantPid: public CopyMe<EngineCoolantPid>
+{
+public:
+
+ EngineCoolantPid()
+ :CopyMe(VehicleProperty::VehicleSpeed,"01051\r",0x0D)
+ {
+
+ }
+
+ void parse(ByteArray replyVector)
+ {
+ int temp = replyVector[2] - 40;
+ value = boost::lexical_cast<std::string>(temp);
+ }
+};
+
+class MassAirFlowPid: public CopyMe<MassAirFlowPid>
+{
+public:
+
+ MassAirFlowPid()
+ :CopyMe(VehicleProperty::VehicleSpeed,"01101\r",0x0D)
+ {
+
+ }
+
+ virtual void parse(ByteArray replyVector)
+ {
+ maf = ((replyVector[2] << 8) + replyVector[3]) / 100.0;
+ value = boost::lexical_cast<std::string>(maf);
+ }
+
+protected:
+ double maf;
+};
+
+
+class FuelConsumptionPid: public MassAirFlowPid
+{
+public:
+ FuelConsumptionPid()
+
+ {
+
+ }
+
+ virtual void parse(ByteArray replyVector)
+ {
+ MassAirFlowPid::parse(replyVector);
+ timespec t;
+ clock_gettime(CLOCK_REALTIME, &t);
+
+ double currentTime = t.tv_sec + t.tv_nsec / 1000000;
+
+ double diffTime = currentTime - oldTime;
+ oldTime = currentTime;
+
+ double consumption = 1 / (14.75 * 6.26) * maf * diffTime/60;
+
+ value = boost::lexical_cast<std::string>(consumption);
+ }
+
+private:
+
+ static double oldTime;
+};
+
+
+class VinPid: public CopyMe<VinPid>
+{
+public:
+
+ VinPid()
+ :CopyMe(VehicleProperty::VIN,"0902\r",0x0D)
+ {
+ type = 0x49;
+ }
+
+ virtual void parse(ByteArray replyVector)
+ {
+ std::string vinstring;
+ for (int j=0;j<replyVector.size();j++)
+ {
+ if(replyVector[j] == 0x49 && replyVector[j+1] == 0x02)
+ {
+ //We're at a reply header
+ j+=3;
+ }
+ if (replyVector[j] != 0x00)
+ {
+ vinstring += (char)replyVector[j];
+ //printf("VIN: %i %c\n",replyVector[j],replyVector[j]);
+ }
+ }
+
+ value = vinstring;
+ }
+
+};
+
+class WmiPid: public VinPid
+{
+public:
+
+ WmiPid()
+ :VinPid()
+ {
+ property = VehicleProperty::WMI;
+ }
+
+ virtual void parse(ByteArray replyVector)
+ {
+ VinPid::parse(replyVector);
+
+ value = value.substr(0,3);
+ }
+
+};
+
+
+#endif