升级工具的开发

使用Pyqt进行客户端升级工具开发

嵌入式主板有4个arm芯片,有4个裁剪过的arm linux系统,而且要做100个板子的批量升级,所以需要进行合理的线程管理,不拘泥与UI和逻辑分离的开发,要考虑的因素比较多

需要了解的工具

因为涉及到主机和嵌入式板子的通信,所以选择一个合理的通信方式是非常有必要的。

  1. Telnet
    之所以还会用这种不安全的通信方式,是因为系统的升级方式有很多种。第一种是通过串口(uart)通信,在uboot模式下进行系统镜像的烧写,第二种是通过一个AP机(外设主机)进行通信升级,第三种是通过网口进行系统的升级。Telnet适用于网口通信,占据23端口。如果板载系统处于uboot模式,并想要通过网口进行系统升级,只能通过telnet实现,因为uboot模式可以将telnet的client端集中进去,而ssh是不行的
    import telnetlib(只能进行命令行的传输)
  2. Serial
    串口通信是在板子没有系统时进行升级的唯一外部方式。如果是命令行可以直接用serial.write(),如果是包的传输,要使用xmodem,ymodem,zmodem这样的协议进行串口包的传输,但是传输速率不快
    import serial(命令行传输)
    xmodem的方式可以写成一个类,git上有,自行参考(包的传输)
import serial
ser=serial.Serial("/dev/ttyUSB0",9600,timeout=0.5) #使用USB连接串行口
ser=serial.Serial("/dev/ttyAMA0",9600,timeout=0.5) #使用树莓派的GPIO口连接串行口
ser=serial.Serial(1,9600,timeout=0.5)#winsows系统使用com1口连接串行口
ser=serial.Serial(“com1”,9600,timeout=0.5)#winsows系统使用com1口连接串行口
ser=serial.Serial("/dev/ttyS1",9600,timeout=0.5)#Linux系统使用com1口连接串行口
 
ser.open() #打开端口
s = ser.read(10)#从端口读10个字节
ser.write(“hello”)#向端口些数据
ser.close()#关闭端口
data = ser.read(20) #是读20个字符
data = ser.readline() #是读一行,以/n结束,要是没有/n就一直读,阻塞。
#以下为获取输入缓存区的数据大小,然后再读取数据(这是读取数据的常规操作,必须的一个步骤)
 n = self.serial.in_waiting
        if n:
            buf = self._serial_read(n)
  1. SSH SFTP
    网口的安全通信方式,如果系统处于激活状态进行升级,这是最好的通信方式。
    python的包 Paramiko封装了ssh的功能,paramiko包含两个核心组件:SSHClient和SFTPClient。
  • SSHClient的作用类似于Linux的ssh命令,是对SSH会话的封装,该类封装了传输(Transport),通道(Channel)及SFTPClient建立的方法(open_sftp),通常用于执行远程命令。(命令行传输)
  • SFTPClient的作用类似与Linux的sftp命令,是对SFTP客户端的封装,用以实现远程文件操作,如文件上传、下载、修改文件权限等操作。(包的传输)
import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(hostname='192.168.1.105', port=22, username='root', password='123456')
stdin, stdout, stderr = client.exec_command('df -h ') # stdout 为正确输出,stderr为错误输出,同时是有1个变量有值
print(stdout.read().decode('utf-8'))
client.close()
  1. TFTP
    端口号固定为69,TFTP是一个传输文件的简单协议,它基于UDP协议而实现。适合在局域网内进行小文件的传输,如果按照规则配置tftp,会比较麻烦,所以可以直接使用开源的第三包,调用API接口就可以了,第三包是tftpy
    import tftpy
  2. Struct
    MCU通过网口进行升级的时候,这个包是非常重要的。首先通过socket的方式进行主机和mcu板载网口的通信,而socket.write()和mcu通信需要的是字节流(bytes),而python都是字符流,所以需要进行转换。至于这两者的区别,可以自行baidu。
  • 例子1:
    数据格式为:c的结构体
    unsigned short id;
    char[4] tag;
    unsigned int version;
    unsigned int count;
    解包 id, tag, version, count = struct.unpack("!H4s2I", s)
    封包 ss = struct.pack("!H4s2I", id, tag, version, count)。
  • 例子2:
    2字节(包长度)+4字节(包id)+包内容
    解包
    size, = struct.unpack(’>H’,raw[0:2])
    cmd, = struct.unpack(’>H’, raw[2:4])
    string, = struct.unpack(’>{0}s’.format(size - 4), raw[4:size])
    封包
    fmt = “>HH{0}s”.format(len(result)) #结构化数据{}的地方用len代替进去,里面有个0是用于补齐
    args = (len(result), cmd,result)
    data = struct.pack(fmt, *args)
    pack怎么使用有很多资料可以参考
  1. Logging
    logging.basicConfig(
        level=logging.DEBUG, format='[%(levelname)s] %(asctime)s %(filename)s:%(lineno)d %(message)s')
    logging.info("输出至log文件")
  1. Threading
  • 使用线程可以把占据长时间的程序中的任务放到后台去处理。
  • 用户界面可以更加吸引人,比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度。
  • 程序的运行速度可能加快。
  • 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。

def start(self):
       logging.debug('tftp server start on %s' % self.tftp_root)
       self.tftpd_thread = threading.Thread(target=self._tftpd_worker) #_tftpd_worker函数单独进行
       self.tftpd_thread.setDaemon(True) #设置为true,则主线程消失,该线程也跟着消失
       self.tftpd_thread.start()#开始工作
       return True
 
   def isAlive(self):
       return self.tftpd_thread.isAlive()

常用的python包如上,可以先好好学一下各部分的功能,有些git有集成的包,可以直接用

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值