1414# Set your COM port e.g. COM3 for Windows, /dev/ttyACM0 for Linux...
1515COM_PORT = "/dev/ttyACM0"
1616# COM_PORT = "COM5"
17+ # MacOS COM port:
18+ COM_PORT = '/dev/cu.usbmodem2017_2_251'
19+
20+ # The new device has a serial number of '2017-2-25'
1721
1822DISPLAY_WIDTH = 320
1923DISPLAY_HEIGHT = 480
2024
2125
26+ class TuringError (Exception ):
27+ pass
28+
29+
2230class Command :
23- RESET = 101
24- CLEAR = 102
25- SCREEN_OFF = 108
26- SCREEN_ON = 109
27- SET_BRIGHTNESS = 110
28- DISPLAY_BITMAP = 197
31+ # Old protocol (6 byte packets, command in final byte)
32+ #RESET = 101
33+ #CLEAR = 102
34+ #SCREEN_OFF = 108
35+ #SCREEN_ON = 109
36+ #SET_BRIGHTNESS = 110
37+ #DISPLAY_BITMAP = 197
38+
39+ # New protocol (10 byte packets, framed with the command, 8 data bytes inside)
40+ HELLO = 0xCA
41+ ORIENTATION = 0xCB
42+ ORIENTATION_PORTRAIT = 0
43+ ORIENTATION_LANDSCAPE = 1
44+ # The device seems to start in PORTRAIT, with the row ordering reversed from
45+ # the ORIENTATION_PORTRAIT setting. It is not clear how to restore the ordering
46+ # to the reset configuration.
47+ DISPLAY_BITMAP = 0xCC
48+ LIGHTING = 0xCD
49+ SET_BRIGHTNESS = 0xCE
2950
3051
3152def SendReg (ser : serial .Serial , cmd : int , x : int , y : int , ex : int , ey : int ):
@@ -39,26 +60,83 @@ def SendReg(ser: serial.Serial, cmd: int, x: int, y: int, ex: int, ey: int):
3960 ser .write (bytes (byteBuffer ))
4061
4162
42- def Reset (ser : serial .Serial ):
43- SendReg (ser , Command .RESET , 0 , 0 , 0 , 0 )
63+ def SendCommand (ser : serial .Serial , cmd : int , payload = None ):
64+ if payload is None :
65+ payload = [0 ] * 8
66+ elif len (payload ) < 8 :
67+ payload = list (payload ) + [0 ] * (8 - len (payload ))
68+
69+ byteBuffer = bytearray (10 )
70+ byteBuffer [0 ] = cmd
71+ byteBuffer [1 ] = payload [0 ]
72+ byteBuffer [2 ] = payload [1 ]
73+ byteBuffer [3 ] = payload [2 ]
74+ byteBuffer [4 ] = payload [3 ]
75+ byteBuffer [5 ] = payload [4 ]
76+ byteBuffer [6 ] = payload [5 ]
77+ byteBuffer [7 ] = payload [6 ]
78+ byteBuffer [8 ] = payload [7 ]
79+ byteBuffer [9 ] = cmd
80+ print ("Sending %r" % (byteBuffer ,))
81+ ser .write (bytes (byteBuffer ))
82+
83+
84+ def Hello (ser : serial .Serial ):
85+ hello = [ord ('H' ), ord ('E' ), ord ('L' ), ord ('L' ), ord ('O' )]
86+ SendCommand (ser , Command .HELLO , payload = hello )
87+ response = ser .read (10 )
88+ if len (response ) != 10 :
89+ raise TuringError ("Device not recognised (short response to HELLO)" )
90+ if response [0 ] != Command .HELLO or response [- 1 ] != Command .HELLO :
91+ raise TuringError ("Device not recognised (bad framing)" )
92+ if [x for x in response [1 :6 ]] != hello :
93+ raise TuringError ("Device not recognised (No HELLO; got %r)" % (response [1 :6 ],))
94+ # The HELLO response here is followed by:
95+ # 0x0A, 0x12, 0x00
96+ # It is not clear what these might be.
97+ # It would be handy if these were a version number, or a set of capability
98+ # flags. The 0x0A=10 being version 10 or 0.10, and the 0x12 being the size or the
99+ # indication that a backlight is present, would be nice. But that's guessing
100+ # based on how I'd do it.
44101
45102
46103def Clear (ser : serial .Serial ):
47- SendReg (ser , Command .CLEAR , 0 , 0 , 0 , 0 )
104+ # Unknown what command this is
105+ print ("Clear unknown" )
106+ # Cannot find a 'clear' command
107+ #SendReg(ser, Command.CLEAR, 0, 0, 0, 0)
108+
109+
110+ def Orientation (ser : serial .Serial , state : int ):
111+ print ("Orientation: %r" % (state ,))
112+ SendCommand (ser , Command .ORIENTATION , payload = [state ])
113+
114+
115+ def SetLighting (ser : serial .Serial , red : int , green : int , blue : int ):
116+ print ("Lighting: %i, %i, %i" % (red , green , blue ))
117+ assert red < 256 , 'Red lighting must be < 256'
118+ assert green < 256 , 'Green lighting must be < 256'
119+ assert blue < 256 , 'Blue lighting must be < 256'
120+ SendCommand (ser , Command .LIGHTING , payload = [red , green , blue ])
48121
49122
50123def ScreenOff (ser : serial .Serial ):
51- SendReg (ser , Command .SCREEN_OFF , 0 , 0 , 0 , 0 )
124+ print ("Screen off unknown" )
125+ # Cannot find a 'screen off' command
126+ #SendReg(ser, Command.SCREEN_OFF, 0, 0, 0, 0)
52127
53128
54129def ScreenOn (ser : serial .Serial ):
55- SendReg (ser , Command .SCREEN_ON , 0 , 0 , 0 , 0 )
130+ print ("Screen on unknown" )
131+ # Cannot find a 'screen on' command
132+ #SendReg(ser, Command.SCREEN_ON, 0, 0, 0, 0)
56133
57134
58135def SetBrightness (ser : serial .Serial , level : int ):
59136 # Level : 0 (brightest) - 255 (darkest)
60137 assert 255 >= level >= 0 , 'Brightness level must be [0-255]'
61- SendReg (ser , Command .SET_BRIGHTNESS , level , 0 , 0 , 0 )
138+ # New protocol has 255 as the brightest, and 0 as off.
139+ SendCommand (ser , Command .SET_BRIGHTNESS , payload = [255 - level ])
62140
63141
64142def DisplayPILImage (ser : serial .Serial , image : Image , x : int , y : int ):
@@ -68,7 +146,14 @@ def DisplayPILImage(ser: serial.Serial, image: Image, x: int, y: int):
68146 assert image_height > 0 , 'Image width must be > 0'
69147 assert image_width > 0 , 'Image height must be > 0'
70148
71- SendReg (ser , Command .DISPLAY_BITMAP , x , y , x + image_width - 1 , y + image_height - 1 )
149+ (x0 , y0 ) = (x , y )
150+ (x1 , y1 ) = (x + image_width - 1 , y + image_height - 1 )
151+
152+ SendCommand (ser , Command .DISPLAY_BITMAP ,
153+ payload = [(x0 >> 8 ) & 255 , x0 & 255 ,
154+ (y0 >> 8 ) & 255 , y0 & 255 ,
155+ (x1 >> 8 ) & 255 , x1 & 255 ,
156+ (y1 >> 8 ) & 255 , y1 & 255 ])
72157
73158 pix = image .load ()
74159 line = bytes ()
@@ -78,7 +163,15 @@ def DisplayPILImage(ser: serial.Serial, image: Image, x: int, y: int):
78163 G = pix [w , h ][1 ] >> 2
79164 B = pix [w , h ][2 ] >> 3
80165
81- rgb = (R << 11 ) | (G << 5 ) | B
166+ # Original: 0bRRRRRGGGGGGBBBBB
167+ # fedcba9876543210
168+ # New: 0bgggBBBBBRRRRRGGG
169+ # That is...
170+ # High 3 bits of green in b0-b2
171+ # Low 3 bits of green in b13-b15
172+ # Red 5 bits in b3-b7
173+ # Blue 5 bits in b8-b12
174+ rgb = (B << 8 ) | (G >> 3 ) | ((G & 7 )<< 13 ) | (R << 3 )
82175 line += struct .pack ('H' , rgb )
83176
84177 # Send image data by multiple of DISPLAY_WIDTH bytes
@@ -183,12 +276,18 @@ def sighandler(signum, frame):
183276 # Do not change COM port settings unless you know what you are doing
184277 lcd_comm = serial .Serial (COM_PORT , 115200 , timeout = 1 , rtscts = 1 )
185278
186- # Clear screen (blank)
187- Clear (lcd_comm )
279+ # Hello! to check this is the right device
280+ Hello (lcd_comm )
281+
282+ # Data orientation
283+ Orientation (lcd_comm , Command .ORIENTATION_PORTRAIT )
188284
189285 # Set brightness to max value
190286 SetBrightness (lcd_comm , 0 )
191287
288+ # Lighting (a purple)
289+ SetLighting (lcd_comm , 128 , 50 , 112 )
290+
192291 # Display sample picture
193292 DisplayBitmap (lcd_comm , "res/example.png" )
194293
0 commit comments