2 Copyright (C) 2012 Intel Corporation
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #include "tpmsplugin.h"
22 #include <boost/assert.hpp>
29 #include "timestamp.h"
31 #define ENDPOINT_IN 0x81
32 #define ENDPOINT_OUT 0x01
34 #define DEVICE_VID 0x0000
35 #define DEVICE_PID 0x0001
39 //timeout for performing interrupt r/w operations in milliseconds
40 #define INTR_TIMEOUT 1000
42 #define PSI_MULTIPLIER 14.5038
43 #define KPA_MULTIPLIER 100
44 #define PRESSURE_SCALE 0.025
46 #define FARENHEIT_MULTIPLIER 1.8
49 static gboolean timeoutCallback(gpointer data)
51 TpmsPlugin* src = (TpmsPlugin*)data;
53 int r = src->readValues();
58 TpmsPlugin::TpmsPlugin(AbstractRoutingEngine* re, map<string, string> config)
59 :AbstractSource(re, config)
61 lfPressure = rfPressure = lrPressure = rrPressure = 0;
62 lfTemperature = rfTemperature = lrTemperature = rrTemperature = 0;
66 r = libusb_init(NULL);
68 DebugOut() << "TPMS: Plugin load failure. Failed to initialize libusb" << endl;
73 DebugOut() << "TPMS: Plugin load failure. Could not find/open device - run as root?" << endl;
76 // need to detach device from kernel driver before claiming the interface
79 DebugOut() << "TPMS: Plugin load failure. USB device detach failed with code " << r << endl;
82 r = libusb_claim_interface(mDeviceHandle, 0);
84 DebugOut() << "TPMS: Plugin load failure. usb_claim_interface error " << r << endl;
87 DebugOut() << "TPMS: USB interface initialized" << endl;
89 re->setSupported(supported(), this);
90 g_timeout_add(5000, timeoutCallback, this );
91 DebugOut() << "TPMS: set to read sensor every 5 seconds" << endl;
99 extern "C" AbstractSource * create(AbstractRoutingEngine* routingengine, map<string, string> config)
101 return new TpmsPlugin(routingengine, config);
105 const string TpmsPlugin::uuid()
107 return "5e896a00-15b3-11e3-8ffd-0800200c9a66";
111 void TpmsPlugin::getPropertyAsync(AsyncPropertyReply *reply)
113 DebugOut() << "TPMS: getPropertyAsync called for property: " << reply->property << endl;
115 if(reply->property == VehicleProperty::TirePressureLeftFront) {
116 VehicleProperty::TirePressureLeftFrontType temp(lfPressure);
117 reply->success = true;
118 reply->value = &temp;
119 reply->completed(reply);
121 else if(reply->property == VehicleProperty::TirePressureRightFront) {
122 VehicleProperty::TirePressureRightFrontType temp(rfPressure);
123 reply->success = true;
124 reply->value = &temp;
125 reply->completed(reply);
127 else if(reply->property == VehicleProperty::TirePressureLeftRear) {
128 VehicleProperty::TirePressureLeftRearType temp(lrPressure);
129 reply->success = true;
130 reply->value = &temp;
131 reply->completed(reply);
133 else if(reply->property == VehicleProperty::TirePressureRightRear) {
134 VehicleProperty::TirePressureRightRearType temp(rrPressure);
135 reply->success = true;
136 reply->value = &temp;
137 reply->completed(reply);
139 else if(reply->property == VehicleProperty::TireTemperatureLeftFront) {
140 VehicleProperty::TireTemperatureLeftFrontType temp(lfTemperature);
141 reply->success = true;
142 reply->value = &temp;
143 reply->completed(reply);
145 else if(reply->property == VehicleProperty::TireTemperatureRightFront) {
146 VehicleProperty::TireTemperatureRightFrontType temp(rfTemperature);
147 reply->success = true;
148 reply->value = &temp;
149 reply->completed(reply);
151 else if(reply->property == VehicleProperty::TireTemperatureLeftRear) {
152 VehicleProperty::TireTemperatureLeftRearType temp(lrTemperature);
153 reply->success = true;
154 reply->value = &temp;
155 reply->completed(reply);
157 else if(reply->property == VehicleProperty::TireTemperatureRightRear) {
158 VehicleProperty::TireTemperatureRightRearType temp(rrTemperature);
159 reply->success = true;
160 reply->value = &temp;
161 reply->completed(reply);
165 DebugOut() << "TPMS: no such getProperty type: " << reply->property << endl;
166 reply->success = false;
167 reply->error = AsyncPropertyReply::InvalidOperation;
168 reply->value = nullptr;
169 reply->completed(reply);
173 void TpmsPlugin::getRangePropertyAsync(AsyncRangePropertyReply *reply)
176 reply->completed(reply);
179 AsyncPropertyReply *TpmsPlugin::setProperty(AsyncSetPropertyRequest request )
184 void TpmsPlugin::subscribeToPropertyChanges(VehicleProperty::Property property)
186 mRequests.push_back(property);
189 PropertyList TpmsPlugin::supported()
192 props.push_back(VehicleProperty::TirePressureLeftFront);
193 props.push_back(VehicleProperty::TirePressureRightFront);
194 props.push_back(VehicleProperty::TirePressureLeftRear);
195 props.push_back(VehicleProperty::TirePressureRightRear);
196 props.push_back(VehicleProperty::TireTemperatureLeftFront);
197 props.push_back(VehicleProperty::TireTemperatureRightFront);
198 props.push_back(VehicleProperty::TireTemperatureLeftRear);
199 props.push_back(VehicleProperty::TireTemperatureRightRear);
204 void TpmsPlugin::unsubscribeToPropertyChanges(VehicleProperty::Property property)
206 mRequests.remove(property);
209 int TpmsPlugin::findDevice(void)
211 int deviceVid = DEVICE_VID;
212 int devicePid = DEVICE_PID;
214 DebugOut() << "TPMS: Trying to open USB device with VID: " << deviceVid << " PID: " << devicePid << endl;
215 mDeviceHandle = libusb_open_device_with_vid_pid(NULL, DEVICE_VID, DEVICE_PID);
217 return mDeviceHandle ? 0 : -1;
221 int TpmsPlugin::detachDevice(void)
224 r = libusb_kernel_driver_active(mDeviceHandle, 0);
226 DebugOut() << "TPMS: USB device seems to be kernel driven, trying to detach" << endl;
227 r = libusb_detach_kernel_driver(mDeviceHandle, 0);
233 int TpmsPlugin::exitClean(int deinit)
236 libusb_release_interface(mDeviceHandle, 0);
237 libusb_attach_kernel_driver(mDeviceHandle, 0);
238 libusb_close(mDeviceHandle);
244 int TpmsPlugin::readValues()
247 unsigned char buf[4];
249 // Sensor 1 = Left Front
250 // Sensor 2 = Right Front
251 // Sensor 3 = Left Rear
252 // Sensor 4 = Right Rear
254 for (snum = 1; snum <= MAX_SENSORS; snum++) {
255 readUsbSensor(snum, buf);
257 // only do this if sensor is available
258 if (buf[3] != 0xff) {
260 char print_string[100];
264 lfPressure = ((float)buf[0]-40) * PRESSURE_SCALE * KPA_MULTIPLIER;
265 lfTemperature = (float)buf[1]-40;
266 sprintf(print_string, "TPMS: Left front pressure = %5.1f kPa, temperature = %5.1f degrees Celsius", lfPressure, lfTemperature);
267 DebugOut() << print_string << endl;
270 rfPressure = (buf[0]-40) * PRESSURE_SCALE * KPA_MULTIPLIER;
271 rfTemperature = buf[1]-40;
272 sprintf(print_string, "TPMS: Right front pressure = %5.1f kPa, temperature = %5.1f degrees Celsius", rfPressure, rfTemperature);
273 DebugOut() << print_string << endl;
276 lrPressure = (buf[0]-40) * PRESSURE_SCALE * KPA_MULTIPLIER;
277 lrTemperature = buf[1]-40;
278 sprintf(print_string, "TPMS: Left rear pressure = %5.1f kPa, temperature = %5.1f degrees Celsius", lrPressure, lrTemperature);
279 DebugOut() << print_string << endl;
282 rrPressure = (buf[0]-40) * PRESSURE_SCALE * KPA_MULTIPLIER;
283 rrTemperature = buf[1]-40;
284 sprintf(print_string, "TPMS: Right rear pressure = %5.1f kPa, temperature = %5.1f degrees Celsius", rrPressure, rrTemperature);
285 DebugOut() << print_string << endl;
289 // make sensor mode human-readable
290 // FIXME: for future reference, modes not being used
292 case 0x01: mode_string = "normal"; break;
293 case 0x02: mode_string = "pressure_alert"; break;
294 // more to add here...
295 default: mode_string = "unknown"; break;
299 DebugOut() << "TPMS: Unable to read sensor " << sensorNumberToString(snum) << " (" << snum << ")" << endl;
303 VehicleProperty::TirePressureLeftFrontType lfPres(lfPressure);
304 VehicleProperty::TirePressureRightFrontType rfPres(rfPressure);
305 VehicleProperty::TirePressureLeftRearType lrPres(lrPressure);
306 VehicleProperty::TirePressureRightRearType rrPres(rrPressure);
307 VehicleProperty::TireTemperatureLeftFrontType lfTemp(lfTemperature);
308 VehicleProperty::TireTemperatureRightFrontType rfTemp(rfTemperature);
309 VehicleProperty::TireTemperatureLeftRearType lrTemp(lrTemperature);
310 VehicleProperty::TireTemperatureRightRearType rrTemp(rrTemperature);
312 routingEngine->updateProperty(&lfPres, uuid());
313 routingEngine->updateProperty(&rfPres, uuid());
314 routingEngine->updateProperty(&lrPres, uuid());
315 routingEngine->updateProperty(&rrPres, uuid());
316 routingEngine->updateProperty(&lfTemp, uuid());
317 routingEngine->updateProperty(&rfTemp, uuid());
318 routingEngine->updateProperty(&lrTemp, uuid());
319 routingEngine->updateProperty(&rrTemp, uuid());
324 int TpmsPlugin::readUsbSensor(int sid, unsigned char *buf)
329 r = libusb_interrupt_transfer(mDeviceHandle, ENDPOINT_OUT, buf, 1, &transferred, INTR_TIMEOUT);
331 DebugOut() << "TPMS: USB write interrupt failed, code " << r << endl;
334 r = libusb_interrupt_transfer(mDeviceHandle, ENDPOINT_IN, buf, 4, &transferred, INTR_TIMEOUT);
336 DebugOut() << "TPMS: USB read interrupt failed, code " << r << endl;
343 string TpmsPlugin::sensorNumberToString(int snid)
346 case 1: return "left front"; break;
347 case 2: return "right front"; break;
348 case 3: return "left rear"; break;
349 case 4: return "right rear"; break;
350 default: return "unknown";