-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathsend.py
More file actions
240 lines (203 loc) · 6.71 KB
/
Copy pathsend.py
File metadata and controls
240 lines (203 loc) · 6.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
## Title: send.py
## Author: Jeroen Venema
## Created: 25/10/2022
## Last update: 29/01/2024
##
## Edited by Steve Lovejoy for linux DTR issue.
##
## syntax
## send.py FILENAME <PORT> <BAUDRATE>
##
## Modinfo:
## 25/10/2022 initial version
## 10/09/2023 Script converts binary file to Intel Hex during transmission.
## Using defaults as constants.
## 11/09/2023 Wait time variable introduced for handling PC serial drivers with low buffer memory
## 29/01/2024 OS-specific serial settings to prevent board reset upon opening of serial port
from pprint import pprint
DEFAULT_START_ADDRESS = 0x40000
DEFAULT_SERIAL_PORT = '/dev/ttyUSB1'
DEFAULT_BAUDRATE = 115200
DEFAULT_LINE_WAITTIME = 0.000 ## A value of +/- 0.003 Helps PC serial drivers with low buffer memory
IHEXBYTELENGTH = 255
WAITCRC = False # request extended format, if available from the VDP
def errorexit(message):
print(message)
print('Press ENTER to continue')
input()
exit()
return
def hexchecksum(hexstring):
result = hexstring[1:]
checksum = 0
msn = True
for digit in result:
if msn:
bytestring = digit
msn = False
else:
bytestring += digit
checksum += int(bytestring, 16)
msn = True
checksum = checksum & 0xff
checksum = (~checksum & 0xff) + 1
return checksum
def create_startrecord(crc32):
startrecord = ':060000FF0000' + hex(crc32)[2:].zfill(8).upper()
startrecord += hex(hexchecksum(startrecord))[2:].zfill(2).upper()
return startrecord
def create_stoprecord():
stoprecord = ':020000FF0001'
stoprecord += hex(hexchecksum(stoprecord))[2:].zfill(2).upper()
return stoprecord
import sys
import time
import os
import os.path
import tempfile
if(os.name == 'posix'): # termios only exists on Linux
DEFAULT_SERIAL_PORT = '/dev/ttyUSB0'
try:
import termios
except ModuleNotFoundError:
errorexit('Please install the \'termios\' module with pip')
try:
import serial
import serial.tools.list_ports
except ModuleNotFoundError:
errorexit('Please install the \'pyserial\' module with pip')
try:
from intelhex import IntelHex
except ModuleNotFoundError:
errorexit('Please install the \'intelhex\' module with pip')
try:
import crcmod
except ModuleNotFoundError:
errorexit('Please install the \'crcmod\' module with pip')
crc16 = crcmod.mkCrcFun(0x18005, 0x0, False, 0x0)
crc32 = crcmod.crcmod.predefined.Crc('crc-32')
if len(sys.argv) == 1 or len(sys.argv) >4:
sys.exit('Usage: send.py FILENAME <PORT> <BAUDRATE>')
if not os.path.isfile(sys.argv[1]):
sys.exit(f'Error: file \'{sys.argv[1]}\' not found')
if len(sys.argv) == 2:
serialports = serial.tools.list_ports.comports()
if len(serialports) > 1:
sys.exit("Multiple serial ports present - cannot automatically select");
serialport = str(serialports[0]).split(" ")[0]
if len(sys.argv) >= 3:
serialport = sys.argv[2]
if len(sys.argv) == 4:
baudrate = int(sys.argv[3])
else:
baudrate = DEFAULT_BAUDRATE
nativehexfile = ((sys.argv[1])[-3:] == 'hex') or ((sys.argv[1])[-4:] == 'ihex')
# report parameters used
print(f'Sending \'{sys.argv[1]}\' ', end="")
if nativehexfile: print('as native hex file')
else:
print('as binary data, in Intel Hex format')
print(f'Using start address 0x{DEFAULT_START_ADDRESS:x}')
print(f'Using serial port {serialport}')
print(f'Using Baudrate {baudrate}')
if nativehexfile:
# calculate crc32 of actual hex content data
ihex = IntelHex()
ihex.loadhex(sys.argv[1])
for start,end in ihex.segments():
while start != end:
byte = ihex[start].to_bytes(1,"little")
crc32.update(byte)
start += 1
# open native hex file for sending
file = open(sys.argv[1], "r")
content = file.readlines()
else:
# Instantiate ihex object and load binary file to it, write out as ihex format to temp file
ihex = IntelHex()
file = tempfile.TemporaryFile("w+t")
ihex.loadbin(sys.argv[1], offset=DEFAULT_START_ADDRESS)
ihex.write_hex_file(file, byte_count = IHEXBYTELENGTH)
file.seek(0)
# Calculate crc from binary file
with open(sys.argv[1], "rb") as f:
byte = f.read(1)
while byte:
crc32.update(byte)
byte = f.read(1)
resetPort = False
if(os.name == 'posix'):
if resetPort == False:
# to be able to suppress DTR, we need this
f = open(serialport)
attrs = termios.tcgetattr(f)
attrs[2] = attrs[2] & ~termios.HUPCL
termios.tcsetattr(f, termios.TCSAFLUSH, attrs)
f.close()
else:
f = open(serialport)
attrs = termios.tcgetattr(f)
attrs[2] = attrs[2] | termios.HUPCL
termios.tcsetattr(f, termios.TCSAFLUSH, attrs)
f.close()
ser = serial.Serial()
ser.baudrate = baudrate
ser.port = serialport
ser.timeout = 2
# OS-specific serial dtr/rts settings
if(os.name == 'nt'):
ser.setDTR(False)
ser.setRTS(False)
if(os.name == 'posix'):
ser.rtscts = False # not setting to false prevents communication
ser.dsrdtr = resetPort # determines if Agon resets or not
try:
ser.open()
print('Opening serial port...')
if not nativehexfile:
content = file
if WAITCRC:
startrecord = create_startrecord(crc32.crcValue)
ser.write(startrecord.encode())
sent = crc16(startrecord.strip().encode('ascii'))
ser.write(hex(sent)[2:].zfill(4).upper().encode())
time.sleep(0.5)
if ser.in_waiting:
ret = int.from_bytes(ser.read(2), "little")
sent = crc16(startrecord.strip().encode('ascii'))
pprint(ret)
pprint(sent)
if ret != sent:
errorexit("Extended header sending error, aborting")
else:
WAITCRC = False # Target VDP has no extended code built in
print('VDP doesn\'t support extended CRC16/32; sending regular format')
print('Sending data...')
for line in content:
linesent_ok = False
while not linesent_ok:
ser.write(str(line).strip().encode('ascii'))
linesent_ok = True
if WAITCRC:
sent = crc16(line.strip().encode('ascii'))
ser.write(hex(sent)[2:].zfill(4).upper().encode())
while ser.in_waiting < 2:
pass
ret = int.from_bytes(ser.read(2), "little")
if ret != sent:
print("CRC error, retransmitting")
linesent_ok = False
time.sleep(DEFAULT_LINE_WAITTIME)
if WAITCRC:
while ser.in_waiting == 0:
pass
crc32result = int.from_bytes(ser.read(4), "little")
if crc32result == crc32.crcValue:
print('CRC - OK')
else:
print('CRC ERROR')
print('Done')
ser.close()
except serial.SerialException:
errorexit('Error: serial port unavailable')
file.close()