Skip to content

Commit 5341180

Browse files
authored
Merge pull request #166 from openxc/next
Next into master for 2.2.0 Python release and 8.2.0 vi-firmware release
2 parents 31655a9 + 08f7647 commit 5341180

17 files changed

Lines changed: 665 additions & 445 deletions

File tree

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# This workflow will upload a Python Package using Twine when a release is created
2+
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
3+
4+
name: Upload Python Package
5+
6+
on:
7+
release:
8+
types: [created]
9+
10+
jobs:
11+
deploy:
12+
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- uses: actions/checkout@v2
17+
- name: Set up Python
18+
uses: actions/setup-python@v2
19+
with:
20+
python-version: '3.x'
21+
- name: Install dependencies
22+
run: |
23+
python -m pip install --upgrade pip
24+
pip install setuptools wheel twine
25+
- name: Build and publish
26+
env:
27+
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
28+
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
29+
run: |
30+
python setup.py sdist bdist_wheel
31+
twine upload dist/*

.github/workflows/python-test.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2+
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3+
4+
name: Test Open XC Pyton
5+
6+
on: [ pull_request ]
7+
8+
jobs:
9+
build:
10+
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
python-version: [3.6.7]
15+
16+
steps:
17+
- uses: actions/checkout@v2
18+
- name: Set up Python ${{ matrix.python-version }}
19+
uses: actions/setup-python@v2
20+
with:
21+
python-version: ${{ matrix.python-version }}
22+
- name: Install dependencies
23+
run: |
24+
sudo apt-get update
25+
sudo apt-get install python-bluetooth -qq -y
26+
python -m pip install --upgrade pip
27+
python -m pip install pytest pyserial==3.1.1 coveralls
28+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
29+
30+
- name: Test
31+
run: |
32+
python setup.py test
33+

.travis.yml

Lines changed: 0 additions & 20 deletions
This file was deleted.

CHANGELOG.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
OpenXC Python Library Changelog
22
===============================
33

4+
v2.2.0
5+
----------
6+
* Improvements to usb traffic handling
7+
* Updated message format based upton the protobuf file
8+
* Improved memory management for protobuf
9+
* SonarQube updates
10+
* Github actions updated,travis decommissioned
11+
* Support for the new get_vin command
12+
openxc-control get_vin
13+
414
v2.1.0
515
----------
616
* SonarQube integration

README.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ OpenXC for Python
44

55
.. image:: https://github.com/openxc/openxc-python/raw/master/docs/_static/logo.png
66

7-
:Version: 2.1.0
7+
:Version: 2.2.0
88
:Web: http://openxcplatform.com
99
:Download: http://pypi.python.org/pypi/openxc/
1010
:Documentation: http://python.openxcplatform.com
1111
:Source: http://github.com/openxc/openxc-python/
1212
:Keywords: vehicle, openxc, python
1313

14-
.. image:: https://travis-ci.org/openxc/openxc-python.svg?branch=master
15-
:target: https://travis-ci.org/openxc/openxc-python
14+
.. image:: https://github.com/openxc/openxc-python/workflows/Test%20Open%20XC%20Pyton/badge.svg
15+
:target: https://github.com/openxc/openxc-python/actions?query=workflow%3A%22Test+Open+XC+Pyton%22
1616

1717
.. image:: https://coveralls.io/repos/openxc/openxc-python/badge.png?branch=master
1818
:target: https://coveralls.io/r/openxc/openxc-python?branch=master
@@ -30,6 +30,8 @@ In addition to a port of the Android library API, the package also contains a
3030
number of command-line tools for connecting to the CAN translator and
3131
manipulating previously recorded vehicle data.
3232

33+
If you are getting the error "ValueError: No backend available" on windows please reinstall your libusb0 driver using https://github.com/openxc/vi-windows-driver if you are in a envirment where you can not use an unsigned driver please use https://zadig.akeo.ie/
34+
3335
Due to changes in signals.cpp openxc-python Version 2.0.0 must be used with vi-firmware 8.0.0 or greater.
3436
Due to changes with large diagnostic responses Version 2.1.0 must be used with vi-firmware 8.1.0 or greater.
3537

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ OpenXC for Python
44

55
.. image:: https://github.com/openxc/openxc-python/raw/master/docs/_static/logo.png
66

7-
:Version: 2.1.0
7+
:Version: 2.2.0
88
:Web: http://openxcplatform.com
99
:Download: http://pypi.python.org/pypi/openxc/
1010
:Documentation: http://python.openxcplatform.com

openxc/controllers/base.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,16 @@ def handle_responses(self):
8383
response = self.queue.get(
8484
timeout=self.COMMAND_RESPONSE_TIMEOUT_S)
8585
if self._response_matches_request(response):
86-
if type(self) == DiagnosticResponseReceiver:
87-
if self._response_is_multiframe(response):
86+
if type(self) == DiagnosticResponseReceiver and self._response_is_multiframe(response):
8887
if response['id'] in self.diag_dict:
8988
self.diag_dict[response['id']].addFrame(response)
9089
else:
9190
self.diag_dict[response['id']] = MultiframeDiagnosticMessage(response)
9291
if self._return_final(response):
93-
self.responses.append(self.diag_dict[response['id']].getResponse())
92+
save = self.responses.pop()
93+
dentry = self.diag_dict[response['id']].getResponse() # DO NOT REMOVE This MUST be saved to a local variable to prevent deallocation
94+
self.responses.append(dentry) # DO NOT REMOVE This MUST be saved to a local variable to prevent deallocation
95+
self.responses.append(save)
9496
self.diag_dict.pop(response['id'])
9597
self.responses.append(response)
9698
if self.quit_after_first:
@@ -101,14 +103,14 @@ def handle_responses(self):
101103

102104
class MultiframeDiagnosticMessage:
103105
def __init__(self, response):
104-
self.id = response['id'] - 16
106+
self.id = response['id']
105107
self.mode = response['mode']
106108
self.bus = response['bus']
107109
self.pid = response['pid']
108110
self.payload = '0x' + response['payload'][8:]
109111

110112
def addFrame(self, response):
111-
self.payload += response['payload'][8:]
113+
self.payload += response['payload'][2:]
112114

113115
def getResponse(self):
114116
request = {
@@ -170,8 +172,9 @@ def _response_matches_request(self, response):
170172
return response.get('mode', None) == self.diagnostic_request['mode']
171173

172174
def _response_is_multiframe(self, response):
173-
if 'frame' in response:
174-
return True
175+
print(response)
176+
if 'total_size' in response.keys() and response["total_size"] > 0:
177+
return True
175178
return False
176179

177180
def _return_final(self, response):
@@ -427,6 +430,14 @@ def device_id(self):
427430
}
428431
return self._check_command_response_message(request)
429432

433+
def get_vin(self):
434+
"""Request vehicle VIN
435+
"""
436+
request = {
437+
"command": "get_vin"
438+
}
439+
return self._check_command_response_message(request)
440+
430441
def write(self, **kwargs):
431442
"""Serialize a raw or translated write request and send it to the VI,
432443
following the OpenXC message format.

openxc/formats/base.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ class VehicleMessageStreamer(object):
33
bytes_received = 0
44

55
def receive(self, payload):
6-
if not isinstance(payload, bytes):
7-
payload = payload.encode("utf-8")
86
if len(payload) > 0:
97
self.message_buffer += payload
108
self.bytes_received += len(payload)

openxc/formats/binary.py

Lines changed: 47 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ def _handle_diagnostic_cc_message(cls, data, message):
126126
request_command.action = openxc_pb2.DiagnosticControlCommand.CANCEL
127127
request = request_command.request
128128
request_data = data['request']
129-
request.bus = request_data['bus']
129+
if 'bus' in request_data:
130+
request.bus = request_data['bus']
130131
request.message_id = request_data['id']
131132
request.mode = request_data['mode']
132133
if 'frequency' in request_data:
@@ -184,6 +185,10 @@ def _build_diagnostic_message(cls, data, message):
184185
response.bus = data['bus']
185186
response.message_id = data['id']
186187
response.mode = data['mode']
188+
if 'total_size' in data:
189+
response.total_size = data['total_size']
190+
if 'frame' in data:
191+
response.frame = data['frame']
187192
if 'pid' in data:
188193
response.pid = data['pid']
189194
if 'success' in data:
@@ -243,63 +248,57 @@ def _dict_to_protobuf(cls, data):
243248
@classmethod
244249
def _build_can_parsed_message(cls, message, parsed_message):
245250
can_message = message.can_message
246-
if can_message.HasField('bus'):
251+
if can_message.bus != 0:
247252
parsed_message['bus'] = can_message.bus
248-
if can_message.HasField('id'):
253+
if can_message.id != 0:
249254
parsed_message['id'] = can_message.id
250-
if can_message.HasField('data'):
255+
if len(binascii.hexlify(can_message.data).decode("ascii")) > 0:
251256
parsed_message['data'] = "0x%s" % binascii.hexlify(can_message.data).decode("ascii")
252-
if can_message.HasField('frame_format'):
253-
if can_message.frame_format == openxc_pb2.CanMessage.STANDARD:
254-
parsed_message['frame_format'] = "standard"
255-
elif can_message.frame_format == openxc_pb2.CanMessage.EXTENDED:
256-
parsed_message['frame_format'] = "extended"
257+
if can_message.frame_format == openxc_pb2.CanMessage.STANDARD:
258+
parsed_message['frame_format'] = "standard"
259+
elif can_message.frame_format == openxc_pb2.CanMessage.EXTENDED:
260+
parsed_message['frame_format'] = "extended"
257261

258262
@classmethod
259263
def _build_diagnostic_parsed_message(cls, message, parsed_message):
260264
diagnostic_message = message.diagnostic_response
261-
if diagnostic_message.HasField('bus'):
265+
if diagnostic_message.bus != 0:
262266
parsed_message['bus'] = diagnostic_message.bus
263-
if diagnostic_message.HasField('message_id'):
267+
if diagnostic_message.message_id != 0:
264268
parsed_message['id'] = diagnostic_message.message_id
265-
if diagnostic_message.HasField('mode'):
266-
parsed_message['mode'] = diagnostic_message.mode
267-
if diagnostic_message.HasField('pid'):
268-
parsed_message['pid'] = diagnostic_message.pid
269-
if diagnostic_message.HasField('success'):
270-
parsed_message['success'] = diagnostic_message.success
271-
if diagnostic_message.HasField('value'):
269+
parsed_message['mode'] = diagnostic_message.mode
270+
parsed_message['pid'] = diagnostic_message.pid
271+
if diagnostic_message.total_size != 0:
272+
parsed_message['total_size'] = diagnostic_message.total_size
273+
parsed_message['frame'] = diagnostic_message.frame
274+
parsed_message['success'] = diagnostic_message.success
275+
if diagnostic_message.value.type != openxc_pb2.DynamicField.UNUSED: ##GJA
272276
parsed_message['value'] = diagnostic_message.value
273-
if diagnostic_message.HasField('negative_response_code'):
277+
if diagnostic_message.negative_response_code !=0:
274278
parsed_message['negative_response_code'] = diagnostic_message.negative_response_code
275-
if diagnostic_message.HasField('payload'):
279+
if len(binascii.hexlify(diagnostic_message.payload).decode("ascii")) > 0:
276280
parsed_message['payload'] = "0x%s" % binascii.hexlify(diagnostic_message.payload).decode("ascii")
277281

278282
@classmethod
279283
def _build_simple_parsed_message(cls, message, parsed_message):
280284
simple_message = message.simple_message
281285
parsed_message['name'] = simple_message.name
282-
if simple_message.HasField('event'):
283-
event = simple_message.event
284-
if event.HasField('numeric_value'):
285-
parsed_message['event'] = event.numeric_value
286-
elif event.HasField('boolean_value'):
287-
parsed_message['event'] = event.boolean_value
288-
elif event.HasField('string_value'):
289-
parsed_message['event'] = event.string_value
290-
291-
if simple_message.HasField('value'):
292-
value = simple_message.value
293-
if value.HasField('numeric_value'):
294-
parsed_message['value'] = value.numeric_value
295-
elif value.HasField('boolean_value'):
296-
parsed_message['value'] = value.boolean_value
297-
elif value.HasField('string_value'):
298-
parsed_message['value'] = value.string_value
299-
else:
300-
parsed_message = None
286+
event = simple_message.event
287+
if (len(event.string_value) > 0):
288+
parsed_message['event'] = event.string_value
289+
elif event.numeric_value != 0:
290+
parsed_message['event'] = event.numeric_value
301291
else:
302-
parsed_message = None
292+
parsed_message['event'] = event.boolean_value
293+
294+
value = simple_message.value
295+
if (len(value.string_value) > 0):
296+
parsed_message['value'] = value.string_value
297+
elif value.numeric_value != 0:
298+
parsed_message['value'] = value.numeric_value
299+
else:
300+
parsed_message['value'] = value.boolean_value
301+
303302

304303
@classmethod
305304
def _handle_diagnostic_cc_parsed_message(cls, command, parsed_message):
@@ -316,16 +315,16 @@ def _handle_diagnostic_cc_parsed_message(cls, command, parsed_message):
316315
parsed_message['request']['bus'] = request.bus
317316
parsed_message['request']['mode'] = request.mode
318317

319-
if request.HasField('frequency'):
318+
if request.frequency != 0:
320319
parsed_message['request']['frequency'] = request.frequency
321-
if request.HasField('name'):
320+
if len(request.name) > 0:
322321
parsed_message['request']['name'] = request.name
323-
if request.HasField('multiple_responses'):
324-
parsed_message['request']['multiple_responses'] = request.multiple_responses
325-
if request.HasField('pid'):
322+
parsed_message['request']['multiple_responses'] = request.multiple_responses
323+
if request.pid != 0:
326324
parsed_message['request']['pid'] = request.pid
327-
if request.HasField('payload'):
325+
if len(binascii.hexlify(request.payload).decode("ascii")) > 0:
328326
parsed_message['request']['payload'] = "0x%s" % binascii.hexlify(request.payload).decode("ascii")
327+
print("Finished _handle_diagnostic_cc_parsed_message")
329328

330329
@classmethod
331330
def _handle_passthrough_cc_parsed_message(cls, command, parsed_message):
@@ -393,14 +392,14 @@ def _build_command_response_parsed_message(cls, message, parsed_message):
393392
raise UnrecognizedBinaryCommandError(response.type)
394393

395394
parsed_message['status'] = response.status
396-
if response.HasField('message'):
395+
if len(response.message) > 0:
397396
parsed_message['message'] = response.message
398397

399398
@classmethod
400399
def _protobuf_to_dict(cls, message):
401400
parsed_message = {}
402401
if message is not None:
403-
if message.type == message.CAN and message.HasField('can_message'):
402+
if message.type == message.CAN:
404403
cls._build_can_parsed_message(message, parsed_message)
405404
elif message.type == message.DIAGNOSTIC:
406405
cls._build_diagnostic_parsed_message(message, parsed_message)

0 commit comments

Comments
 (0)