国民技术N32G430开发笔记(15)- IAP升级 树莓派串口发送数据
IAP升级 树莓派串口发送数据
1、树莓派接入usb转串口模块后,会生成/dev/ttyUSB0节点,因为树莓派内核已经编译usb_serial以及各模块的驱动。
我们直接对ttyUSB0节点编程即可。
2、协议同上一节
cmd + data_lenght + data0 + …+ datax + checksum
1、获取版本号 0x01 0x02 0x00 0x00 checksum
2、升级
1、进入升级模式 0x02 0x02 0x00 0x00 checksum
2、升级文件大小 0x03 0x04 0x00 0x00 0x00 0x00 checksum
3、数据包发送 0x04 0x80 0x00 0x00 0x00 0x00 … checksum
4、数据包发送完成 0x05 0x02 0x00 0x00 checksum
checksum采用crc16的检验方法。
3、升级过程:
1、发送升级模式命令。
2、发送文件大小命令
3、循环发送Application.bin的升级包,每包数据head+64个数据+checksum。
4、发送升级完成命令。
4、代码解析如下:
在build目录执行 cmake …;make 即可编译出uartiap。
CMakeLists.txt
cmake_minimum_required(VERSION 3.18.4)
project (uartIap)
aux_source_directory(. C_SOURCES)
aux_source_directory(./UartIap C_SOURCES_UART)
include_directories(./UartIap)
add_executable(${PROJECT_NAME} ${C_SOURCES} ${C_SOURCES_UART})
target_link_libraries(${PROJECT_NAME} pthread)
n32g430_iap.c
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#include "uart.h"
#define APPLICATION_PATH "Application.bin"
#define UPGRADE_DATA_PACKAGES_LENGHT 0x40
#define UPGRADE_PACKAGES_LENGHT 0x40 + 0x04
typedef enum{
MI_FALSE = 0,
MI_TRUE = 1,
}MI_BOOL;
typedef unsigned char MI_U8;
typedef unsigned short MI_U16;
MI_U8 get_ver_cmd[6] = {0x01,0x02,0x00,0x00,0x00,0x00};
MI_U8 update_cmd[6] = {0x02,0x02,0x00,0x00,0x00,0x00};
MI_U8 file_size_cmd[8] = {0x03,0x04,0x00,0x00,0x00,0x00,0x00,0x00};
MI_U8 file_package[UPGRADE_PACKAGES_LENGHT] = {0x04,UPGRADE_DATA_PACKAGES_LENGHT};
MI_U8 update_complete_cmd[6] = {0x05,0x02,0x00,0x00};
MI_U16 w_num = 0;
static MI_U8 isRunning = 0;
char r_data[256] = {0};
sem_t sem;
static MI_BOOL get_update_file_size(char * file_path,size_t *size)
{
FILE *file;
file = fopen(file_path,"rb");
if (!file)
{
perror("get_update_file_size fopen error\n");
return MI_FALSE;
}
fseek(file, 0L, SEEK_END);
*size = ftell(file);
fclose(file);
return MI_TRUE;
}
static MI_U16 CRC16(MI_U8 * buf, MI_U16 len)
{
MI_U16 i;
MI_U16 crc = 0xffff;
if (len == 0) {
len = 1;
}
while (len--) {
crc ^= *buf;
for (i = 0; i<8; i++)
{
if (crc & 1) {
crc >>= 1;
crc ^= 0xA001;
}
else {
crc >>= 1;
}
}
buf++;
}
return(crc);
}
static MI_BOOL compare(MI_U8 *des,MI_U8 *src,int len)
{
while (len--)
{
if (*des != *src)
{
return MI_FALSE;
}
des++;
src++;
}
return MI_TRUE;
}
static void send_get_version_cmd(int fd)
{
int len = sizeof(get_ver_cmd);
int crc = CRC16(get_ver_cmd,len-2);
get_ver_cmd[len-2] = crc & 0x00ff;
get_ver_cmd[len-1] = ((crc >> 8) & 0x00ff);
serialWrite(fd,get_ver_cmd,sizeof(get_ver_cmd));
}
static void send_enter_update_cmd(int fd)
{
int len = sizeof(update_cmd);
int crc = CRC16(update_cmd,len-2);
update_cmd[len-2] = crc & 0x00ff;
update_cmd[len-1] = ((crc >> 8) & 0x00ff);
serialWrite(fd,update_cmd,sizeof(update_cmd));
}
static MI_BOOL send_update_file_size_cmd(int fd)
{
int len = sizeof(file_size_cmd);
size_t file_size = 0;
get_update_file_size(APPLICATION_PATH,&file_size);
file_size_cmd[2] = (file_size >> 24 & (0xff));
file_size_cmd[3] = (file_size >> 16 & (0xff));
file_size_cmd[4] = (file_size >> 8 & (0xff));
file_size_cmd[5] = (file_size & (0xff));
int crc = CRC16(file_size_cmd,len-2);
file_size_cmd[len-2] = crc & 0x00ff;
file_size_cmd[len-1] = ((crc >> 8) & 0x00ff);
serialWrite(fd,file_size_cmd,sizeof(file_size_cmd));
return MI_TRUE;
}
static MI_BOOL send_file_every_package(int fd)
{
int len = sizeof(file_package);
FILE *fp;
size_t file_size;
int package_num;
MI_U8 package_buff[UPGRADE_DATA_PACKAGES_LENGHT] = {0};
fp = fopen(APPLICATION_PATH,"rb");
if (!fp)
{
perror("fopen error\n");
return MI_FALSE;
}
get_update_file_size(APPLICATION_PATH,&file_size);
if (file_size % UPGRADE_DATA_PACKAGES_LENGHT == 0 )
{
package_num = file_size / UPGRADE_DATA_PACKAGES_LENGHT;
}
else
{
package_num = (file_size / UPGRADE_DATA_PACKAGES_LENGHT) + 1;
}
printf("pageage_num == %d\n",package_num);
while (!feof(fp)/* condition */)
{
/* code */
int r_len = fread(package_buff,1,UPGRADE_DATA_PACKAGES_LENGHT,fp);
// 最后读出来不满128 ,用0xff补全。
if (r_len != UPGRADE_DATA_PACKAGES_LENGHT)
{
for (int i=r_len;i<UPGRADE_DATA_PACKAGES_LENGHT;i++)
{
package_buff[i] = 0xff;
}
}
memcpy(&file_package[2],package_buff,sizeof(package_buff));
int crc = CRC16(file_package,sizeof(file_package)-2);
file_package[sizeof(file_package)-2] = crc & 0x00ff;
file_package[sizeof(file_package)-1] = ((crc >> 8) & 0x00ff);
usleep(30 * 1000);
w_num++;
printf("send package process == [%03d]\n", ((w_num * 100)/package_num));
#if DEBUG
for(int i=0;i< len;i++)
{
printf("0x%02x ",file_package[i]);
if ((i+1) % 16 == 0)
printf("\n");
}
printf("\n");
#endif
memset(r_data,0,sizeof(r_data));
serialWrite(fd,file_package,len);
sem_wait(&sem);
#if DEBUG
// for(int i=0;i< len;i++)
// {
// printf("0x%02x ",r_data[i]);
// if ((i+1) % 16 == 0)
// printf("\n");
// }
// printf("\n");
// int status = compare(r_data,file_package,20);
// if (status)
// {
// printf("send_file_every_package and receive cmd success!\n");
// }
// else
// {
// perror("send_file_every_package not equal receive cmd\n");
// }
//printf("read len == %d w_num == %d \n",len,w_num);
#endif
}
fclose(fp);
return MI_TRUE;
}
static MI_BOOL send_update_complete_cmd(int fd)
{
int len = sizeof(update_complete_cmd);
int crc = CRC16(update_complete_cmd,len-2);
update_complete_cmd[len-2] = crc & 0x00ff;
update_complete_cmd[len-1] = ((crc >> 8) & 0x00ff);
serialWrite(fd,update_complete_cmd,sizeof(update_complete_cmd));
return MI_TRUE;
}
void *uart_read_thread(void *arg)
{
int fd = *((int *)arg);
size_t size ;
sem_wait(&sem);
while(isRunning)
{
size = serialRead(fd,r_data,256); //阻塞方式去读
#if DEBUG
if (size > 0)
{
for(int i=0;i<size;i++)
{
printf("0x%02x ",r_data[i]);
}
printf("\n");
}
#endif
sem_post(&sem);
}
printf("uart_read_thread exit\n");
pthread_exit(0);
}
int main(int argc,char *argv[])
{
int fd = 0;
int ret;
char w_data[] = "hello world\n";
MI_U16 crc = 0;
MI_BOOL status;
pthread_t m_read_thread ;
size_t update_file_size;
sem_init(&sem, 0, 0);
fd = serialOpen("/dev/ttyUSB0",115200);
if (fd > 0)
{
printf("open ttyUSB0 ok\n");
}
else
{
printf("open ttyUSB0 fail\n");
return -1;
}
ret = pthread_create(&m_read_thread,NULL,uart_read_thread,&fd);
if (ret)
{
perror("pthread_create error\n");
return -1;
}
else
{
isRunning = 1;
sem_post(&sem);
}
sleep(1);// 获取一下N32G430C8L7的版本号
memset(r_data,0,sizeof(r_data));
send_get_version_cmd(fd);
sem_wait(&sem);
printf("get version == %s\n",r_data);
memset(r_data,0,sizeof(r_data));
send_enter_update_cmd(fd);
sem_wait(&sem);
status = compare(r_data,update_cmd,sizeof(update_cmd));
if (status)
{
printf("send_enter_update_cmd and receive cmd success!\n");
}
else
{
perror("send_enter_update_cmd not equal receive cmd\n");
}
get_update_file_size(APPLICATION_PATH,&update_file_size);
printf("get update file size == %ld\n",update_file_size);
memset(r_data,0,sizeof(r_data));
send_update_file_size_cmd(fd);
sem_wait(&sem);
status = compare(r_data,file_size_cmd,sizeof(file_size_cmd));
if (status)
{
printf("send_update_file_size_cmd and receive cmd success!\n");
}
else
{
perror("send_update_file_size_cmd not equal receive cmd\n");
}
send_file_every_package(fd);
memset(r_data,0,sizeof(r_data));
send_update_complete_cmd(fd);
sem_wait(&sem);
pthread_cancel(m_read_thread);
isRunning = 0;
pthread_join(m_read_thread,NULL);
serialClose(fd);
printf("raspberryPi App exit!\n");
}
uart.c
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>
#include "uart.h"
static speed_t getBaudRate(int baudRate)
{
switch(baudRate) {
case 0: return B0;
case 50: return B50;
case 75: return B75;
case 110: return B110;
case 134: return B134;
case 150: return B150;
case 200: return B200;
case 300: return B300;
case 600: return B600;
case 1200: return B1200;
case 1800: return B1800;
case 2400: return B2400;
case 4800: return B4800;
case 9600: return B9600;
case 19200: return B19200;
case 38400: return B38400;
case 57600: return B57600;
case 115200: return B115200;
case 230400: return B230400;
case 460800: return B460800;
case 500000: return B500000;
case 576000: return B576000;
case 921600: return B921600;
case 1000000: return B1000000;
case 1152000: return B1152000;
case 1500000: return B1500000;
case 2000000: return B2000000;
case 2500000: return B2500000;
case 3000000: return B3000000;
case 3500000: return B3500000;
case 4000000: return B4000000;
default: return -1;
}
}
static int setParity(int fd,int dataBits,int stopBits,int parity)
{
struct termios options;
if (tcgetattr (fd, &options) != 0) {
printf ("SetupSerial 1");
return (-1);
}
options.c_cflag &= ~CSIZE;
switch (dataBits) {
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
fprintf (stderr, "Unsupported data size\n");
return (-1);
}
switch (parity) {
case 'n':
case 'N':
options.c_cflag &= ~PARENB; /* Clear parity enable */
options.c_iflag &= ~INPCK; /* Enable parity checking */
break;
case 'o':
case 'O':
options.c_cflag |= (PARODD | PARENB);
options.c_iflag |= INPCK; /* Disable parity checking */
break;
case 'e':
case 'E':
options.c_cflag |= PARENB; /* Enable parity */
options.c_cflag &= ~PARODD;
options.c_iflag |= INPCK; /* Disable parity checking */
break;
case 'S':
case 's': /*as no parity */
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
break;
default:
fprintf (stderr, "Unsupported parity\n");
return (-1);
}
switch (stopBits) {
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
fprintf (stderr, "Unsupported stop bits\n");
return (-1);
}
/* Set input parity option */
if (parity != 'n')
options.c_iflag |= INPCK;
tcflush (fd, TCIFLUSH);
options.c_cc[VTIME] = 0x01;
options.c_cc[VMIN] = 0xFF; /* Update the options and do it NOW */
//qd to set raw mode, which is copied from web
options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON);
options.c_oflag &= ~OPOST;
options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
options.c_cflag &= ~(CSIZE | PARENB);
options.c_cflag |= CS8;
if (tcsetattr (fd, TCSANOW, &options) != 0) {
perror ("SetupSerial 3");
return (-1);
}
return 0;
}
int serialOpen(const char *path, int baudRate)
{
int fd;
speed_t speed;
/* Check arguments */
{
speed = getBaudRate(baudRate);
if (speed == -1) {
printf("get Baud rate error\n");
return -1;
}
}
{
fd = open(path, O_RDWR);
if (fd == -1)
{
printf("open serial error =%d\n",fd);
return -1;
}
}
/* Configure device */
{
struct termios cfg;
if (tcgetattr(fd, &cfg))
{
printf("tcgetattr() failed\n");
close(fd);
return -1;
}
cfmakeraw(&cfg);
cfsetispeed(&cfg, speed);
cfsetospeed(&cfg, speed);
if (tcsetattr(fd, TCSANOW, &cfg))
{
printf("tcsetattr() failed\n");
close(fd);
return -1;
}
}
setParity(fd,8,1,'N');
//printf("open Success==%d\n",fd);
return fd;
}
int serialWrite(int fd,char *writeData,int len)
{
if (fd > 0){
write(fd,writeData,len);
}else{
printf("[File]=%s[Function]=%s error\n",__FILE__,__FUNCTION__);
return -1;
}
return 0;
}
int serialRead(int fd,char *readData,int len)
{
size_t size = 0;
if (fd > 0)
{
size = read(fd,readData,len);
}
else
{
printf("[File]=%s[Function]=%s error\n",__FILE__,__FUNCTION__);
return -1;
}
return size;
}
int serialClose(int fd)
{
close(fd);
return 0;
}
uart.h
#ifndef __UART_H__
#define __UART_H__
int serialOpen(const char *path, int baudRate);
int serialWrite(int fd,char *writeData,int len);
int serialRead(int fd,char *readData,int len);
int serialClose(int fd);
#endif
5、视频
屏幕录制2023-05-03 15.39.07
6、代码路径 : https://gitee.com/xiaoguo-tec_0/raspberrypi