Browse Source

More Pythonic API for A and B, implement W

The LPC class now has properties for getting and setting echo, baudrate,
and stopbits.  Low-level access is now private to avoid letting users
break the public properties.

Also, a new write_ram method implements the W command.  If no number of
bytes is specified, the length of the data is used.
Clara Hobbs 6 years ago
parent
commit
3d93cf8b8c
1 changed files with 89 additions and 37 deletions
  1. 89
    37
      alpaca_isp/__init__.py

+ 89
- 37
alpaca_isp/__init__.py View File

@@ -22,19 +22,19 @@ class LPC:
22 22
     """Interface for LPC in-system programming"""
23 23
 
24 24
     def __init__(self, serport, baudrate=115200, clock=12000, timeout=0.1):
25
-        self.serport = serport
26
-        self.baudrate = baudrate
27
-        self.clock = clock
28
-        self.timeout = timeout
25
+        self._serport = serport
26
+        self._baudrate = baudrate
27
+        self._clock = clock
28
+        self._timeout = timeout
29 29
         self._echo = True
30 30
 
31 31
     def open(self):
32 32
         """Open the serial port to communicate with the microcontroller"""
33
-        self._uart = serial.Serial(self.serport, baudrate=self.baudrate,
34
-                timeout=self.timeout)
33
+        self._uart = serial.Serial(self._serport, baudrate=self._baudrate,
34
+                timeout=self._timeout)
35 35
 
36
-    def readline(self):
37
-        """Read a line terminated with '\r\n'"""
36
+    def _readline(self):
37
+        """Read a line terminated with b'\r\n'"""
38 38
         s = b""
39 39
         while True:
40 40
             c = self._uart.read(1)
@@ -45,35 +45,43 @@ class LPC:
45 45
             if s.endswith(b"\r\n"):
46 46
                 return s
47 47
 
48
-    def writeline(self, line):
49
-        """Write a line to the microcontroller and read the echoed response"""
48
+    def _writeline(self, line, plain=False):
49
+        """Write a line to the microcontroller and read the echoed response
50
+
51
+        If plain is True, the command is taken to be raw binary data.
52
+        """
50 53
         self._uart.write(line)
51 54
         self._uart.flush()
52 55
 
53
-        if not self._echo:
56
+        # If echo is disabled, don't try to read back what we sent
57
+        if not self.echo:
54 58
             return
59
+
55 60
         # Read the response, raising the exception if there is one
56
-        response = self.readline()
61
+        if plain:
62
+            response = self._uart.read(len(line))
63
+        else:
64
+            response = self._readline()
57 65
         # If we got the wrong response, raise an exception
58 66
         if response != line:
59 67
             raise ISPError("Wrong text echoed: {}".format(response))
60 68
 
61
-    def send_command_raw(self, cmd):
69
+    def _send_command_raw(self, cmd):
62 70
         """Send a command to the microcontroller, returning bytes"""
63
-        self.writeline(cmd)
64
-        return self.readline()
71
+        self._writeline(cmd)
72
+        return self._readline()
65 73
 
66
-    def send_command(self, cmd):
74
+    def _send_command(self, cmd):
67 75
         """Send a command to the microcontroller, returning the result"""
68
-        rr = self.send_command_raw(cmd)
76
+        rr = self._send_command_raw(cmd)
69 77
         lr = [int(n) for n in rr.split()]
70 78
         lr[0] = ReturnCode(lr[0])
71 79
         return lr
72 80
 
73
-    def start_isp(self, delay=0.01):
81
+    def enter_isp(self, delay=0.01):
74 82
         """Enter ISP mode by controlling the DTR (/RST) and RTS (/ISP) lines
75 83
 
76
-        This operation is performed synchronously.
84
+        This operation is performed synchronously, with delays.
77 85
         """
78 86
         self._uart.rts = True
79 87
         time.sleep(delay)
@@ -83,8 +91,8 @@ class LPC:
83 91
         time.sleep(delay)
84 92
         self._uart.rts = False
85 93
 
86
-    def start_comms(self, verbose=False):
87
-        """Start communication with the microcontroller"""
94
+    def synchronize(self, verbose=False):
95
+        """Begin communication with the microcontroller"""
88 96
         # Synchronize with the MCU
89 97
         while True:
90 98
             # Send a ?
@@ -94,20 +102,21 @@ class LPC:
94 102
                 print("?")
95 103
             # Receive a response
96 104
             try:
97
-                s = self.readline()
105
+                s = self._readline()
98 106
             except RecvTimeout:
99 107
                 continue
100 108
             # If we got the right response, break
101 109
             if s == b"Synchronized\r\n":
102 110
                 break
103 111
         # Tell the MCU we've synchronized
104
-        s = self.send_command_raw(b"Synchronized\r\n")
112
+        s = self._send_command_raw(b"Synchronized\r\n")
105 113
         # Next, it should say OK, at which point we're done synchronizing
106 114
         if s != b"OK\r\n":
107 115
             raise ISPError("Wrong response during synchronization")
108 116
 
109 117
         # Send clock frequency in kHz
110
-        s = self.send_command_raw("{:d}\r\n".format(self.clock).encode("utf-8"))
118
+        s = self._send_command_raw("{:d}\r\n".format(self._clock).encode(
119
+            "utf-8"))
111 120
         # Next, it should say OK
112 121
         if s != b"OK\r\n":
113 122
             raise ISPError("Wrong response during synchronization")
@@ -118,22 +127,65 @@ class LPC:
118 127
 
119 128
     def unlock(self, code="23130"):
120 129
         """Unlock the flash write, erase, and go commands"""
121
-        return self.send_command("U {}\r\n".format(code).encode("utf-8"))
130
+        return self._send_command("U {}\r\n".format(code).encode("utf-8"))
131
+
132
+    @property
133
+    def baudrate(self):
134
+        """The baud rate used for communication"""
135
+        return self._uart.baudrate
136
+
137
+    @baudrate.setter
138
+    def baudrate(self, br):
139
+        r = self._send_command("B {} {}\r\n".format(br,
140
+            self._uart.stopbits).encode("utf-8"))
141
+        # Update the baud rate for our UART
142
+        if r[0] != ReturnCode.CMD_SUCCESS:
143
+            raise ISPError(r)
144
+        self._uart.baudrate = br
145
+
146
+    @property
147
+    def stopbits(self):
148
+        """The number of stop bits used for communication"""
149
+        return self._uart.stopbits
150
+
151
+    @stopbits.setter
152
+    def stopbits(self, sb):
153
+        r = self._send_command("B {} {}\r\n".format(self._uart.baudrate,
154
+            sb).encode("utf-8"))
155
+        # Update the number of stop bits for our UART
156
+        if r[0] != ReturnCode.CMD_SUCCESS:
157
+            raise ISPError(r)
158
+        self._uart.stopbits = sb
159
+
160
+    @property
161
+    def echo(self):
162
+        """Whether the microcontroller echoes characters back to the host"""
163
+        return self._echo
164
+
165
+    @echo.setter
166
+    def echo(self, setting):
167
+        setting = bool(setting)
168
+        r = self._send_command("A {}\r\n".format(int(setting)).encode("utf-8"))
169
+        if r[0] != ReturnCode.CMD_SUCCESS:
170
+            raise ISPError(r)
171
+        self._echo = setting
122 172
 
123
-    def setbaudrate(self, baudrate, stopbits):
124
-        """Update the baud rate and number of stop bits"""
125
-        r = self.send_command("B {} {}\r\n".format(baudrate, stopbits).encode(
173
+    def write_ram(self, start, data, count=None):
174
+        """Write count bytes from data to RAM at the given start address
175
+        
176
+        Start and count must be multiples of four.  If count is not specified,
177
+        len(data) is used.
178
+        """
179
+        # Get the length of the data we're writing
180
+        if count is None:
181
+            count = len(data)
182
+        # Ask to write data
183
+        r = self._send_command("W {} {}\r\n".format(start, count).encode(
126 184
             "utf-8"))
127
-        # Update the baud rate and number of stop bits for our UART connection
185
+        # If the MCU is okay with what we intend to do, send the data
128 186
         if r[0] == ReturnCode.CMD_SUCCESS:
129
-            self._uart.baudrate = baudrate
130
-            self._uart.stopbits = stopbits
131
-        return r
132
-
133
-    def echo(self, setting):
134
-        """Set whether echo is enabled or disabled"""
135
-        r = self.send_command("A {}\r\n".format(int(setting)).encode("utf-8"))
136
-        self._echo = setting
187
+            # NOTE: this is right for LPC8xx chips, not others
188
+            ok = self._writeline(data[:count], plain=True)
137 189
         return r
138 190
 
139 191
 

Loading…
Cancel
Save