Tino de Bruijn avatar Tino de Bruijn committed acdbe82

Factored out bytes utility functions to util. Also fixed the way the firmwarestring is read. Thanks to nickraptis

Comments (0)

Files changed (3)

pyfirmata/pyfirmata.py

 import serial
 import inspect
 import time
-from boards import BOARDS
+from util import two_byte_iter_to_str
 
 # Message command bytes - straight from Firmata.h
 DIGITAL_MESSAGE = 0x90      # send data for a digital pin
         
     def send_as_two_bytes(self, val):
         self.sp.write(chr(val % 128) + chr(val >> 7))
-        
-    def received_as_two_bytes(self, bytes):
-        lsb, msb = bytes
-        return msb << 7 | lsb
-        
+
     def setup_layout(self, board_layout):
         """
         Setup the Pin instances based on the given board-layout. Maybe it will
         major = data[0]
         minor = data[1]
         self.firmata_version = (major, minor)
-        self.firmware = ''.join([chr(x) for x in data[2:]]) # TODO this is more complicated, values is send as 7 bit bytes
+        self.firmware = two_byte_iter_to_str(data[2:])
 
 class Port(object):
     """ An 8-bit port on the board """

pyfirmata/util.py

                     pass
                 raise
                 
-def to_7_bits(integer):
+def to_two_bytes(integer):
     """
     Breaks an integer into two 7 bit bytes.
     
     >>> for i in range(32768):
-    ...     val = to_7_bits(i)
+    ...     val = to_two_bytes(i)
     ...     assert len(val) == 2
     ...
-    >>> to_7_bits(32767)
+    >>> to_two_bytes(32767)
     ('\\x7f', '\\xff')
-    >>> to_7_bits(32768)
+    >>> to_two_bytes(32768)
     Traceback (most recent call last):
         ...
     ValueError: Can't handle values bigger than 32767 (max for 2 bits)
     if integer > 32767:
         raise ValueError, "Can't handle values bigger than 32767 (max for 2 bits)"
     return chr(integer % 128), chr(integer >> 7)
+    
+def from_two_bytes(bytes):
+    """
+    Return an integer from two 7 bit bytes.
+    
+    >>> for i in range(32766, 32768):
+    ...     val = to_two_bytes(i)
+    ...     ret = from_two_bytes(val)
+    ...     assert ret == i
+    ...
+    >>> from_two_bytes(('\\xff', '\\xff'))
+    32767
+    >>> from_two_bytes(('\\x7f', '\\xff'))
+    32767
+    """
+    lsb, msb = bytes
+    try:
+        # Usually bytes have been converted to integers with ord already
+        return msb << 7 | lsb
+    except TypeError:
+        # But add this for easy testing
+        # One of them can be a string, or both
+        try:
+            lsb = ord(lsb)
+        except TypeError:
+            pass
+        try:
+            msb = ord(msb)
+        except TypeError:
+            pass
+        return msb << 7 | lsb
+    
+def two_byte_iter_to_str(bytes):
+    """
+    Return a string made from a list of two byte chars.
+    
+    >>> string, s = 'StandardFirmata', []
+    >>> for i in string:
+    ...   s.append(i)
+    ...   s.append('\\x00')
+    >>> two_byte_iter_to_str(s)
+    'StandardFirmata'
+    
+    >>> string, s = 'StandardFirmata', []
+    >>> for i in string:
+    ...   s.append(ord(i))
+    ...   s.append(ord('\\x00'))
+    >>> two_byte_iter_to_str(s)
+    'StandardFirmata'
+    """
+    bytes = list(bytes)
+    chars = []
+    while bytes:
+        lsb = bytes.pop(0)
+        try:
+            msb = bytes.pop(0)
+        except IndexError:
+            msb = 0x00
+        chars.append(chr(from_two_bytes((lsb, msb))))
+    return ''.join(chars)
+    
+def str_to_two_byte_iter(string):
+    """
+    Return a iter consisting of two byte chars from a string.
+    
+    >>> string, iter = 'StandardFirmata', []
+    >>> for i in string:
+    ...   iter.append(i)
+    ...   iter.append('\\x00')
+    >>> assert iter == str_to_two_byte_iter(string)
+     """
+    bytes = []
+    for char in string:
+        bytes += list(to_two_bytes(ord(char)))
+    return bytes
 
 def break_to_bytes(value):
     """
 import unittest
 import serial
-import time
 import pyfirmata
 from pyfirmata import mockup
 from pyfirmata.boards import BOARDS
-from pyfirmata.util import to_7_bits
+from pyfirmata.util import str_to_two_byte_iter
 
 # Messages todo left:
 
         
     def test_handle_report_firmware(self):
         self.assertEqual(self.board.firmware, None)
-        data = [2, 1] + [ord(x) for x in 'Firmware_name']
+        data = [2, 1] + str_to_two_byte_iter('Firmware_name')
         self.board._handle_report_firmware(*data)
         self.assertEqual(self.board.firmware, 'Firmware_name')
         self.assertEqual(self.board.firmata_version, (2, 1))
         msg = [chr(pyfirmata.START_SYSEX), 
                chr(pyfirmata.REPORT_FIRMWARE), 
                chr(2), 
-               chr(1)] + [i for i in 'Firmware_name'] + \
+               chr(1)] + str_to_two_byte_iter('Firmware_name') + \
               [chr(pyfirmata.END_SYSEX)]
         self.board.sp.write(msg)
         self.board.iterate()
         self.assert_serial(*sysex)
         
     def test_receive_sysex_message(self):
-        sysex = (chr(0xF0), chr(0x79), chr(2), chr(1), 'a', 'b', 'c', chr(0xF7))
+        sysex = (chr(0xF0), chr(0x79), chr(2), chr(1), 'a', '\x00', 'b', 
+            '\x00', 'c', '\x00', chr(0xF7))
         self.board.sp.write(sysex)
         while len(self.board.sp):
             self.board.iterate()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.