Package: release.debian.org
Severity: normal
User: release.debian....@packages.debian.org
Usertags: unblock

Please unblock package sireader

This fixes an at least important bug (probably even grave). The package
currently in testing does not work with Python 3.x at all. It throws an
Exception as soon as you try to do something usefull.

This includes an upstream update which fixes the Python 3.x
compatibility. I'm also the upstream author of the code and think this
is the right way to update this. There are now other changes in this
upstream update. The risks are really small as nothing depends on
sireader at the moment.

The debdiff is attached.

unblock sireader/1.0.2-1

-- System Information:
Debian Release: jessie/sid
  APT prefers testing
  APT policy: (500, 'testing'), (100, 'unstable'), (1, 'experimental')
Architecture: amd64 (x86_64)

Kernel: Linux 3.16-3-amd64 (SMP w/4 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
diff -Nru sireader-1.0.1/debian/changelog sireader-1.0.2/debian/changelog
--- sireader-1.0.1/debian/changelog	2014-09-30 23:22:03.000000000 +0200
+++ sireader-1.0.2/debian/changelog	2014-11-05 11:51:21.000000000 +0100
@@ -1,3 +1,10 @@
+sireader (1.0.2-1) unstable; urgency=medium
+
+  * New upstream release
+    - Fix Python 3 compatibility (Closes: #767292)
+
+ -- Gaudenz Steinlin <gaud...@debian.org>  Wed, 05 Nov 2014 11:51:16 +0100
+
 sireader (1.0.1-1) unstable; urgency=medium
 
   * Initial release (Closes: #763548)
diff -Nru sireader-1.0.1/PKG-INFO sireader-1.0.2/PKG-INFO
--- sireader-1.0.1/PKG-INFO	2014-09-30 23:15:52.000000000 +0200
+++ sireader-1.0.2/PKG-INFO	2014-11-05 11:44:55.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: sireader
-Version: 1.0.1
+Version: 1.0.2
 Summary: Python module to communicate with SportIdent main stations
 Home-page: http://bosco.durcheinandertal.ch/
 Author: Gaudenz Steinlin
diff -Nru sireader-1.0.1/setup.py sireader-1.0.2/setup.py
--- sireader-1.0.1/setup.py	2014-09-30 23:12:04.000000000 +0200
+++ sireader-1.0.2/setup.py	2014-11-05 11:44:05.000000000 +0100
@@ -11,7 +11,7 @@
 setup(
     name='sireader',
 
-    version='1.0.1',
+    version='1.0.2',
 
     description='Python module to communicate with SportIdent main stations',
     long_description=long_description,
@@ -59,5 +59,5 @@
     # project is installed. For an analysis of "install_requires" vs pip's
     # requirements files see:
     # https://packaging.python.org/en/latest/technical.html#install-requires-vs-requirements-files
-    install_requires=['pyserial'],
+    install_requires=['pyserial', 'six'],
 )
diff -Nru sireader-1.0.1/sireader.egg-info/PKG-INFO sireader-1.0.2/sireader.egg-info/PKG-INFO
--- sireader-1.0.1/sireader.egg-info/PKG-INFO	2014-09-30 23:15:52.000000000 +0200
+++ sireader-1.0.2/sireader.egg-info/PKG-INFO	2014-11-05 11:44:55.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: sireader
-Version: 1.0.1
+Version: 1.0.2
 Summary: Python module to communicate with SportIdent main stations
 Home-page: http://bosco.durcheinandertal.ch/
 Author: Gaudenz Steinlin
diff -Nru sireader-1.0.1/sireader.egg-info/requires.txt sireader-1.0.2/sireader.egg-info/requires.txt
--- sireader-1.0.1/sireader.egg-info/requires.txt	2014-09-30 23:15:52.000000000 +0200
+++ sireader-1.0.2/sireader.egg-info/requires.txt	2014-11-05 11:44:55.000000000 +0100
@@ -1 +1,2 @@
 pyserial
+six
diff -Nru sireader-1.0.1/sireader.py sireader-1.0.2/sireader.py
--- sireader-1.0.1/sireader.py	2014-09-14 22:00:55.000000000 +0200
+++ sireader-1.0.2/sireader.py	2014-11-05 11:34:58.000000000 +0100
@@ -20,6 +20,18 @@
 """
 
 from __future__ import print_function
+from six import int2byte, byte2int, iterbytes, PY3
+if PY3:
+    # Make byte2int on Python 3.x compatible with
+    # the fact that indexing into a byte variable
+    # already returns an integer. With this byte2int(b[0])
+    # works on 2.x and 3.x
+    def byte2int(x):
+        try:
+            return x[0]
+        except TypeError:
+            return x
+
 from serial import Serial
 from serial.serialutil import SerialException
 from datetime import datetime, timedelta, time
@@ -36,149 +48,149 @@
     CRC_BITF         = 0x8000
 
     # Protocol characters
-    STX              = '\x02'
-    ETX              = '\x03'
-    ACK              = '\x06' # when sent to BSx3..6 with a card inserted, causes beep until SI-card taken out
-    NAK              = '\x15'
-    DLE              = '\x10'
-    WAKEUP           = '\xFF'
+    STX              = b'\x02'
+    ETX              = b'\x03'
+    ACK              = b'\x06' # when sent to BSx3..6 with a card inserted, causes beep until SI-card taken out
+    NAK              = b'\x15'
+    DLE              = b'\x10'
+    WAKEUP           = b'\xFF'
 
     # Basic protocol commands, currently unused
-    BC_SET_CARDNO    = '\x30'
-    BC_GET_SI5       = '\x31' # read out SI-card 5 data
-    BC_TRANS_REC     = '\x33' # autosend timestamp (online control) in very old stations (BSF3)
-    BC_SI5_WRITE     = '\x43' # write SI-card 5 data page: 02 43 (page: 0x30 to 0x37) (16 bytes) 03
-    BC_SI5_DET       = '\x46' # SI-card 5 inserted (46 49) or removed (46 4F)
-    BC_TRANS_REC2    = '\x53' # autosend timestamp (online control)
-    BC_TRANS_TIME    = '\x54' # autosend timestamp (lightbeam trigger)
-    BC_GET_SI6       = '\x61' # read out SI-card 6 data (and in compatibility mode: model SI-card 8/9/10/11/SIAC/pCard/tCard as SI-card 6)
-    BC_SI6_WRITEPAGE = '\x62'# write SI-card 6 data page: 02 62 (block: 0x00 to 0x07) (page: 0x00 to 0x07) (16 bytes) 03
-    BC_SI6_READWORD  = '\x63'# read SI-card 6 data word: 02 63 (block: 0x00 to 0x07) (page: 0x00 to 0x07) (word: 0x00 to 0x03) 03
-    BC_SI6_WRITEWORD = '\x64'# write SI-card 6 data word: 02 64 (block: 0x00 to 0x07) (page: 0x00 to 0x07) (word: 0x00 to 0x03) (4 bytes) 03
-    BC_SI6_DET       = '\x66' # SI-card 6 inserted
-    BC_SET_MS        = '\x70' # \x4D="M"aster, \x53="S"lave
-    BC_GET_MS        = '\x71'
-    BC_SET_SYS_VAL   = '\x72'
-    BC_GET_SYS_VAL   = '\x73'
-    BC_GET_BACKUP    = '\x74' # Note: response carries '\xC4'!
-    BC_ERASE_BACKUP  = '\x75'
-    BC_SET_TIME      = '\x76'
-    BC_GET_TIME      = '\x77'
-    BC_OFF           = '\x78'
-    BC_RESET         = '\x79'
-    BC_GET_BACKUP2   = '\x7A' # (for extended start and extended finish only) Note: response carries '\xCA'!
-    BC_SET_BAUD      = '\x7E' # \x00=4800 baud, \x01=38400 baud
+    BC_SET_CARDNO    = b'\x30'
+    BC_GET_SI5       = b'\x31' # read out SI-card 5 data
+    BC_TRANS_REC     = b'\x33' # autosend timestamp (online control) in very old stations (BSF3)
+    BC_SI5_WRITE     = b'\x43' # write SI-card 5 data page: 02 43 (page: 0x30 to 0x37) (16 bytes) 03
+    BC_SI5_DET       = b'\x46' # SI-card 5 inserted (46 49) or removed (46 4F)
+    BC_TRANS_REC2    = b'\x53' # autosend timestamp (online control)
+    BC_TRANS_TIME    = b'\x54' # autosend timestamp (lightbeam trigger)
+    BC_GET_SI6       = b'\x61' # read out SI-card 6 data (and in compatibility mode: model SI-card 8/9/10/11/SIAC/pCard/tCard as SI-card 6)
+    BC_SI6_WRITEPAGE = b'\x62'# write SI-card 6 data page: 02 62 (block: 0x00 to 0x07) (page: 0x00 to 0x07) (16 bytes) 03
+    BC_SI6_READWORD  = b'\x63'# read SI-card 6 data word: 02 63 (block: 0x00 to 0x07) (page: 0x00 to 0x07) (word: 0x00 to 0x03) 03
+    BC_SI6_WRITEWORD = b'\x64'# write SI-card 6 data word: 02 64 (block: 0x00 to 0x07) (page: 0x00 to 0x07) (word: 0x00 to 0x03) (4 bytes) 03
+    BC_SI6_DET       = b'\x66' # SI-card 6 inserted
+    BC_SET_MS        = b'\x70' # \x4D="M"aster, \x53="S"lave
+    BC_GET_MS        = b'\x71'
+    BC_SET_SYS_VAL   = b'\x72'
+    BC_GET_SYS_VAL   = b'\x73'
+    BC_GET_BACKUP    = b'\x74' # Note: response carries b'\xC4'!
+    BC_ERASE_BACKUP  = b'\x75'
+    BC_SET_TIME      = b'\x76'
+    BC_GET_TIME      = b'\x77'
+    BC_OFF           = b'\x78'
+    BC_RESET         = b'\x79'
+    BC_GET_BACKUP2   = b'\x7A' # (for extended start and extended finish only) Note: response carries b'\xCA'!
+    BC_SET_BAUD      = b'\x7E' # \x00=4800 baud, \x01=38400 baud
 
     # Extended protocol commands
-    C_GET_BACKUP     = '\x81'
-    C_SET_SYS_VAL    = '\x82'
-    C_GET_SYS_VAL    = '\x83'
-    C_SRR_WRITE      = '\xA2' # ShortRangeRadio - SysData write
-    C_SRR_READ       = '\xA3' # ShortRangeRadio - SysData read
-    C_SRR_QUERY      = '\xA6' # ShortRangeRadio - network device query
-    C_SRR_PING       = '\xA7' # ShortRangeRadio - heartbeat from linked devices, every 50 seconds
-    C_SRR_ADHOC      = '\xA8' # ShortRangeRadio - ad-hoc message, f.ex. from SI-ActiveCard
-    C_GET_SI5        = '\xB1' # read out SI-card 5 data
-    C_SI5_WRITE      = '\xC3' # write SI-card 5 data page: 02 C3 11 (page: 0x00 to 0x07) (16 bytes) (CRC) 03
-    C_TRANS_REC      = '\xD3' # autosend timestamp (online control)
-    C_CLEAR_CARD     = '\xE0' # found on SI-dev-forum: 02 E0 00 E0 00 03 (http://www.sportident.com/index.php?option=com_kunena&view=topic&catid=8&id=56#59)
-    C_GET_SI6        = '\xE1' # read out SI-card 6 data block
-    C_SI5_DET        = '\xE5' # SI-card 5 inserted
-    C_SI6_DET        = '\xE6' # SI-card 6 inserted
-    C_SI_REM         = '\xE7' # SI-card removed
-    C_SI9_DET        = '\xE8' # SI-card 8/9/10/11/p/t inserted
-    C_SI9_WRITE      = '\xEA' # write data page (double-word)
-    C_GET_SI9        = '\xEF' # read out SI-card 8/9/10/11/p/t data block
-    C_SET_MS         = '\xF0' # \x4D="M"aster, \x53="S"lave
-    C_GET_MS         = '\xF1'
-    C_ERASE_BACKUP   = '\xF5'
-    C_SET_TIME       = '\xF6'
-    C_GET_TIME       = '\xF7'
-    C_OFF            = '\xF8'
-    C_BEEP           = '\xF9' # 02 F9 01 (number of beeps) (CRC16) 03
-    C_SET_BAUD       = '\xFE' # \x00=4800 baud, \x01=38400 baud
+    C_GET_BACKUP     = b'\x81'
+    C_SET_SYS_VAL    = b'\x82'
+    C_GET_SYS_VAL    = b'\x83'
+    C_SRR_WRITE      = b'\xA2' # ShortRangeRadio - SysData write
+    C_SRR_READ       = b'\xA3' # ShortRangeRadio - SysData read
+    C_SRR_QUERY      = b'\xA6' # ShortRangeRadio - network device query
+    C_SRR_PING       = b'\xA7' # ShortRangeRadio - heartbeat from linked devices, every 50 seconds
+    C_SRR_ADHOC      = b'\xA8' # ShortRangeRadio - ad-hoc message, f.ex. from SI-ActiveCard
+    C_GET_SI5        = b'\xB1' # read out SI-card 5 data
+    C_SI5_WRITE      = b'\xC3' # write SI-card 5 data page: 02 C3 11 (page: 0x00 to 0x07) (16 bytes) (CRC) 03
+    C_TRANS_REC      = b'\xD3' # autosend timestamp (online control)
+    C_CLEAR_CARD     = b'\xE0' # found on SI-dev-forum: 02 E0 00 E0 00 03 (http://www.sportident.com/index.php?option=com_kunena&view=topic&catid=8&id=56#59)
+    C_GET_SI6        = b'\xE1' # read out SI-card 6 data block
+    C_SI5_DET        = b'\xE5' # SI-card 5 inserted
+    C_SI6_DET        = b'\xE6' # SI-card 6 inserted
+    C_SI_REM         = b'\xE7' # SI-card removed
+    C_SI9_DET        = b'\xE8' # SI-card 8/9/10/11/p/t inserted
+    C_SI9_WRITE      = b'\xEA' # write data page (double-word)
+    C_GET_SI9        = b'\xEF' # read out SI-card 8/9/10/11/p/t data block
+    C_SET_MS         = b'\xF0' # \x4D="M"aster, \x53="S"lave
+    C_GET_MS         = b'\xF1'
+    C_ERASE_BACKUP   = b'\xF5'
+    C_SET_TIME       = b'\xF6'
+    C_GET_TIME       = b'\xF7'
+    C_OFF            = b'\xF8'
+    C_BEEP           = b'\xF9' # 02 F9 01 (number of beeps) (CRC16) 03
+    C_SET_BAUD       = b'\xFE' # \x00=4800 baud, \x01=38400 baud
 
     # Protocol Parameters
-    P_MS_DIRECT      = '\x4D' # "M"aster
-    P_MS_INDIRECT    = '\x53' # "S"lave
-    P_SI6_CB         = '\x08' # CardBlocks (see also O_SI6_CB)
+    P_MS_DIRECT      = b'\x4D' # "M"aster
+    P_MS_INDIRECT    = b'\x53' # "S"lave
+    P_SI6_CB         = b'\x08' # CardBlocks (see also O_SI6_CB)
 
     # offsets in system data
     # Thanks to Simon Harston <si...@harston.de> for most of this information
     # currently only O_MODE, O_STATION_CODE and O_PROTO are used
-    O_OLD_SERIAL     = '\x00' # 2 bytes - only up to BSx6, numbers < 65.536
-    O_OLD_CPU_ID     = '\x02' # 2 bytes - only up to BSx6, numbers < 65.536
-    O_SERIAL_NO      = '\x00' # 4 bytes - only after BSx7, numbers > 70.000
-                              #   (if byte 0x00 > 0, better use OLD offsets)
-    O_SRR_CFG        = '\x04' # 1 byte - SRR-dongle configuration, bit mask value:
-                              #   xxxxxx1xb Auto send SIAC data
-                              #   xxxxx1xxb Sync time via radio
-    O_FIRMWARE       = '\x05' # 3 bytes
-    O_BUILD_DATE     = '\x08' # 3 bytes - YYMMDD
-    O_MODEL_ID       = '\x0B' # 2 bytes:
-                              #   6F21: SIMSRR1-AP (ShortRangeRadio AccessPoint = SRR-dongle)
-                              #   8003: BSF3 (serial numbers > 1.000)
-                              #   8004: BSF4 (serial numbers > 10.000)
-                              #   8084: BSM4-RS232
-                              #   8086: BSM6-RS232 / BSM6-USB
-                              #   8115: BSF5 (serial numbers > 50.000)
-                              #   8117 / 8118: BSF7 / BSF8 (serial no. 70.000...70.521, 72.002...72.009)
-                              #   8146: BSF6 (serial numbers > 30.000)
-                              #   8187 / 8188: BS7-SI-Master / BS8-SI-Master
-                              #   8197: BSF7 (serial numbers > 71.000, apart from 72.002...72.009)
-                              #   8198: BSF8 (serial numbers > 80.000)
-                              #   9197 / 9198: BSM7-RS232, BSM7-USB / BSM8-USB, BSM8-SRR
-                              #   9199: unknown
-                              #   9597: BS7-S (Sprinter)
-                              #   9D9A: BS11-BL (SIAC / Air+)
-                              #   B197 / B198: BS7-P / BS8-P (Printer)
-                              #   B897: BS7-GSM
-                              #   CD9B: BS11-BS-red / BS11-BS-blue (SIAC / Air+)
-
-    O_MEM_SIZE       = '\x0D' # 1 byte - in KB
-    O_BAT_DATE       = '\x15' # 3 bytes - YYMMDD
-    O_BAT_CAP        = '\x19' # 2 bytes - battery capacity in mAh (as multiples of 14.0625?!)
-    O_BACKUP_PTR     = '\x1C' # 4 bytes - at positions 1C,1D,21,22
-    O_SI6_CB         = '\x33' # 1 byte - bitfield defining which SI Card 6 blocks to read:
-                              #   \x00=\xC1=read block0,6,7; \x08=\xFF=read all 8 blocks
-    O_SRR_CHANNEL    = '\x34' # 1 byte - SRR-dongle frequency band: 0x00="red", 0x01="blue"
-    O_MEM_OVERFLOW   = '\x3D' # 1 byte - memory overflow if != 0x00
-    O_PROGRAM        = '\x70' # 1 byte - station program: xx0xxxxxb competition, xx1xxxxxb training
-    O_MODE           = '\x71' # 1 byte - see SI station modes below
-    O_STATION_CODE   = '\x72' # 1 byte
-    O_FEEDBACK       = '\x73' # 1 byte - feedback on punch (and other unknown bits), bit mask value:
-                              #   xxxxxxx1b optical feedback
-                              #   xxxxx1xxb audible feedback
-    O_PROTO          = '\x74' # 1 byte - protocol configuration, bit mask value:
-                              #   xxxxxxx1b extended protocol
-                              #   xxxxxx1xb auto send out
-                              #   xxxxx1xxb handshake (only valid for card readout)
-                              #   xxx1xxxxb access with password only
-                              #   1xxxxxxxb read out SI-card after punch (only for punch modes;
-                              #             depends on bit 2: auto send out or handshake)
-    O_WAKEUP_DATE    = '\x75' # 3 bytes - YYMMDD
-    O_WAKEUP_TIME    = '\x78' # 3 bytes - 1 byte day (see below), 2 bytes seconds after midnight/midday
-    O_SLEEP_TIME     = '\x7B' # 3 bytes - 1 byte day (see below), 2 bytes seconds after midnight/midday
-                              #   xxxxxxx0b - seconds relative to midnight/midday: 0 = am, 1 = pm
-                              #   xxxx000xb - day of week: 000 = Sunday, 110 = Saturday
-                              #   xx00xxxxb - week counter 0..3, relative to programming date
+    O_OLD_SERIAL     = b'\x00' # 2 bytes - only up to BSx6, numbers < 65.536
+    O_OLD_CPU_ID     = b'\x02' # 2 bytes - only up to BSx6, numbers < 65.536
+    O_SERIAL_NO      = b'\x00' # 4 bytes - only after BSx7, numbers > 70.000
+                               #   (if byte 0x00 > 0, better use OLD offsets)
+    O_SRR_CFG        = b'\x04' # 1 byte - SRR-dongle configuration, bit mask value:
+                               #   xxxxxx1xb Auto send SIAC data
+                               #   xxxxx1xxb Sync time via radio
+    O_FIRMWARE       = b'\x05' # 3 bytes
+    O_BUILD_DATE     = b'\x08' # 3 bytes - YYMMDD
+    O_MODEL_ID       = b'\x0B' # 2 bytes:
+                               #   6F21: SIMSRR1-AP (ShortRangeRadio AccessPoint = SRR-dongle)
+                               #   8003: BSF3 (serial numbers > 1.000)
+                               #   8004: BSF4 (serial numbers > 10.000)
+                               #   8084: BSM4-RS232
+                               #   8086: BSM6-RS232 / BSM6-USB
+                               #   8115: BSF5 (serial numbers > 50.000)
+                               #   8117 / 8118: BSF7 / BSF8 (serial no. 70.000...70.521, 72.002...72.009)
+                               #   8146: BSF6 (serial numbers > 30.000)
+                               #   8187 / 8188: BS7-SI-Master / BS8-SI-Master
+                               #   8197: BSF7 (serial numbers > 71.000, apart from 72.002...72.009)
+                               #   8198: BSF8 (serial numbers > 80.000)
+                               #   9197 / 9198: BSM7-RS232, BSM7-USB / BSM8-USB, BSM8-SRR
+                               #   9199: unknown
+                               #   9597: BS7-S (Sprinter)
+                               #   9D9A: BS11-BL (SIAC / Air+)
+                               #   B197 / B198: BS7-P / BS8-P (Printer)
+                               #   B897: BS7-GSM
+                               #   CD9B: BS11-BS-red / BS11-BS-blue (SIAC / Air+)
+
+    O_MEM_SIZE       = b'\x0D' # 1 byte - in KB
+    O_BAT_DATE       = b'\x15' # 3 bytes - YYMMDD
+    O_BAT_CAP        = b'\x19' # 2 bytes - battery capacity in mAh (as multiples of 14.0625?!)
+    O_BACKUP_PTR     = b'\x1C' # 4 bytes - at positions 1C,1D,21,22
+    O_SI6_CB         = b'\x33' # 1 byte - bitfield defining which SI Card 6 blocks to read:
+                               #   \x00=\xC1=read block0,6,7; \x08=\xFF=read all 8 blocks
+    O_SRR_CHANNEL    = b'\x34' # 1 byte - SRR-dongle frequency band: 0x00="red", 0x01="blue"
+    O_MEM_OVERFLOW   = b'\x3D' # 1 byte - memory overflow if != 0x00
+    O_PROGRAM        = b'\x70' # 1 byte - station program: xx0xxxxxb competition, xx1xxxxxb training
+    O_MODE           = b'\x71' # 1 byte - see SI station modes below
+    O_STATION_CODE   = b'\x72' # 1 byte
+    O_FEEDBACK       = b'\x73' # 1 byte - feedback on punch (and other unknown bits), bit mask value:
+                               #   xxxxxxx1b optical feedback
+                               #   xxxxx1xxb audible feedback
+    O_PROTO          = b'\x74' # 1 byte - protocol configuration, bit mask value:
+                               #   xxxxxxx1b extended protocol
+                               #   xxxxxx1xb auto send out
+                               #   xxxxx1xxb handshake (only valid for card readout)
+                               #   xxx1xxxxb access with password only
+                               #   1xxxxxxxb read out SI-card after punch (only for punch modes;
+                               #             depends on bit 2: auto send out or handshake)
+    O_WAKEUP_DATE    = b'\x75' # 3 bytes - YYMMDD
+    O_WAKEUP_TIME    = b'\x78' # 3 bytes - 1 byte day (see below), 2 bytes seconds after midnight/midday
+    O_SLEEP_TIME     = b'\x7B' # 3 bytes - 1 byte day (see below), 2 bytes seconds after midnight/midday
+                               #   xxxxxxx0b - seconds relative to midnight/midday: 0 = am, 1 = pm
+                               #   xxxx000xb - day of week: 000 = Sunday, 110 = Saturday
+                               #   xx00xxxxb - week counter 0..3, relative to programming date
 
     # SI station modes
-    M_SIAC_SPECIAL     = '\x01' # SI Air+ special register set (ON, OFF, Radio_ReadOut, etc.)
-    M_CONTROL          = '\x02'
-    M_START            = '\x03'
-    M_FINISH           = '\x04'
-    M_READOUT          = '\x05'
-    M_CLEAR_OLD        = '\x06' # without start-number (not used anymore)
-    M_CLEAR            = '\x07' # with start-number = standard
-    M_CHECK            = '\x0A'
-    M_PRINTOUT         = '\x0B' # BS7-P Printer-station (Note: also used by SRR-Receiver-module)
-    M_START_TRIG       = '\x0C' # BS7-S (Sprinter) with external trigger
-    M_FINISH_TRIG      = '\x0D' # BS7-S (Sprinter) with external trigger
-    M_BC_CONTROL       = '\x12' # SI Air+ / SIAC Beacon mode
-    M_BC_START         = '\x13' # SI Air+ / SIAC Beacon mode
-    M_BC_FINISH        = '\x14' # SI Air+ / SIAC Beacon mode
-    M_BC_READOUT       = '\x15' # SI Air+ / SIAC Beacon mode
+    M_SIAC_SPECIAL     = 0x01 # SI Air+ special register set (ON, OFF, Radio_ReadOut, etc.)
+    M_CONTROL          = 0x02
+    M_START            = 0x03
+    M_FINISH           = 0x04
+    M_READOUT          = 0x05
+    M_CLEAR_OLD        = 0x06 # without start-number (not used anymore)
+    M_CLEAR            = 0x07 # with start-number = standard
+    M_CHECK            = 0x0A
+    M_PRINTOUT         = 0x0B # BS7-P Printer-station (Note: also used by SRR-Receiver-module)
+    M_START_TRIG       = 0x0C # BS7-S (Sprinter) with external trigger
+    M_FINISH_TRIG      = 0x0D # BS7-S (Sprinter) with external trigger
+    M_BC_CONTROL       = 0x12 # SI Air+ / SIAC Beacon mode
+    M_BC_START         = 0x13 # SI Air+ / SIAC Beacon mode
+    M_BC_FINISH        = 0x14 # SI Air+ / SIAC Beacon mode
+    M_BC_READOUT       = 0x15 # SI Air+ / SIAC Beacon mode
     SUPPORTED_MODES    = (M_CONTROL, M_START, M_FINISH, M_READOUT, M_CLEAR, M_CHECK)
 
     # Weekday encoding (only for reference, currently unused)
@@ -195,7 +207,7 @@
     REC_LEN            = 8 # Only in extended protocol, otherwise 6!
 
     # General card data structure values
-    TIME_RESET         = '\xEE\xEE'
+    TIME_RESET         = b'\xEE\xEE'
 
     # SI Card data structures
     CARD               = {'SI5':{'CN2': 6,   # card number byte 2
@@ -346,9 +358,9 @@
         @param mode: operating mode, supported modes: M_CONTROL, M_START, M_FINISH, M_READOUT, M_CLEAR, M_CHECK
         """
         if not mode in SIReader.SUPPORTED_MODES:
-            raise SIReaderException("Unsupported mode '%s'!" % ord(mode))
+            raise SIReaderException("Unsupported mode '%i'!" % mode)
         try:
-            self._send_command(SIReader.C_SET_SYS_VAL, SIReader.O_MODE + mode)
+            self._send_command(SIReader.C_SET_SYS_VAL, SIReader.O_MODE + int2byte(mode))
         finally:
             self._update_proto_config()
         self.beep()
@@ -360,9 +372,9 @@
         if code < 1 or code > 1023:
             raise SIReaderException("Invalid control code: '%i'! Supported code range: 1-1023." % code)
         # lower byte of control code
-        code_low = chr(code & 0xFF)
+        code_low = int2byte(code & 0xFF)
         # high byte of control code, only first 2 bits are used, the rest is set to 1
-        code_high = chr((code >> 2) | 0b00111111)
+        code_high = int2byte((code >> 2) | 0b00111111)
         try:
             self._send_command(SIReader.C_SET_SYS_VAL, SIReader.O_STATION_CODE + code_low + code_high)
         finally:
@@ -373,17 +385,17 @@
         """Read out stations internal time.
         @return: datetime
         """
-        bintime = self._send_command(SIReader.C_GET_TIME, '')[1]
-        year = SIReader._to_int(bintime[0])
-        month = SIReader._to_int(bintime[1])
-        day = SIReader._to_int(bintime[2])
-        am_pm = SIReader._to_int(bintime[3]) & 0b1
+        bintime = self._send_command(SIReader.C_GET_TIME, b'')[1]
+        year = byte2int(bintime[0])
+        month = byte2int(bintime[1])
+        day = byte2int(bintime[2])
+        am_pm = byte2int(bintime[3]) & 0b1
         second = SIReader._to_int(bintime[4:6])
         hour = am_pm * 12 + second // 3600
         second %= 3600
         minute = second // 60
         second %= 60
-        ms = int(round(SIReader._to_int(bintime[6]) / 256.0 * 1000000))
+        ms = int(round(byte2int(bintime[6]) / 256.0 * 1000000))
         self.beep()
         try:
             return datetime(year, month, day, hour, minute, second, ms)
@@ -411,11 +423,11 @@
         inserted into the station.
         @param count: Count of beeps
         """
-        self._send_command(SIReader.C_BEEP, chr(count)) 
+        self._send_command(SIReader.C_BEEP, int2byte(count))
 
     def poweroff(self):
         """Switch off the control station and disconnect."""
-        self._send_command(SIReader.C_OFF, '')
+        self._send_command(SIReader.C_OFF, b'')
         self.disconnect()
 
     def disconnect(self):
@@ -466,8 +478,8 @@
 
     def _update_proto_config(self):
         # Read protocol configuration
-        ret = self._send_command(SIReader.C_GET_SYS_VAL, SIReader.O_PROTO+'\x01')
-        config_byte = ord(ret[1][1])
+        ret = self._send_command(SIReader.C_GET_SYS_VAL, SIReader.O_PROTO+b'\x01')
+        config_byte = byte2int(ret[1][1])
         self.proto_config = {}
         self.proto_config['ext_proto']  = config_byte & (1 << 0) != 0
         self.proto_config['auto_send']  = config_byte & (1 << 1) != 0
@@ -476,18 +488,18 @@
         self.proto_config['punch_read'] = config_byte & (1 << 7) != 0
 
         # Read operating mode
-        ret = self._send_command(SIReader.C_GET_SYS_VAL, SIReader.O_MODE+'\x01')
-        self.proto_config['mode'] = ret[1][1]
+        ret = self._send_command(SIReader.C_GET_SYS_VAL, SIReader.O_MODE+b'\x01')
+        self.proto_config['mode'] = byte2int(ret[1][1])
 
         return self.proto_config
         
     def _set_proto_config(self, config):
         try:
-            config_byte = chr((config['ext_proto'] << 0) |
-                              (config['auto_send'] << 1) |
-                              (config['handshake'] << 2) |
-                              (config['pw_access'] << 4) |
-                              (config['punch_read'] << 7))
+            config_byte = int2byte((config['ext_proto'] << 0) |
+                                   (config['auto_send'] << 1) |
+                                   (config['handshake'] << 2) |
+                                   (config['pw_access'] << 4) |
+                                   (config['punch_read'] << 7))
             self._send_command(SIReader.C_SET_SYS_VAL, SIReader.O_PROTO + config_byte)
         finally:
             self._update_proto_config()
@@ -500,20 +512,24 @@
     def _to_int(s):
         """Computes the integer value of a raw byte string."""
         value = 0
-        for offset, c in enumerate(s[::-1]):
-            value += ord(c) << offset*8
+        for offset, c in enumerate(iterbytes(s[::-1])):
+            value += c << offset*8
         return value
 
     @staticmethod
     def _to_str(i, len):
         """
         @param i:   Integer to convert into str
-        @param len: Length of the return value. If i does not fit it's truncated.
+        @param len: Length of the return value. If i does not fit OverflowError is raised.
         @return:    string representation of i (MSB first)
         """
+        if PY3:
+            return i.to_bytes(len, 'big')
+        if i >> len*8 != 0:
+            raise OverflowError('%i too big to convert to %i bytes' % (i, len))
         string = ''
         for offset in range(len-1, -1, -1):
-            string += chr((i >> offset*8) & 0xFF)
+            string += int2byte((i >> offset*8) & 0xFF)
         return string
 
     @staticmethod
@@ -530,15 +546,15 @@
             
             # add 0 to the string and make it even length
             if len(s)%2 == 0:
-                s += '\x00\x00'
+                s += b'\x00\x00'
             else:
-                s += '\x00'
+                s += b'\x00'
             for i in range(0, len(s), 2):
                 yield s[i:i+2]
 
         if len(s) < 1:
             # return value for 1 or no data byte is 0
-            return '\x00\x00'
+            return b'\x00\x00'
         
         crc = SIReader._to_int(s[0:2])
         
@@ -563,7 +579,7 @@
 
         # truncate to 16 bit and convert to char
         crc &= 0xFFFF
-        return chr(crc >> 8) + chr(crc & 0xFF)
+        return int2byte(crc >> 8) + int2byte(crc & 0xFF)
 
     @staticmethod
     def _crc_check(s, crc):
@@ -595,18 +611,18 @@
            (500'000 = 0x07A120 > 0x04FFFF = 465'535 = highest technically possible value on a SI5)
         """
         
-        if number[0] != '\x00':
+        if number[0:1] != b'\x00':
             raise SIReaderException('Unknown card series')
         
         nr = SIReader._to_int(number[1:4])
         if nr < 500000:
             # SI5 card
             ret = SIReader._to_int(number[2:4])
-            if ord(number[1]) < 2:
+            if byte2int(number[1]) < 2:
 	        # Card series 0 and 1 do not have the 0/1 printed on the card
                 return ret
             else:
-                return ord(number[1])*100000 + ret
+                return byte2int(number[1])*100000 + ret
         else:
             # SI6/8/9
             return nr
@@ -660,10 +676,12 @@
         ret = {}
         card = SIReader.CARD[card_type]
         
-        ret['card_number'] = SIReader._decode_cardnr('\x00'
-                                                     + data[card['CN2']]
-                                                     + data[card['CN1']]
-                                                     + data[card['CN0']])
+        # the slicing of data is necessary for Python 3 to get a bytes object instead
+        # of an int
+        ret['card_number'] = SIReader._decode_cardnr(b'\x00'
+                                                     + data[card['CN2']:card['CN2']+1]
+                                                     + data[card['CN1']:card['CN1']+1]
+                                                     + data[card['CN0']:card['CN0']+1])
         ret['start'] = SIReader._decode_time(data[card['ST']:card['ST']+2],
                                              reftime)
         ret['finish'] = SIReader._decode_time(data[card['FT']:card['FT']+2],
@@ -676,7 +694,7 @@
         else:
             ret['clear'] = None # SI 5 and 9 cards don't store the clear time
 
-        punch_count = ord(data[card['RC']])
+        punch_count = byte2int(data[card['RC']:card['RC']+1])
         if card_type == 'SI5':
             # RC is the index of the next punch on SI5
             punch_count -= 1
@@ -685,15 +703,16 @@
             punch_count = card['PM']
             
         ret['punches'] = []
-        p = i = 0
+        p = 0
+        i = card['P1']
         while p < punch_count:
             if card_type == 'SI5' and i % 16 == 0:
                 # first byte of each block is reserved for punches 31-36
                 i += 1
+
             SIReader._append_punch(ret['punches'],
-                                   ord(data[card['P1'] + i + card['CN']]),
-                                   data[card['P1'] + i + card['PTH']] +
-                                   data[card['P1'] + i + card['PTL']],
+                                   byte2int(data[i + card['CN']]),
+                                   data[i + card['PTH']:i + card['PTL']+1],
                                    reftime)
             i += card['PL']
             p += 1
@@ -704,7 +723,7 @@
         try:
             if self._serial.inWaiting() != 0:
                 raise SIReaderException('Input buffer must be empty before sending command. Currently %s bytes in the input buffer.' % self._serial.inWaiting())
-            command_string = command + chr(len(parameters)) + parameters
+            command_string = command + int2byte(len(parameters)) + parameters
             crc = SIReader._crc(command_string)
             cmd = SIReader.STX + command_string + crc + SIReader.ETX
             if self._debug:
@@ -732,26 +751,26 @@
             if timeout != None:
                 self._serial.timeout = old_timeout
 
-            if char == '':
+            if char == b'':
                 raise SIReaderTimeout('No data available')
             elif char == SIReader.NAK:
                 raise SIReaderException('Invalid command or parameter.')
             elif char != SIReader.STX:
                 self._serial.flushInput()
-                raise SIReaderException('Invalid start byte %s' % hex(ord(char))) 
+                raise SIReaderException('Invalid start byte %s' % hex(byte2int(char)))
 
             # Read command, length, data, crc, ETX
             cmd = self._serial.read()
             length = self._serial.read()
             station = self._serial.read(2)
             self.station_code = SIReader._to_int(station)
-            data = self._serial.read(ord(length)-2)
+            data = self._serial.read(byte2int(length)-2)
             crc = self._serial.read(2)
             etx = self._serial.read()
 
             if self._debug:
                 print("<<== command '%s', len %i, station %s, data %s, crc %s, etx %s" % (hexlify(cmd),
-                                                                                          ord(length),
+                                                                                          byte2int(length),
                                                                                           hexlify(station),
                                                                                           ' '.join([hexlify(c) for c in data]),
                                                                                           hexlify(crc),
@@ -809,7 +828,7 @@
                     
         return not oldcard == self.sicard
 
-    def read_sicard(self):
+    def read_sicard(self, reftime=None):
         """Reads out the SI Card currently inserted into the station. The card must be
         detected with poll_sicard before."""
             
@@ -821,9 +840,8 @@
             raise SIReaderException("Station must be in 'Read SI cards' operating mode! Change operating mode first.")
 
         if self.cardtype == 'SI5':
-            return SIReader._decode_carddata(self._send_command(SIReader.C_GET_SI5,
-                                                                '')[1],
-                                             self.cardtype)
+            raw_data = self._send_command(SIReader.C_GET_SI5,
+                                          b'')[1]
         elif self.cardtype == 'SI6':
             raw_data  = self._send_command(SIReader.C_GET_SI6,
                                            SIReader.P_SI6_CB)[1][1:]
@@ -831,10 +849,10 @@
             raw_data += self._read_command()[1][1:]
             return SIReader._decode_carddata(raw_data, self.cardtype)
         elif self.cardtype in ('SI8', 'SI9'):
-            raw_data = ''
+            raw_data = b''
             for b in range(SIReader.CARD[self.cardtype]['BC']):
                 raw_data += self._send_command(SIReader.C_GET_SI9,
-                                               chr(b))[1][1:]
+                                               int2byte(b))[1][1:]
 
             return SIReader._decode_carddata(raw_data, self.cardtype)
         elif self.cardtype == 'SI10':
@@ -847,9 +865,10 @@
             raw_data += self._read_command()[1][1:]
             raw_data += self._read_command()[1][1:]
             raw_data += self._read_command()[1][1:]
-            return SIReader._decode_carddata(raw_data, self.cardtype)
         else:
             raise SIReaderException('No card in the device.')
+
+        return SIReader._decode_carddata(raw_data, self.cardtype, reftime)
     
     def ack_sicard(self):
         """Sends an ACK signal to the SI Station. After receiving an ACK signal
@@ -909,7 +928,7 @@
             raise SIReaderException('This command only supports stations in "Extended Protocol" '
                                     'mode. Switch mode first')
 
-        if not self.proto_config['autosend']:
+        if not self.proto_config['auto_send']:
             raise SIReaderException('This command only supports stations in "Autosend" '
                                     'mode. Switch mode first')
 
@@ -932,7 +951,7 @@
             punches.append( (self._decode_cardnr(c[1][SIReader.T_CN:SIReader.T_CN+4]), 
                              self._decode_time(c[1][SIReader.T_TIME:SIReader.T_TIME+2])) )
         else:
-            raise SIReaderException('Unexpected command %s received' % hex(ord(c[0])))
+            raise SIReaderException('Unexpected command %s received' % hex(byte2int(c[0])))
         
         return punches
         
@@ -941,8 +960,9 @@
         @param offset: Position in the backup memory to read
         @warning:      Only supports firmwares 5.55+ older firmwares have an incompatible record format!
         """
-        c = self._send_command(SIReader.C_GET_BACKUP, SIReader._to_str(offset, 3)+chr(SIReader.REC_LEN))
-        return (self._decode_cardnr('\x00'+c[1][SIReader.BC_CN:SIReader.BC_CN+3]), 
+        c = self._send_command(SIReader.C_GET_BACKUP,
+                               SIReader._to_str(offset, 3)+int2byte(SIReader.REC_LEN))
+        return (self._decode_cardnr(b'\x00'+c[1][SIReader.BC_CN:SIReader.BC_CN+3]),
                 self._decode_time(c[1][SIReader.BC_TIME:SIReader.BC_TIME+2]))
 
 class SIReaderException(Exception):

Reply via email to