Skip to content

Commit 80349e1

Browse files
authored
Abort SDO server upload when the object has zero length (#587)
A data size of zero bytes cannot be encoded in the "number of bytes that do not contain data" semantics, as that would require n=4, which is however limited to two bits (maximum value 3). So the SDO expedited upload protocol simply cannot convey that condition. The current implementation however still tries and thereby corrupts the the reserved, always-zero field value. Avoid that protocol violation by responding with an SDO abort code of 0800 0024h, No data available. Add a test case for this condition, verifying that the client raises the appropriate SdoAbortedError exception.
1 parent de0e644 commit 80349e1

File tree

2 files changed

+12
-1
lines changed

2 files changed

+12
-1
lines changed

canopen/sdo/server.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@ def init_upload(self, request):
6666

6767
data = self._node.get_data(index, subindex, check_readable=True)
6868
size = len(data)
69-
if size <= 4:
69+
if size == 0:
70+
logger.info("No content to upload for 0x%04X:%02X", index, subindex)
71+
self.abort(0x0800_0024)
72+
return
73+
elif size <= 4:
7074
logger.info("Expedited upload for 0x%04X:%02X", index, subindex)
7175
res_command |= EXPEDITED
7276
res_command |= (4 - size) << 2

test/test_local.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ def test_expedited_upload_default_value_real(self):
6262
sampling_rate = self.remote_node.sdo["Sensor Sampling Rate (Hz)"].raw
6363
self.assertAlmostEqual(sampling_rate, 5.2, places=2)
6464

65+
def test_upload_zero_length(self):
66+
self.local_node.sdo["Manufacturer device name"].raw = b""
67+
with self.assertRaises(canopen.SdoAbortedError) as error:
68+
self.remote_node.sdo["Manufacturer device name"].data
69+
# Should be No data available
70+
self.assertEqual(error.exception.code, 0x0800_0024)
71+
6572
def test_segmented_upload(self):
6673
self.local_node.sdo["Manufacturer device name"].raw = "Some cool device"
6774
device_name = self.remote_node.sdo["Manufacturer device name"].data

0 commit comments

Comments
 (0)