|
@@ -25,320 +25,320 @@ import MarlinBinaryProtocol
|
25
|
25
|
#-----------------#
|
26
|
26
|
def Upload(source, target, env):
|
27
|
27
|
|
28
|
|
- #-------#
|
29
|
|
- # Debug #
|
30
|
|
- #-------#
|
31
|
|
- Debug = False # Set to True to enable script debug
|
32
|
|
- def debugPrint(data):
|
33
|
|
- if Debug: print(f"[Debug]: {data}")
|
34
|
|
-
|
35
|
|
- #------------------#
|
36
|
|
- # Marlin functions #
|
37
|
|
- #------------------#
|
38
|
|
- def _GetMarlinEnv(marlinEnv, feature):
|
39
|
|
- if not marlinEnv: return None
|
40
|
|
- return marlinEnv[feature] if feature in marlinEnv else None
|
41
|
|
-
|
42
|
|
- #----------------#
|
43
|
|
- # Port functions #
|
44
|
|
- #----------------#
|
45
|
|
- def _GetUploadPort(env):
|
46
|
|
- debugPrint('Autodetecting upload port...')
|
47
|
|
- env.AutodetectUploadPort(env)
|
48
|
|
- portName = env.subst('$UPLOAD_PORT')
|
49
|
|
- if not portName:
|
50
|
|
- raise Exception('Error detecting the upload port.')
|
51
|
|
- debugPrint('OK')
|
52
|
|
- return portName
|
53
|
|
-
|
54
|
|
- #-------------------------#
|
55
|
|
- # Simple serial functions #
|
56
|
|
- #-------------------------#
|
57
|
|
- def _OpenPort():
|
58
|
|
- # Open serial port
|
59
|
|
- if port.is_open: return
|
60
|
|
- debugPrint('Opening upload port...')
|
61
|
|
- port.open()
|
62
|
|
- port.reset_input_buffer()
|
63
|
|
- debugPrint('OK')
|
64
|
|
-
|
65
|
|
- def _ClosePort():
|
66
|
|
- # Open serial port
|
67
|
|
- if port is None: return
|
68
|
|
- if not port.is_open: return
|
69
|
|
- debugPrint('Closing upload port...')
|
70
|
|
- port.close()
|
71
|
|
- debugPrint('OK')
|
72
|
|
-
|
73
|
|
- def _Send(data):
|
74
|
|
- debugPrint(f'>> {data}')
|
75
|
|
- strdata = bytearray(data, 'utf8') + b'\n'
|
76
|
|
- port.write(strdata)
|
77
|
|
- time.sleep(0.010)
|
78
|
|
-
|
79
|
|
- def _Recv():
|
80
|
|
- clean_responses = []
|
81
|
|
- responses = port.readlines()
|
82
|
|
- for Resp in responses:
|
83
|
|
- # Suppress invalid chars (coming from debug info)
|
84
|
|
- try:
|
85
|
|
- clean_response = Resp.decode('utf8').rstrip().lstrip()
|
86
|
|
- clean_responses.append(clean_response)
|
87
|
|
- debugPrint(f'<< {clean_response}')
|
88
|
|
- except:
|
89
|
|
- pass
|
90
|
|
- return clean_responses
|
91
|
|
-
|
92
|
|
- #------------------#
|
93
|
|
- # SDCard functions #
|
94
|
|
- #------------------#
|
95
|
|
- def _CheckSDCard():
|
96
|
|
- debugPrint('Checking SD card...')
|
97
|
|
- _Send('M21')
|
98
|
|
- Responses = _Recv()
|
99
|
|
- if len(Responses) < 1 or not any('SD card ok' in r for r in Responses):
|
100
|
|
- raise Exception('Error accessing SD card')
|
101
|
|
- debugPrint('SD Card OK')
|
102
|
|
- return True
|
103
|
|
-
|
104
|
|
- #----------------#
|
105
|
|
- # File functions #
|
106
|
|
- #----------------#
|
107
|
|
- def _GetFirmwareFiles(UseLongFilenames):
|
108
|
|
- debugPrint('Get firmware files...')
|
109
|
|
- _Send(f"M20 F{'L' if UseLongFilenames else ''}")
|
110
|
|
- Responses = _Recv()
|
111
|
|
- if len(Responses) < 3 or not any('file list' in r for r in Responses):
|
112
|
|
- raise Exception('Error getting firmware files')
|
113
|
|
- debugPrint('OK')
|
114
|
|
- return Responses
|
115
|
|
-
|
116
|
|
- def _FilterFirmwareFiles(FirmwareList, UseLongFilenames):
|
117
|
|
- Firmwares = []
|
118
|
|
- for FWFile in FirmwareList:
|
119
|
|
- # For long filenames take the 3rd column of the firmwares list
|
120
|
|
- if UseLongFilenames:
|
121
|
|
- Space = 0
|
122
|
|
- Space = FWFile.find(' ')
|
123
|
|
- if Space >= 0: Space = FWFile.find(' ', Space + 1)
|
124
|
|
- if Space >= 0: FWFile = FWFile[Space + 1:]
|
125
|
|
- if not '/' in FWFile and '.BIN' in FWFile.upper():
|
126
|
|
- Firmwares.append(FWFile[:FWFile.upper().index('.BIN') + 4])
|
127
|
|
- return Firmwares
|
128
|
|
-
|
129
|
|
- def _RemoveFirmwareFile(FirmwareFile):
|
130
|
|
- _Send(f'M30 /{FirmwareFile}')
|
131
|
|
- Responses = _Recv()
|
132
|
|
- Removed = len(Responses) >= 1 and any('File deleted' in r for r in Responses)
|
133
|
|
- if not Removed:
|
134
|
|
- raise Exception(f"Firmware file '{FirmwareFile}' not removed")
|
135
|
|
- return Removed
|
136
|
|
-
|
137
|
|
- def _RollbackUpload(FirmwareFile):
|
138
|
|
- if not rollback: return
|
139
|
|
- print(f"Rollback: trying to delete firmware '{FirmwareFile}'...")
|
140
|
|
- _OpenPort()
|
141
|
|
- # Wait for SD card release
|
142
|
|
- time.sleep(1)
|
143
|
|
- # Remount SD card
|
144
|
|
- _CheckSDCard()
|
145
|
|
- print(' OK' if _RemoveFirmwareFile(FirmwareFile) else ' Error!')
|
146
|
|
- _ClosePort()
|
147
|
|
-
|
148
|
|
-
|
149
|
|
- #---------------------#
|
150
|
|
- # Callback Entrypoint #
|
151
|
|
- #---------------------#
|
152
|
|
- port = None
|
153
|
|
- protocol = None
|
154
|
|
- filetransfer = None
|
155
|
|
- rollback = False
|
156
|
|
-
|
157
|
|
- # Get Marlin evironment vars
|
158
|
|
- MarlinEnv = env['MARLIN_FEATURES']
|
159
|
|
- marlin_pioenv = _GetMarlinEnv(MarlinEnv, 'PIOENV')
|
160
|
|
- marlin_motherboard = _GetMarlinEnv(MarlinEnv, 'MOTHERBOARD')
|
161
|
|
- marlin_board_info_name = _GetMarlinEnv(MarlinEnv, 'BOARD_INFO_NAME')
|
162
|
|
- marlin_board_custom_build_flags = _GetMarlinEnv(MarlinEnv, 'BOARD_CUSTOM_BUILD_FLAGS')
|
163
|
|
- marlin_firmware_bin = _GetMarlinEnv(MarlinEnv, 'FIRMWARE_BIN')
|
164
|
|
- marlin_long_filename_host_support = _GetMarlinEnv(MarlinEnv, 'LONG_FILENAME_HOST_SUPPORT') is not None
|
165
|
|
- marlin_longname_write = _GetMarlinEnv(MarlinEnv, 'LONG_FILENAME_WRITE_SUPPORT') is not None
|
166
|
|
- marlin_custom_firmware_upload = _GetMarlinEnv(MarlinEnv, 'CUSTOM_FIRMWARE_UPLOAD') is not None
|
167
|
|
- marlin_short_build_version = _GetMarlinEnv(MarlinEnv, 'SHORT_BUILD_VERSION')
|
168
|
|
- marlin_string_config_h_author = _GetMarlinEnv(MarlinEnv, 'STRING_CONFIG_H_AUTHOR')
|
169
|
|
-
|
170
|
|
- # Get firmware upload params
|
171
|
|
- upload_firmware_source_name = str(source[0]) # Source firmware filename
|
172
|
|
- upload_speed = env['UPLOAD_SPEED'] if 'UPLOAD_SPEED' in env else 115200
|
173
|
|
- # baud rate of serial connection
|
174
|
|
- upload_port = _GetUploadPort(env) # Serial port to use
|
175
|
|
-
|
176
|
|
- # Set local upload params
|
177
|
|
- upload_firmware_target_name = os.path.basename(upload_firmware_source_name)
|
178
|
|
- # Target firmware filename
|
179
|
|
- upload_timeout = 1000 # Communication timout, lossy/slow connections need higher values
|
180
|
|
- upload_blocksize = 512 # Transfer block size. 512 = Autodetect
|
181
|
|
- upload_compression = True # Enable compression
|
182
|
|
- upload_error_ratio = 0 # Simulated corruption ratio
|
183
|
|
- upload_test = False # Benchmark the serial link without storing the file
|
184
|
|
- upload_reset = True # Trigger a soft reset for firmware update after the upload
|
185
|
|
-
|
186
|
|
- # Set local upload params based on board type to change script behavior
|
187
|
|
- # "upload_delete_old_bins": delete all *.bin files in the root of SD Card
|
188
|
|
- upload_delete_old_bins = marlin_motherboard in ['BOARD_CREALITY_V4', 'BOARD_CREALITY_V4210', 'BOARD_CREALITY_V422', 'BOARD_CREALITY_V423',
|
189
|
|
- 'BOARD_CREALITY_V427', 'BOARD_CREALITY_V431', 'BOARD_CREALITY_V452', 'BOARD_CREALITY_V453',
|
190
|
|
- 'BOARD_CREALITY_V24S1']
|
191
|
|
- # "upload_random_name": generate a random 8.3 firmware filename to upload
|
192
|
|
- upload_random_filename = marlin_motherboard in ['BOARD_CREALITY_V4', 'BOARD_CREALITY_V4210', 'BOARD_CREALITY_V422', 'BOARD_CREALITY_V423',
|
193
|
|
- 'BOARD_CREALITY_V427', 'BOARD_CREALITY_V431', 'BOARD_CREALITY_V452', 'BOARD_CREALITY_V453',
|
194
|
|
- 'BOARD_CREALITY_V24S1'] and not marlin_long_filename_host_support
|
195
|
|
-
|
196
|
|
- try:
|
197
|
|
-
|
198
|
|
- # Start upload job
|
199
|
|
- print(f"Uploading firmware '{os.path.basename(upload_firmware_target_name)}' to '{marlin_motherboard}' via '{upload_port}'")
|
200
|
|
-
|
201
|
|
- # Dump some debug info
|
202
|
|
- if Debug:
|
203
|
|
- print('Upload using:')
|
204
|
|
- print('---- Marlin -----------------------------------')
|
205
|
|
- print(f' PIOENV : {marlin_pioenv}')
|
206
|
|
- print(f' SHORT_BUILD_VERSION : {marlin_short_build_version}')
|
207
|
|
- print(f' STRING_CONFIG_H_AUTHOR : {marlin_string_config_h_author}')
|
208
|
|
- print(f' MOTHERBOARD : {marlin_motherboard}')
|
209
|
|
- print(f' BOARD_INFO_NAME : {marlin_board_info_name}')
|
210
|
|
- print(f' CUSTOM_BUILD_FLAGS : {marlin_board_custom_build_flags}')
|
211
|
|
- print(f' FIRMWARE_BIN : {marlin_firmware_bin}')
|
212
|
|
- print(f' LONG_FILENAME_HOST_SUPPORT : {marlin_long_filename_host_support}')
|
213
|
|
- print(f' LONG_FILENAME_WRITE_SUPPORT : {marlin_longname_write}')
|
214
|
|
- print(f' CUSTOM_FIRMWARE_UPLOAD : {marlin_custom_firmware_upload}')
|
215
|
|
- print('---- Upload parameters ------------------------')
|
216
|
|
- print(f' Source : {upload_firmware_source_name}')
|
217
|
|
- print(f' Target : {upload_firmware_target_name}')
|
218
|
|
- print(f' Port : {upload_port} @ {upload_speed} baudrate')
|
219
|
|
- print(f' Timeout : {upload_timeout}')
|
220
|
|
- print(f' Block size : {upload_blocksize}')
|
221
|
|
- print(f' Compression : {upload_compression}')
|
222
|
|
- print(f' Error ratio : {upload_error_ratio}')
|
223
|
|
- print(f' Test : {upload_test}')
|
224
|
|
- print(f' Reset : {upload_reset}')
|
225
|
|
- print('-----------------------------------------------')
|
226
|
|
-
|
227
|
|
- # Custom implementations based on board parameters
|
228
|
|
- # Generate a new 8.3 random filename
|
229
|
|
- if upload_random_filename:
|
230
|
|
- upload_firmware_target_name = f"fw-{''.join(random.choices('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', k=5))}.BIN"
|
231
|
|
- print(f"Board {marlin_motherboard}: Overriding firmware filename to '{upload_firmware_target_name}'")
|
232
|
|
-
|
233
|
|
- # Delete all *.bin files on the root of SD Card (if flagged)
|
234
|
|
- if upload_delete_old_bins:
|
235
|
|
- # CUSTOM_FIRMWARE_UPLOAD is needed for this feature
|
236
|
|
- if not marlin_custom_firmware_upload:
|
237
|
|
- raise Exception(f"CUSTOM_FIRMWARE_UPLOAD must be enabled in 'Configuration_adv.h' for '{marlin_motherboard}'")
|
238
|
|
-
|
239
|
|
- # Init & Open serial port
|
240
|
|
- port = serial.Serial(upload_port, baudrate = upload_speed, write_timeout = 0, timeout = 0.1)
|
241
|
|
- _OpenPort()
|
242
|
|
-
|
243
|
|
- # Check SD card status
|
244
|
|
- _CheckSDCard()
|
245
|
|
-
|
246
|
|
- # Get firmware files
|
247
|
|
- FirmwareFiles = _GetFirmwareFiles(marlin_long_filename_host_support)
|
248
|
|
- if Debug:
|
249
|
|
- for FirmwareFile in FirmwareFiles:
|
250
|
|
- print(f'Found: {FirmwareFile}')
|
251
|
|
-
|
252
|
|
- # Get all 1st level firmware files (to remove)
|
253
|
|
- OldFirmwareFiles = _FilterFirmwareFiles(FirmwareFiles[1:len(FirmwareFiles)-2], marlin_long_filename_host_support) # Skip header and footers of list
|
254
|
|
- if len(OldFirmwareFiles) == 0:
|
255
|
|
- print('No old firmware files to delete')
|
256
|
|
- else:
|
257
|
|
- print(f"Remove {len(OldFirmwareFiles)} old firmware file{'s' if len(OldFirmwareFiles) != 1 else ''}:")
|
258
|
|
- for OldFirmwareFile in OldFirmwareFiles:
|
259
|
|
- print(f" -Removing- '{OldFirmwareFile}'...")
|
260
|
|
- print(' OK' if _RemoveFirmwareFile(OldFirmwareFile) else ' Error!')
|
261
|
|
-
|
262
|
|
- # Close serial
|
263
|
|
- _ClosePort()
|
264
|
|
-
|
265
|
|
- # Cleanup completed
|
266
|
|
- debugPrint('Cleanup completed')
|
267
|
|
-
|
268
|
|
- # WARNING! The serial port must be closed here because the serial transfer that follow needs it!
|
269
|
|
-
|
270
|
|
- # Upload firmware file
|
271
|
|
- debugPrint(f"Copy '{upload_firmware_source_name}' --> '{upload_firmware_target_name}'")
|
272
|
|
- protocol = MarlinBinaryProtocol.Protocol(upload_port, upload_speed, upload_blocksize, float(upload_error_ratio), int(upload_timeout))
|
273
|
|
- #echologger = MarlinBinaryProtocol.EchoProtocol(protocol)
|
274
|
|
- protocol.connect()
|
275
|
|
- # Mark the rollback (delete broken transfer) from this point on
|
276
|
|
- rollback = True
|
277
|
|
- filetransfer = MarlinBinaryProtocol.FileTransferProtocol(protocol)
|
278
|
|
- transferOK = filetransfer.copy(upload_firmware_source_name, upload_firmware_target_name, upload_compression, upload_test)
|
279
|
|
- protocol.disconnect()
|
280
|
|
-
|
281
|
|
- # Notify upload completed
|
282
|
|
- protocol.send_ascii('M117 Firmware uploaded' if transferOK else 'M117 Firmware upload failed')
|
283
|
|
-
|
284
|
|
- # Remount SD card
|
285
|
|
- print('Wait for SD card release...')
|
286
|
|
- time.sleep(1)
|
287
|
|
- print('Remount SD card')
|
288
|
|
- protocol.send_ascii('M21')
|
289
|
|
-
|
290
|
|
- # Transfer failed?
|
291
|
|
- if not transferOK:
|
292
|
|
- protocol.shutdown()
|
293
|
|
- _RollbackUpload(upload_firmware_target_name)
|
294
|
|
- else:
|
295
|
|
- # Trigger firmware update
|
296
|
|
- if upload_reset:
|
297
|
|
- print('Trigger firmware update...')
|
298
|
|
- protocol.send_ascii('M997', True)
|
299
|
|
- protocol.shutdown()
|
300
|
|
-
|
301
|
|
- print('Firmware update completed' if transferOK else 'Firmware update failed')
|
302
|
|
- return 0 if transferOK else -1
|
303
|
|
-
|
304
|
|
- except KeyboardInterrupt:
|
305
|
|
- print('Aborted by user')
|
306
|
|
- if filetransfer: filetransfer.abort()
|
307
|
|
- if protocol:
|
308
|
|
- protocol.disconnect()
|
309
|
|
- protocol.shutdown()
|
310
|
|
- _RollbackUpload(upload_firmware_target_name)
|
311
|
|
- _ClosePort()
|
312
|
|
- raise
|
313
|
|
-
|
314
|
|
- except serial.SerialException as se:
|
315
|
|
- # This exception is raised only for send_ascii data (not for binary transfer)
|
316
|
|
- print(f'Serial excepion: {se}, transfer aborted')
|
317
|
|
- if protocol:
|
318
|
|
- protocol.disconnect()
|
319
|
|
- protocol.shutdown()
|
320
|
|
- _RollbackUpload(upload_firmware_target_name)
|
321
|
|
- _ClosePort()
|
322
|
|
- raise Exception(se)
|
323
|
|
-
|
324
|
|
- except MarlinBinaryProtocol.FatalError:
|
325
|
|
- print('Too many retries, transfer aborted')
|
326
|
|
- if protocol:
|
327
|
|
- protocol.disconnect()
|
328
|
|
- protocol.shutdown()
|
329
|
|
- _RollbackUpload(upload_firmware_target_name)
|
330
|
|
- _ClosePort()
|
331
|
|
- raise
|
332
|
|
-
|
333
|
|
- except Exception as ex:
|
334
|
|
- print(f"\nException: {ex}, transfer aborted")
|
335
|
|
- if protocol:
|
336
|
|
- protocol.disconnect()
|
337
|
|
- protocol.shutdown()
|
338
|
|
- _RollbackUpload(upload_firmware_target_name)
|
339
|
|
- _ClosePort()
|
340
|
|
- print('Firmware not updated')
|
341
|
|
- raise
|
|
28
|
+ #-------#
|
|
29
|
+ # Debug #
|
|
30
|
+ #-------#
|
|
31
|
+ Debug = False # Set to True to enable script debug
|
|
32
|
+ def debugPrint(data):
|
|
33
|
+ if Debug: print(f"[Debug]: {data}")
|
|
34
|
+
|
|
35
|
+ #------------------#
|
|
36
|
+ # Marlin functions #
|
|
37
|
+ #------------------#
|
|
38
|
+ def _GetMarlinEnv(marlinEnv, feature):
|
|
39
|
+ if not marlinEnv: return None
|
|
40
|
+ return marlinEnv[feature] if feature in marlinEnv else None
|
|
41
|
+
|
|
42
|
+ #----------------#
|
|
43
|
+ # Port functions #
|
|
44
|
+ #----------------#
|
|
45
|
+ def _GetUploadPort(env):
|
|
46
|
+ debugPrint('Autodetecting upload port...')
|
|
47
|
+ env.AutodetectUploadPort(env)
|
|
48
|
+ portName = env.subst('$UPLOAD_PORT')
|
|
49
|
+ if not portName:
|
|
50
|
+ raise Exception('Error detecting the upload port.')
|
|
51
|
+ debugPrint('OK')
|
|
52
|
+ return portName
|
|
53
|
+
|
|
54
|
+ #-------------------------#
|
|
55
|
+ # Simple serial functions #
|
|
56
|
+ #-------------------------#
|
|
57
|
+ def _OpenPort():
|
|
58
|
+ # Open serial port
|
|
59
|
+ if port.is_open: return
|
|
60
|
+ debugPrint('Opening upload port...')
|
|
61
|
+ port.open()
|
|
62
|
+ port.reset_input_buffer()
|
|
63
|
+ debugPrint('OK')
|
|
64
|
+
|
|
65
|
+ def _ClosePort():
|
|
66
|
+ # Open serial port
|
|
67
|
+ if port is None: return
|
|
68
|
+ if not port.is_open: return
|
|
69
|
+ debugPrint('Closing upload port...')
|
|
70
|
+ port.close()
|
|
71
|
+ debugPrint('OK')
|
|
72
|
+
|
|
73
|
+ def _Send(data):
|
|
74
|
+ debugPrint(f'>> {data}')
|
|
75
|
+ strdata = bytearray(data, 'utf8') + b'\n'
|
|
76
|
+ port.write(strdata)
|
|
77
|
+ time.sleep(0.010)
|
|
78
|
+
|
|
79
|
+ def _Recv():
|
|
80
|
+ clean_responses = []
|
|
81
|
+ responses = port.readlines()
|
|
82
|
+ for Resp in responses:
|
|
83
|
+ # Suppress invalid chars (coming from debug info)
|
|
84
|
+ try:
|
|
85
|
+ clean_response = Resp.decode('utf8').rstrip().lstrip()
|
|
86
|
+ clean_responses.append(clean_response)
|
|
87
|
+ debugPrint(f'<< {clean_response}')
|
|
88
|
+ except:
|
|
89
|
+ pass
|
|
90
|
+ return clean_responses
|
|
91
|
+
|
|
92
|
+ #------------------#
|
|
93
|
+ # SDCard functions #
|
|
94
|
+ #------------------#
|
|
95
|
+ def _CheckSDCard():
|
|
96
|
+ debugPrint('Checking SD card...')
|
|
97
|
+ _Send('M21')
|
|
98
|
+ Responses = _Recv()
|
|
99
|
+ if len(Responses) < 1 or not any('SD card ok' in r for r in Responses):
|
|
100
|
+ raise Exception('Error accessing SD card')
|
|
101
|
+ debugPrint('SD Card OK')
|
|
102
|
+ return True
|
|
103
|
+
|
|
104
|
+ #----------------#
|
|
105
|
+ # File functions #
|
|
106
|
+ #----------------#
|
|
107
|
+ def _GetFirmwareFiles(UseLongFilenames):
|
|
108
|
+ debugPrint('Get firmware files...')
|
|
109
|
+ _Send(f"M20 F{'L' if UseLongFilenames else ''}")
|
|
110
|
+ Responses = _Recv()
|
|
111
|
+ if len(Responses) < 3 or not any('file list' in r for r in Responses):
|
|
112
|
+ raise Exception('Error getting firmware files')
|
|
113
|
+ debugPrint('OK')
|
|
114
|
+ return Responses
|
|
115
|
+
|
|
116
|
+ def _FilterFirmwareFiles(FirmwareList, UseLongFilenames):
|
|
117
|
+ Firmwares = []
|
|
118
|
+ for FWFile in FirmwareList:
|
|
119
|
+ # For long filenames take the 3rd column of the firmwares list
|
|
120
|
+ if UseLongFilenames:
|
|
121
|
+ Space = 0
|
|
122
|
+ Space = FWFile.find(' ')
|
|
123
|
+ if Space >= 0: Space = FWFile.find(' ', Space + 1)
|
|
124
|
+ if Space >= 0: FWFile = FWFile[Space + 1:]
|
|
125
|
+ if not '/' in FWFile and '.BIN' in FWFile.upper():
|
|
126
|
+ Firmwares.append(FWFile[:FWFile.upper().index('.BIN') + 4])
|
|
127
|
+ return Firmwares
|
|
128
|
+
|
|
129
|
+ def _RemoveFirmwareFile(FirmwareFile):
|
|
130
|
+ _Send(f'M30 /{FirmwareFile}')
|
|
131
|
+ Responses = _Recv()
|
|
132
|
+ Removed = len(Responses) >= 1 and any('File deleted' in r for r in Responses)
|
|
133
|
+ if not Removed:
|
|
134
|
+ raise Exception(f"Firmware file '{FirmwareFile}' not removed")
|
|
135
|
+ return Removed
|
|
136
|
+
|
|
137
|
+ def _RollbackUpload(FirmwareFile):
|
|
138
|
+ if not rollback: return
|
|
139
|
+ print(f"Rollback: trying to delete firmware '{FirmwareFile}'...")
|
|
140
|
+ _OpenPort()
|
|
141
|
+ # Wait for SD card release
|
|
142
|
+ time.sleep(1)
|
|
143
|
+ # Remount SD card
|
|
144
|
+ _CheckSDCard()
|
|
145
|
+ print(' OK' if _RemoveFirmwareFile(FirmwareFile) else ' Error!')
|
|
146
|
+ _ClosePort()
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+ #---------------------#
|
|
150
|
+ # Callback Entrypoint #
|
|
151
|
+ #---------------------#
|
|
152
|
+ port = None
|
|
153
|
+ protocol = None
|
|
154
|
+ filetransfer = None
|
|
155
|
+ rollback = False
|
|
156
|
+
|
|
157
|
+ # Get Marlin evironment vars
|
|
158
|
+ MarlinEnv = env['MARLIN_FEATURES']
|
|
159
|
+ marlin_pioenv = _GetMarlinEnv(MarlinEnv, 'PIOENV')
|
|
160
|
+ marlin_motherboard = _GetMarlinEnv(MarlinEnv, 'MOTHERBOARD')
|
|
161
|
+ marlin_board_info_name = _GetMarlinEnv(MarlinEnv, 'BOARD_INFO_NAME')
|
|
162
|
+ marlin_board_custom_build_flags = _GetMarlinEnv(MarlinEnv, 'BOARD_CUSTOM_BUILD_FLAGS')
|
|
163
|
+ marlin_firmware_bin = _GetMarlinEnv(MarlinEnv, 'FIRMWARE_BIN')
|
|
164
|
+ marlin_long_filename_host_support = _GetMarlinEnv(MarlinEnv, 'LONG_FILENAME_HOST_SUPPORT') is not None
|
|
165
|
+ marlin_longname_write = _GetMarlinEnv(MarlinEnv, 'LONG_FILENAME_WRITE_SUPPORT') is not None
|
|
166
|
+ marlin_custom_firmware_upload = _GetMarlinEnv(MarlinEnv, 'CUSTOM_FIRMWARE_UPLOAD') is not None
|
|
167
|
+ marlin_short_build_version = _GetMarlinEnv(MarlinEnv, 'SHORT_BUILD_VERSION')
|
|
168
|
+ marlin_string_config_h_author = _GetMarlinEnv(MarlinEnv, 'STRING_CONFIG_H_AUTHOR')
|
|
169
|
+
|
|
170
|
+ # Get firmware upload params
|
|
171
|
+ upload_firmware_source_name = str(source[0]) # Source firmware filename
|
|
172
|
+ upload_speed = env['UPLOAD_SPEED'] if 'UPLOAD_SPEED' in env else 115200
|
|
173
|
+ # baud rate of serial connection
|
|
174
|
+ upload_port = _GetUploadPort(env) # Serial port to use
|
|
175
|
+
|
|
176
|
+ # Set local upload params
|
|
177
|
+ upload_firmware_target_name = os.path.basename(upload_firmware_source_name)
|
|
178
|
+ # Target firmware filename
|
|
179
|
+ upload_timeout = 1000 # Communication timout, lossy/slow connections need higher values
|
|
180
|
+ upload_blocksize = 512 # Transfer block size. 512 = Autodetect
|
|
181
|
+ upload_compression = True # Enable compression
|
|
182
|
+ upload_error_ratio = 0 # Simulated corruption ratio
|
|
183
|
+ upload_test = False # Benchmark the serial link without storing the file
|
|
184
|
+ upload_reset = True # Trigger a soft reset for firmware update after the upload
|
|
185
|
+
|
|
186
|
+ # Set local upload params based on board type to change script behavior
|
|
187
|
+ # "upload_delete_old_bins": delete all *.bin files in the root of SD Card
|
|
188
|
+ upload_delete_old_bins = marlin_motherboard in ['BOARD_CREALITY_V4', 'BOARD_CREALITY_V4210', 'BOARD_CREALITY_V422', 'BOARD_CREALITY_V423',
|
|
189
|
+ 'BOARD_CREALITY_V427', 'BOARD_CREALITY_V431', 'BOARD_CREALITY_V452', 'BOARD_CREALITY_V453',
|
|
190
|
+ 'BOARD_CREALITY_V24S1']
|
|
191
|
+ # "upload_random_name": generate a random 8.3 firmware filename to upload
|
|
192
|
+ upload_random_filename = marlin_motherboard in ['BOARD_CREALITY_V4', 'BOARD_CREALITY_V4210', 'BOARD_CREALITY_V422', 'BOARD_CREALITY_V423',
|
|
193
|
+ 'BOARD_CREALITY_V427', 'BOARD_CREALITY_V431', 'BOARD_CREALITY_V452', 'BOARD_CREALITY_V453',
|
|
194
|
+ 'BOARD_CREALITY_V24S1'] and not marlin_long_filename_host_support
|
|
195
|
+
|
|
196
|
+ try:
|
|
197
|
+
|
|
198
|
+ # Start upload job
|
|
199
|
+ print(f"Uploading firmware '{os.path.basename(upload_firmware_target_name)}' to '{marlin_motherboard}' via '{upload_port}'")
|
|
200
|
+
|
|
201
|
+ # Dump some debug info
|
|
202
|
+ if Debug:
|
|
203
|
+ print('Upload using:')
|
|
204
|
+ print('---- Marlin -----------------------------------')
|
|
205
|
+ print(f' PIOENV : {marlin_pioenv}')
|
|
206
|
+ print(f' SHORT_BUILD_VERSION : {marlin_short_build_version}')
|
|
207
|
+ print(f' STRING_CONFIG_H_AUTHOR : {marlin_string_config_h_author}')
|
|
208
|
+ print(f' MOTHERBOARD : {marlin_motherboard}')
|
|
209
|
+ print(f' BOARD_INFO_NAME : {marlin_board_info_name}')
|
|
210
|
+ print(f' CUSTOM_BUILD_FLAGS : {marlin_board_custom_build_flags}')
|
|
211
|
+ print(f' FIRMWARE_BIN : {marlin_firmware_bin}')
|
|
212
|
+ print(f' LONG_FILENAME_HOST_SUPPORT : {marlin_long_filename_host_support}')
|
|
213
|
+ print(f' LONG_FILENAME_WRITE_SUPPORT : {marlin_longname_write}')
|
|
214
|
+ print(f' CUSTOM_FIRMWARE_UPLOAD : {marlin_custom_firmware_upload}')
|
|
215
|
+ print('---- Upload parameters ------------------------')
|
|
216
|
+ print(f' Source : {upload_firmware_source_name}')
|
|
217
|
+ print(f' Target : {upload_firmware_target_name}')
|
|
218
|
+ print(f' Port : {upload_port} @ {upload_speed} baudrate')
|
|
219
|
+ print(f' Timeout : {upload_timeout}')
|
|
220
|
+ print(f' Block size : {upload_blocksize}')
|
|
221
|
+ print(f' Compression : {upload_compression}')
|
|
222
|
+ print(f' Error ratio : {upload_error_ratio}')
|
|
223
|
+ print(f' Test : {upload_test}')
|
|
224
|
+ print(f' Reset : {upload_reset}')
|
|
225
|
+ print('-----------------------------------------------')
|
|
226
|
+
|
|
227
|
+ # Custom implementations based on board parameters
|
|
228
|
+ # Generate a new 8.3 random filename
|
|
229
|
+ if upload_random_filename:
|
|
230
|
+ upload_firmware_target_name = f"fw-{''.join(random.choices('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', k=5))}.BIN"
|
|
231
|
+ print(f"Board {marlin_motherboard}: Overriding firmware filename to '{upload_firmware_target_name}'")
|
|
232
|
+
|
|
233
|
+ # Delete all *.bin files on the root of SD Card (if flagged)
|
|
234
|
+ if upload_delete_old_bins:
|
|
235
|
+ # CUSTOM_FIRMWARE_UPLOAD is needed for this feature
|
|
236
|
+ if not marlin_custom_firmware_upload:
|
|
237
|
+ raise Exception(f"CUSTOM_FIRMWARE_UPLOAD must be enabled in 'Configuration_adv.h' for '{marlin_motherboard}'")
|
|
238
|
+
|
|
239
|
+ # Init & Open serial port
|
|
240
|
+ port = serial.Serial(upload_port, baudrate = upload_speed, write_timeout = 0, timeout = 0.1)
|
|
241
|
+ _OpenPort()
|
|
242
|
+
|
|
243
|
+ # Check SD card status
|
|
244
|
+ _CheckSDCard()
|
|
245
|
+
|
|
246
|
+ # Get firmware files
|
|
247
|
+ FirmwareFiles = _GetFirmwareFiles(marlin_long_filename_host_support)
|
|
248
|
+ if Debug:
|
|
249
|
+ for FirmwareFile in FirmwareFiles:
|
|
250
|
+ print(f'Found: {FirmwareFile}')
|
|
251
|
+
|
|
252
|
+ # Get all 1st level firmware files (to remove)
|
|
253
|
+ OldFirmwareFiles = _FilterFirmwareFiles(FirmwareFiles[1:len(FirmwareFiles)-2], marlin_long_filename_host_support) # Skip header and footers of list
|
|
254
|
+ if len(OldFirmwareFiles) == 0:
|
|
255
|
+ print('No old firmware files to delete')
|
|
256
|
+ else:
|
|
257
|
+ print(f"Remove {len(OldFirmwareFiles)} old firmware file{'s' if len(OldFirmwareFiles) != 1 else ''}:")
|
|
258
|
+ for OldFirmwareFile in OldFirmwareFiles:
|
|
259
|
+ print(f" -Removing- '{OldFirmwareFile}'...")
|
|
260
|
+ print(' OK' if _RemoveFirmwareFile(OldFirmwareFile) else ' Error!')
|
|
261
|
+
|
|
262
|
+ # Close serial
|
|
263
|
+ _ClosePort()
|
|
264
|
+
|
|
265
|
+ # Cleanup completed
|
|
266
|
+ debugPrint('Cleanup completed')
|
|
267
|
+
|
|
268
|
+ # WARNING! The serial port must be closed here because the serial transfer that follow needs it!
|
|
269
|
+
|
|
270
|
+ # Upload firmware file
|
|
271
|
+ debugPrint(f"Copy '{upload_firmware_source_name}' --> '{upload_firmware_target_name}'")
|
|
272
|
+ protocol = MarlinBinaryProtocol.Protocol(upload_port, upload_speed, upload_blocksize, float(upload_error_ratio), int(upload_timeout))
|
|
273
|
+ #echologger = MarlinBinaryProtocol.EchoProtocol(protocol)
|
|
274
|
+ protocol.connect()
|
|
275
|
+ # Mark the rollback (delete broken transfer) from this point on
|
|
276
|
+ rollback = True
|
|
277
|
+ filetransfer = MarlinBinaryProtocol.FileTransferProtocol(protocol)
|
|
278
|
+ transferOK = filetransfer.copy(upload_firmware_source_name, upload_firmware_target_name, upload_compression, upload_test)
|
|
279
|
+ protocol.disconnect()
|
|
280
|
+
|
|
281
|
+ # Notify upload completed
|
|
282
|
+ protocol.send_ascii('M117 Firmware uploaded' if transferOK else 'M117 Firmware upload failed')
|
|
283
|
+
|
|
284
|
+ # Remount SD card
|
|
285
|
+ print('Wait for SD card release...')
|
|
286
|
+ time.sleep(1)
|
|
287
|
+ print('Remount SD card')
|
|
288
|
+ protocol.send_ascii('M21')
|
|
289
|
+
|
|
290
|
+ # Transfer failed?
|
|
291
|
+ if not transferOK:
|
|
292
|
+ protocol.shutdown()
|
|
293
|
+ _RollbackUpload(upload_firmware_target_name)
|
|
294
|
+ else:
|
|
295
|
+ # Trigger firmware update
|
|
296
|
+ if upload_reset:
|
|
297
|
+ print('Trigger firmware update...')
|
|
298
|
+ protocol.send_ascii('M997', True)
|
|
299
|
+ protocol.shutdown()
|
|
300
|
+
|
|
301
|
+ print('Firmware update completed' if transferOK else 'Firmware update failed')
|
|
302
|
+ return 0 if transferOK else -1
|
|
303
|
+
|
|
304
|
+ except KeyboardInterrupt:
|
|
305
|
+ print('Aborted by user')
|
|
306
|
+ if filetransfer: filetransfer.abort()
|
|
307
|
+ if protocol:
|
|
308
|
+ protocol.disconnect()
|
|
309
|
+ protocol.shutdown()
|
|
310
|
+ _RollbackUpload(upload_firmware_target_name)
|
|
311
|
+ _ClosePort()
|
|
312
|
+ raise
|
|
313
|
+
|
|
314
|
+ except serial.SerialException as se:
|
|
315
|
+ # This exception is raised only for send_ascii data (not for binary transfer)
|
|
316
|
+ print(f'Serial excepion: {se}, transfer aborted')
|
|
317
|
+ if protocol:
|
|
318
|
+ protocol.disconnect()
|
|
319
|
+ protocol.shutdown()
|
|
320
|
+ _RollbackUpload(upload_firmware_target_name)
|
|
321
|
+ _ClosePort()
|
|
322
|
+ raise Exception(se)
|
|
323
|
+
|
|
324
|
+ except MarlinBinaryProtocol.FatalError:
|
|
325
|
+ print('Too many retries, transfer aborted')
|
|
326
|
+ if protocol:
|
|
327
|
+ protocol.disconnect()
|
|
328
|
+ protocol.shutdown()
|
|
329
|
+ _RollbackUpload(upload_firmware_target_name)
|
|
330
|
+ _ClosePort()
|
|
331
|
+ raise
|
|
332
|
+
|
|
333
|
+ except Exception as ex:
|
|
334
|
+ print(f"\nException: {ex}, transfer aborted")
|
|
335
|
+ if protocol:
|
|
336
|
+ protocol.disconnect()
|
|
337
|
+ protocol.shutdown()
|
|
338
|
+ _RollbackUpload(upload_firmware_target_name)
|
|
339
|
+ _ClosePort()
|
|
340
|
+ print('Firmware not updated')
|
|
341
|
+ raise
|
342
|
342
|
|
343
|
343
|
# Attach custom upload callback
|
344
|
344
|
env.Replace(UPLOADCMD=Upload)
|