216 lines
6.9 KiB
Python
216 lines
6.9 KiB
Python
'''
|
||
Copyright 2020 Blue Liang, liangkangnan@163.com
|
||
|
||
Licensed under the Apache License, Version 2.0 (the "License");
|
||
you may not use this file except in compliance with the License.
|
||
You may obtain a copy of the License at
|
||
|
||
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
||
Unless required by applicable law or agreed to in writing, software
|
||
distributed under the License is distributed on an "AS IS" BASIS,
|
||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
See the License for the specific language governing permissions and
|
||
limitations under the License.
|
||
'''
|
||
|
||
import os
|
||
import sys
|
||
|
||
import serial
|
||
#import serial.tools.list_ports
|
||
|
||
'''
|
||
通过串口下载固件到FPGA开发板,FPGA收到数据后将数据烧写到ROM(Flash)。
|
||
有两种包类型:包0和其他包。包0用来传输文件名和文件大小,其他包用来传输文件内容。
|
||
每个包的大小固定为131个字节(1字节包号+128字节数据+2字节CRC)。
|
||
'''
|
||
|
||
# 包0格式
|
||
# number:0,包序号
|
||
# data[0] ~ data[59]:文件名
|
||
# data[60] ~ data[63]:文件大小(字节),其中data[60]为MSB
|
||
# crc[0]:crc低字节,crc[1]:crc高字节
|
||
'''
|
||
0 1 2 ... 128 129 130
|
||
|-------------------------------------------------------------------|
|
||
| number | data[0] | data[1] | ... | data[127] | crc[0] | crc[1] |
|
||
|-------------------------------------------------------------------|
|
||
'''
|
||
|
||
# 包1 ~ n格式
|
||
# number:包序号
|
||
# data[0]~data[127]:文件内容
|
||
# crc[0]:crc低字节,crc[1]:crc高字节
|
||
'''
|
||
0 1 2 ... 128 129 130
|
||
|-------------------------------------------------------------------|
|
||
| number | data[0] | data[1] | ... | data[127] | crc[0] | crc[1] |
|
||
|-------------------------------------------------------------------|
|
||
'''
|
||
|
||
|
||
ACK = bytes([0x6])
|
||
FIRST_PACKET_LEN = 131
|
||
FILE_NAME_INDEX = 1
|
||
FILE_SIZE_INDEX = 61
|
||
FIRST_PACKET_CRC0_INDEX = 129
|
||
FIRST_PACKET_CRC1_INDEX = 130
|
||
OTHER_PACKET_LEN = 131
|
||
|
||
|
||
serial_com = serial.Serial()
|
||
|
||
|
||
# 串口初始化
|
||
# 串口参数:115200, 8 N 1
|
||
def serial_init():
|
||
serial_com.port = sys.argv[1]
|
||
serial_com.baudrate = 115200
|
||
serial_com.bytesize = serial.EIGHTBITS
|
||
serial_com.parity = serial.PARITY_NONE
|
||
serial_com.stopbits = serial.STOPBITS_ONE
|
||
serial_com.xonxoff = False
|
||
serial_com.rtscts = False
|
||
serial_com.dsrdtr = False
|
||
|
||
if serial_com.is_open == False:
|
||
serial_com.open()
|
||
if serial_com.is_open:
|
||
return 0
|
||
else:
|
||
return -1
|
||
|
||
def serial_deinit():
|
||
if serial_com.is_open == True:
|
||
serial_com.close()
|
||
|
||
# 串口写数据
|
||
def serial_write(b):
|
||
if serial_com.is_open == True:
|
||
serial_com.write(b)
|
||
return len(b)
|
||
else:
|
||
return 0
|
||
|
||
# 串口读数据
|
||
def serial_read(length, timeout):
|
||
if (timeout > 0):
|
||
serial_com.timeout = timeout
|
||
|
||
if serial_com.is_open == True:
|
||
data = serial_com.read(length)
|
||
if len(data) > 0:
|
||
return data
|
||
else:
|
||
return -1
|
||
else:
|
||
return -1
|
||
|
||
# CRC计算
|
||
def calc_crc16(data):
|
||
crc = 0xFFFF
|
||
for pos in data:
|
||
crc ^= pos
|
||
for i in range(8):
|
||
if ((crc & 1) != 0):
|
||
crc >>= 1
|
||
crc ^= 0xA001
|
||
else:
|
||
crc >>= 1
|
||
return crc
|
||
|
||
# 主函数
|
||
def main():
|
||
if serial_init() == 0:
|
||
bin_file_size = os.path.getsize(sys.argv[2])
|
||
print('bin file size: %d bytes' % bin_file_size)
|
||
bin_file_name = os.path.basename(sys.argv[2])
|
||
print('bin file name: ' + bin_file_name)
|
||
print('Total %d packets to be sent' % (int(bin_file_size / 128) + 1))
|
||
|
||
############### 第一个包 ###############
|
||
print('send #0 packet')
|
||
packet = [0] * FIRST_PACKET_LEN
|
||
# 1.包号
|
||
packet[0] = 0
|
||
i = FILE_NAME_INDEX
|
||
# 2.文件名
|
||
for c in bin_file_name:
|
||
packet[i] = ord(c)
|
||
i = i + 1
|
||
# 3.文件大小
|
||
packet[FILE_SIZE_INDEX] = (bin_file_size >> 24) & 0xff
|
||
packet[FILE_SIZE_INDEX + 1] = (bin_file_size >> 16) & 0xff
|
||
packet[FILE_SIZE_INDEX + 2] = (bin_file_size >> 8) & 0xff
|
||
packet[FILE_SIZE_INDEX + 3] = (bin_file_size >> 0) & 0xff
|
||
crc = calc_crc16(packet[1:129])
|
||
# 4.CRC
|
||
packet[FIRST_PACKET_CRC0_INDEX] = (crc >> 0) & 0xff
|
||
packet[FIRST_PACKET_CRC1_INDEX] = (crc >> 8) & 0xff
|
||
|
||
#print(packet)
|
||
# 5.发送
|
||
serial_write(bytes(packet))
|
||
# 6.读应答
|
||
ack = serial_read(1, 3)
|
||
if (ack != ACK):
|
||
print('packet0 NACK from slave')
|
||
return
|
||
|
||
############### 剩余包 ###############
|
||
bin_file = open(sys.argv[2], 'rb')
|
||
data = bin_file.read(bin_file_size)
|
||
remain_data_len = bin_file_size
|
||
remain_data_index = 0
|
||
# 文件有多少个128字节
|
||
for i in range(int(bin_file_size / 128) + 1):
|
||
print('send #%d packet' % (i + 1))
|
||
packet = [0] * OTHER_PACKET_LEN
|
||
packet[0] = i + 1
|
||
j = 1
|
||
k = remain_data_index
|
||
if (remain_data_len >= 128):
|
||
for r in range(128):
|
||
packet[j] = data[k]
|
||
j = j + 1
|
||
k = k + 1
|
||
crc = calc_crc16(packet[1:129])
|
||
packet[FIRST_PACKET_CRC0_INDEX] = (crc >> 0) & 0xff
|
||
packet[FIRST_PACKET_CRC1_INDEX] = (crc >> 8) & 0xff
|
||
serial_write(bytes(packet))
|
||
ack = serial_read(1, 3)
|
||
if (ack != ACK):
|
||
print('NACK1 from slave')
|
||
return
|
||
remain_data_len = remain_data_len - 128
|
||
remain_data_index = remain_data_index + 128
|
||
else:
|
||
for r in range(remain_data_len):
|
||
packet[j] = data[k]
|
||
j = j + 1
|
||
k = k + 1
|
||
crc = calc_crc16(packet[1:129])
|
||
packet[FIRST_PACKET_CRC0_INDEX] = (crc >> 0) & 0xff
|
||
packet[FIRST_PACKET_CRC1_INDEX] = (crc >> 8) & 0xff
|
||
serial_write(bytes(packet))
|
||
ack = serial_read(1, 3)
|
||
if (ack != ACK):
|
||
print('NACK2 from slave')
|
||
return
|
||
|
||
bin_file.close()
|
||
|
||
print('Send successfully...')
|
||
else:
|
||
print('!!! serial init failed !!!')
|
||
|
||
serial_deinit()
|
||
|
||
# 程序入口
|
||
if __name__ == "__main__":
|
||
if (len(sys.argv) != 3):
|
||
print('Usage: python ' + sys.argv[0] + ' COMx ' + 'bin_file')
|
||
else:
|
||
main()
|