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 string TpmsPlugin::uuid()
107 return "CHANGE THIS 6dd4268a-c605-4a06-9034-59c1e8344c8e";
111 void TpmsPlugin::getPropertyAsync(AsyncPropertyReply *reply)
113 DebugOut() << "TPMS: getPropertyAsync called for property: " << reply->property << endl;
115 if(reply->property == VehicleProperty::TirePressureLeftFront) {
116 VehicleProperty::TirePressureType temp(lfPressure);
117 reply->value = &temp;
118 reply->completed(reply);
120 else if(reply->property == VehicleProperty::TirePressureRightFront) {
121 VehicleProperty::TirePressureType temp(rfPressure);
122 reply->value = &temp;
123 reply->completed(reply);
125 else if(reply->property == VehicleProperty::TirePressureLeftRear) {
126 VehicleProperty::TirePressureType temp(lrPressure);
127 reply->value = &temp;
128 reply->completed(reply);
130 else if(reply->property == VehicleProperty::TirePressureRightRear) {
131 VehicleProperty::TirePressureType temp(rrPressure);
132 reply->value = &temp;
133 reply->completed(reply);
135 else if(reply->property == VehicleProperty::TireTemperatureLeftFront) {
136 VehicleProperty::EngineSpeedType temp(lfTemperature);
137 reply->value = &temp;
138 reply->completed(reply);
140 else if(reply->property == VehicleProperty::TireTemperatureRightFront) {
141 VehicleProperty::EngineSpeedType temp(rfTemperature);
142 reply->value = &temp;
143 reply->completed(reply);
145 else if(reply->property == VehicleProperty::TireTemperatureLeftRear) {
146 VehicleProperty::EngineSpeedType temp(lrTemperature);
147 reply->value = &temp;
148 reply->completed(reply);
150 else if(reply->property == VehicleProperty::TireTemperatureRightRear) {
151 VehicleProperty::EngineSpeedType temp(rrTemperature);
152 reply->value = &temp;
153 reply->completed(reply);
157 DebugOut() << "TPMS: no such getProperty type: " << reply->property << endl;
158 reply->value = nullptr;
159 reply->completed(reply);
163 void TpmsPlugin::getRangePropertyAsync(AsyncRangePropertyReply *reply)
166 reply->completed(reply);
169 AsyncPropertyReply *TpmsPlugin::setProperty(AsyncSetPropertyRequest request )
174 void TpmsPlugin::subscribeToPropertyChanges(VehicleProperty::Property property)
176 mRequests.push_back(property);
179 PropertyList TpmsPlugin::supported()
182 props.push_back(VehicleProperty::TirePressureLeftFront);
183 props.push_back(VehicleProperty::TirePressureRightFront);
184 props.push_back(VehicleProperty::TirePressureLeftRear);
185 props.push_back(VehicleProperty::TirePressureRightRear);
186 props.push_back(VehicleProperty::TireTemperatureLeftFront);
187 props.push_back(VehicleProperty::TireTemperatureRightFront);
188 props.push_back(VehicleProperty::TireTemperatureLeftRear);
189 props.push_back(VehicleProperty::TireTemperatureRightRear);
194 void TpmsPlugin::unsubscribeToPropertyChanges(VehicleProperty::Property property)
196 mRequests.remove(property);
199 int TpmsPlugin::findDevice(void)
201 int deviceVid = DEVICE_VID;
202 int devicePid = DEVICE_PID;
204 DebugOut() << "TPMS: Trying to open USB device with VID: " << deviceVid << " PID: " << devicePid << endl;
205 mDeviceHandle = libusb_open_device_with_vid_pid(NULL, DEVICE_VID, DEVICE_PID);
207 return mDeviceHandle ? 0 : -1;
211 int TpmsPlugin::detachDevice(void)
214 r = libusb_kernel_driver_active(mDeviceHandle, 0);
216 DebugOut() << "TPMS: USB device seems to be kernel driven, trying to detach" << endl;
217 r = libusb_detach_kernel_driver(mDeviceHandle, 0);
223 int TpmsPlugin::exitClean(int deinit)
226 libusb_release_interface(mDeviceHandle, 0);
227 libusb_attach_kernel_driver(mDeviceHandle, 0);
228 libusb_close(mDeviceHandle);
234 int TpmsPlugin::readValues()
237 unsigned char buf[4];
239 // Sensor 1 = Left Front
240 // Sensor 2 = Right Front
241 // Sensor 3 = Left Rear
242 // Sensor 4 = Right Rear
244 for (snum = 1; snum <= MAX_SENSORS; snum++) {
245 readUsbSensor(snum, buf);
247 // only do this if sensor is available
248 if (buf[3] != 0xff) {
250 char print_string[100];
254 lfPressure = ((float)buf[0]-40) * PRESSURE_SCALE * KPA_MULTIPLIER;
255 lfTemperature = (float)buf[1]-40;
256 sprintf(print_string, "TPMS: Left front pressure = %5.1f kPa, temperature = %5.1f degrees Celsius", lfPressure, lfTemperature);
257 DebugOut() << print_string << endl;
260 rfPressure = (buf[0]-40) * PRESSURE_SCALE * KPA_MULTIPLIER;
261 rfTemperature = buf[1]-40;
262 sprintf(print_string, "TPMS: Right front pressure = %5.1f kPa, temperature = %5.1f degrees Celsius", rfPressure, rfTemperature);
263 DebugOut() << print_string << endl;
266 lrPressure = (buf[0]-40) * PRESSURE_SCALE * KPA_MULTIPLIER;
267 lrTemperature = buf[1]-40;
268 sprintf(print_string, "TPMS: Left rear pressure = %5.1f kPa, temperature = %5.1f degrees Celsius", lrPressure, lrTemperature);
269 DebugOut() << print_string << endl;
272 rrPressure = (buf[0]-40) * PRESSURE_SCALE * KPA_MULTIPLIER;
273 rrTemperature = buf[1]-40;
274 sprintf(print_string, "TPMS: Right rear pressure = %5.1f kPa, temperature = %5.1f degrees Celsius", rrPressure, rrTemperature);
275 DebugOut() << print_string << endl;
279 // make sensor mode human-readable
280 // FIXME: for future reference, modes not being used
282 case 0x01: mode_string = "normal"; break;
283 case 0x02: mode_string = "pressure_alert"; break;
284 // more to add here...
285 default: mode_string = "unknown"; break;
289 DebugOut() << "TPMS: Unable to read sensor " << sensorNumberToString(snum) << " (" << snum << ")" << endl;
293 VehicleProperty::TirePressureType lfPres(lfPressure);
294 VehicleProperty::TirePressureType rfPres(rfPressure);
295 VehicleProperty::TirePressureType lrPres(lrPressure);
296 VehicleProperty::TirePressureType rrPres(rrPressure);
297 VehicleProperty::TireTemperatureType lfTemp(lfTemperature);
298 VehicleProperty::TireTemperatureType rfTemp(rfTemperature);
299 VehicleProperty::TireTemperatureType lrTemp(lrTemperature);
300 VehicleProperty::TireTemperatureType rrTemp(rrTemperature);
302 routingEngine->updateProperty(VehicleProperty::TirePressureLeftFront, &lfPres, uuid(), amb::currentTime(), 0);
303 routingEngine->updateProperty(VehicleProperty::TirePressureRightFront, &rfPres, uuid(), amb::currentTime(), 0);
304 routingEngine->updateProperty(VehicleProperty::TirePressureLeftRear, &lrPres, uuid(), amb::currentTime(), 0);
305 routingEngine->updateProperty(VehicleProperty::TirePressureRightRear, &rrPres, uuid(), amb::currentTime(), 0);
306 routingEngine->updateProperty(VehicleProperty::TireTemperatureLeftFront, &lfTemp, uuid(), amb::currentTime(), 0);
307 routingEngine->updateProperty(VehicleProperty::TireTemperatureRightFront, &rfTemp, uuid(), amb::currentTime(), 0);
308 routingEngine->updateProperty(VehicleProperty::TireTemperatureLeftRear, &lrTemp, uuid(), amb::currentTime(), 0);
309 routingEngine->updateProperty(VehicleProperty::TireTemperatureRightRear, &rrTemp, uuid(), amb::currentTime(), 0);
314 int TpmsPlugin::readUsbSensor(int sid, unsigned char *buf)
319 r = libusb_interrupt_transfer(mDeviceHandle, ENDPOINT_OUT, buf, 1, &transferred, INTR_TIMEOUT);
321 DebugOut() << "TPMS: USB write interrupt failed, code " << r << endl;
324 r = libusb_interrupt_transfer(mDeviceHandle, ENDPOINT_IN, buf, 4, &transferred, INTR_TIMEOUT);
326 DebugOut() << "TPMS: USB read interrupt failed, code " << r << endl;
333 string TpmsPlugin::sensorNumberToString(int snid)
336 case 1: return "left front"; break;
337 case 2: return "right front"; break;
338 case 3: return "left rear"; break;
339 case 4: return "right rear"; break;
340 default: return "unknown";