一、介绍
linux烧写包括应用、内核、文件系统、uboot,在实际开发过程中应用修改是最频繁,但是烧写占用时间比较多,这个给出一个工具通过网络和串口一键烧写并启动应用,让linux应用开发烧写变得和单片机一样简单
二、原理思路
通过在linux设备上面创建tcp服务端,
pc上面通过客户端连接服务端,
pc发送文件数据到设备服务端,
设备服务端收到数据将数据写入文件,
当收到数据完成以后,启动新的程序
三、代码实现
设备端
main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "tcp.h"
#include "download.h"
int main()
{
unsigned char rcvbuff[1024] = {0};
unsigned char sendbuff[1024] = {0};
int rcvlen,sendlen;
unsigned short port = 100;
printf("update process start\n");
system("ifconfig");
printf("server port:%d\n",5000);
while(tcp_server_init(port) == -1)
{
usleep(1000);//1ms
port+= 10;
printf("port:%d\n",port);
}
printf("tcp server init ok\n");
while (1)
{
rcvlen = 0;
rcvlen = tcp_server_rcv(0, rcvbuff, 1024);
if(rcvlen > 0)
printf("tcp rcv:%s\n", rcvbuff);
download_run(rcvbuff, rcvlen, sendbuff, &sendlen);
if(sendlen > 0)
{
tcp_server_send(0, sendbuff, sendlen);
sendlen = 0;
}
usleep(10000);//10ms
}
return 0;
}
download.c
#include "file.h"
#include <stdio.h>
enum {
WAIT_CMD = 0,
RCV_FILE,
CLOSE_OLD_PROCESS,
OPEN_NEW_PROCESS
};
unsigned char write_buff[1024] = {0};
int write_len = 0;
unsigned long total_size = 0;
unsigned short check_sum(unsigned char *buff, unsigned int len)
{
unsigned short ret = 0;
unsigned int i;
for ( i = 0; i < len; i++)
{
ret += buff[i];
}
return ret;
}
int mystr_cmp(unsigned char *s1, unsigned char *s2, int len)
{
int i;
for ( i = 0; i < len; i++)
{
if(s1[i] != s2[i])
return 0;
}
return 1;
}
//查询下载命令
//接收文件
//关闭旧的程序
//打开新的程序
int download_run(unsigned char *rcvbuff, int rcvlen,unsigned char *sendbuff, int *sendlen)
{
static char state = 0;
unsigned short check_num = 0;
printf("download_run\n");
switch (state)
{
case WAIT_CMD:
printf("WAIT_CMD\n");
if(rcvlen > 0)
{
if(mystr_cmp(rcvbuff, "download", 8) == 1)
{
state = RCV_FILE;
memcpy(sendbuff, "start", 5);
*sendlen = 5;
total_size = 0;
printf("start to rcv file\n");
}
}
break;
case RCV_FILE:
printf("RCV_FILE\n");
if(mystr_cmp(rcvbuff, "end", 3) == 1)
{
state = CLOSE_OLD_PROCESS;
printf("rcv file ok\nclsoe old app\n");
}
else if(rcvlen > 0)
{
//memcpy(write_buff, rcvbuff, rcvlen);
write_file1("newapp", rcvbuff, rcvlen);
check_num = check_sum(rcvbuff, rcvlen);
sendbuff[0] = check_num&0xff;
sendbuff[1] = check_num>>8;
memcpy(&sendbuff[2],"ok\n", 3);
sendlen = 5;
total_size += rcvlen;
printf("total_size:%d\n", total_size);
}
break;
case CLOSE_OLD_PROCESS:
//close old app
printf("CLOSE_OLD_PROCESS\n");
state = OPEN_NEW_PROCESS;
//system("rm -rf newapp");
// sleep(1);
printf("open new app\n");
break;
case OPEN_NEW_PROCESS:
//open new app
printf("OPEN_NEW_PROCESS\n");
system("chmod 777 newapp");
sleep(1);
system("./newapp");
sleep(1);
printf("app opened\n wait cmd");
state = WAIT_CMD;
break;
default:
state = WAIT_CMD;
break;
}
}
download.h
#ifndef __DOWNLOAD_H
#define __DOWNLOAD_H
int download_run(unsigned char *rcvbuff, int rcvlen,
unsigned char *sendbuff, int *sendlen);
#endif
tcp.c
//-------tcp相关头文件------
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h> //close()
static int socket_fd = 0;
//tcp_client_init()
//1、创建socket
//2、配置为客户端
//3、配置要连接的服务器ip和端口以及协议类型
//4、连接服务器
//5、收发数据
//6、关闭连接
int tcp_client_init(char *ip, int port)
{
int ret;
//1 2
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if(socket_fd == -1)
{
printf("create socket fail\n");
return -1;
}
//3
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;//IPv4协议
servaddr.sin_port = htons(port);//服务器端口号
servaddr.sin_addr.s_addr = inet_addr(ip);//设置服务器
//4
ret = connect(socket_fd, &servaddr, sizeof(servaddr));
if(ret == -1)
{
printf("connect %s fail\n", ip);
return -1;
}
}
//tcp_client_send()
int tcp_client_send(char *buff, int len)
{
write(socket_fd, buff, len);
}
//tcp_client_rcv()
int tcp_client_rcv(char *buff, int *len)
{
int ret;
ret = read(socket_fd, buff, 1024);
*len = ret;
return ret;
}
//tcp_client_close()
int tcp_client_close()
{
close(socket_fd);
}
#define CLENT_NUM 2
struct sockaddr_in sSever_c_sd[CLENT_NUM];
static int socket_s_fd = 0;
static int socket_c_fd[CLENT_NUM] = {0};
//tcp_server_init()
#if 0
1、创建socket
2、设置本地ip和端口以及协议类型
3、绑定
4、监听
5、等待客户端连接
6、收发数据
7、关闭连接
#endif
int tcp_server_init(int port)
{
int ret;
//1
socket_s_fd = socket(AF_INET, SOCK_STREAM, 0);
if(socket_s_fd == -1)
{
printf("create socket fail\n");
return -1;
}
else
{
printf("create socket ok\n");
}
//2
struct sockaddr_in local_addr,c_addr;
local_addr.sin_family = AF_INET;//IPv4协议
local_addr.sin_port = htons(port);//服务器端口号
local_addr.sin_addr.s_addr = INADDR_ANY;//设置服务器ip
//3
ret = bind(socket_s_fd, &local_addr, sizeof(local_addr));
if(ret == -1)
{
printf("bind fail\n");
close(socket_s_fd);
return -1;
}
else
{
printf("bind ok\n");
}
//4
ret = listen(socket_s_fd, 3);
if(ret == -1)
{
printf("listen fail\n");
close(socket_s_fd);
return -1;
}
else
{
printf("listen ok\n");
}
//5
socklen_t addrlen = 0;
while(1)
{
printf("wait client conect\n");
socket_c_fd[0] = accept(socket_s_fd, &c_addr, &addrlen);
if(addrlen != 0)
break;
sleep(1);
}
printf("client conect\n");
return 0;
}
//tcp_server_send()
int tcp_server_send(char c, char *buff, int len)
{
write(socket_c_fd[c], buff, len);
}
//tcp_server_rcv()
int tcp_server_rcv(char c, char *buff, int len)
{
int ret;
ret = read(socket_c_fd[c], buff, len);
return ret;
}
//tcp_server_close()
int tcp_server_close()
{
close(socket_s_fd);
}
tcp.h
#ifndef __TCP_H
#define __TCP_H
int tcp_client_init(char *ip, int port);
int tcp_client_send(unsigned char *buff, int len);
int tcp_client_rcv(unsigned char *buff, int *len);
int tcp_client_close();
int tcp_server_init( int port);
int tcp_server_send(char c, unsigned char *buff, int len);
int tcp_server_rcv(char c, unsigned char *buff, int len);
int tcp_server_close();
#endif
file.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int write_file(char *filename, char *s, int len)
{
int fd;
fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, O_APPEND); //创建并打开文件
if(fd > 0)//创建成功或者打开成功
{
write(fd, s, len);
close(fd);
return -1;
}
else
{
printf("open %s fail\n",filename);
return 0;
}
}
int read_file(char *filename, char *s, int len)
{
int fd,rtn_len;
fd = open(filename, O_RDWR);
rtn_len = read(fd, s, len); /* 读取文件内容 */
close(fd);
return rtn_len;
}
int write_file1(char *filename, char *s, int len)
{
FILE *fp;
fp = fopen(filename, "ab+"); //创建并打开文件
if(fp > 0)//创建成功或者打开成功
{
fwrite(s, 1, len, fp);
fclose(fp);
return -1;
}
else
{
printf("open %s fail\n",filename);
return 0;
}
fclose(fp);
}
int read_file1(char *filename, char *s, int len)
{
int rtn_len;
FILE *fp;
fp = fopen(filename, "rb");
rtn_len = fread(s, 1, len, fp); /* 读取文件内容 */
fclose(fp);
return rtn_len;
}
file.h
#ifndef __FILE_H
#define __FILE_H
int write_file(char *filename, char *s, int len);
int read_file(char *filename, char *s, int len);
int write_file1(char *filename, char *s, int len);
int read_file1(char *filename, char *s, int len);
#endif
编译脚本
build.sh
gcc *.c -o netupdate -w
运行
./netupdate
测试
1、windows传执行文件到linux
1)启动程序./netupdate
2)打开网络调试最新版(老版本发送文件有问题)
连接设备
3)发送download启动下载
4)发送文件
这个文件事先已经编译好了放在windows上的测试程序
选择文件
发送完成以后,发送end结束发送
再发送两次end等待设备启动程序
2、linux传执行文件到linux
linux端需要写发送程序
main.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include "tcp.h"
int mystr_cmp(unsigned char *s1, unsigned char *s2, int len)
{
int i;
for ( i = 0; i < len; i++)
{
if(s1[i] != s2[i])
return 0;
}
return 1;
}
int sendrcv(unsigned char *s, int len, unsigned char *rcv, int rcvlen)
{
unsigned char rcvbuff[1024] = {0};
unsigned char sendbuff[1024] = {0};
int sendlen;
char overtime = 0;
tcp_client_send(s, len);
while(1)
{
if(tcp_client_rcv(rcvbuff, 1024) > 0)
{
if( mystr_cmp(&rcvbuff, rcv, rcvlen) == 1)
{
printf("send ok\n");
return 0;
}
}
overtime++;
usleep(1000);
if(overtime > 3)
{
return -1;
}
}
}
int sendfile(char *filename, char *ip, int port)
{
FILE *fp;
int rtn_len;
int ret = 0;
unsigned char rcvbuff[1024] = {0};
unsigned char sendbuff[1024] = {0};
int rcvlen,sendlen;
unsigned long total_size = 0;
int overtime = 0;
while(tcp_client_init(ip, port) == -1)
{
printf("conncet ip:%s port:%d fail\n",ip, port);
sleep(1);
}
fp = fopen(filename, "rb");
if(fp == -1)
{
printf("open %s fail\n", filename);
}
tcp_client_send("download", 8);
sleep(1);
while(1)
{
rtn_len = 0;
rtn_len = fread(sendbuff, 1, 1024, fp); /* 读取文件内容 */
if(rtn_len > 0)
{
total_size += rtn_len;
tcp_client_send(sendbuff, rtn_len);
printf("total size %d\n", total_size);
}
while(1)
{
if(tcp_client_rcv(rcvbuff, 10) > 0)
{
if( mystr_cmp(&rcvbuff[2], "ok", 2) == 1)
{
printf("send ok\n");
break;
}
}
usleep(1000);
overtime++;
if(overtime > 10)
{
overtime = 0;
break;
}
}
if(rtn_len == 0)
{
printf("send finished\n");
tcp_client_send("end", 3);
break;
}
}
tcp_client_send("end", 3);
sleep(1);
tcp_client_send("end", 3);
fclose(fp);
}
int main(int argc, char *argv[])
{
if(argc > 3)
{
printf("input:%s %s %s\n",argv[1],argv[2],argv[3]);
sendfile(argv[1], argv[2], atoi(argv[3]));
}
else
{
sendfile("test", "192.168.136.130", 1040);
}
return 0;
}
tcp.c
//-------tcp相关头文件------
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h> //close()
static int socket_fd = 0;
//tcp_client_init()
//1、创建socket
//2、配置为客户端
//3、配置要连接的服务器ip和端口以及协议类型
//4、连接服务器
//5、收发数据
//6、关闭连接
int tcp_client_init(char *ip, int port)
{
int ret;
//1 2
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if(socket_fd == -1)
{
printf("create socket fail\n");
return -1;
}
//3
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;//IPv4协议
servaddr.sin_port = htons(port);//服务器端口号
servaddr.sin_addr.s_addr = inet_addr(ip);//设置服务器
//4
ret = connect(socket_fd, &servaddr, sizeof(servaddr));
if(ret == -1)
{
printf("connect %s fail\n", ip);
close(socket_fd);
return -1;
}
return 0;
}
//tcp_client_send()
int tcp_client_send(char *buff, int len)
{
write(socket_fd, buff, len);
}
//tcp_client_rcv()
int tcp_client_rcv(char *buff, int len)
{
int ret;
//ret = read(socket_fd, buff, 1024);
ret = recv(socket_fd, buff, len, MSG_DONTWAIT);
return ret;
}
//tcp_client_close()
int tcp_client_close()
{
close(socket_fd);
}
#define CLENT_NUM 2
struct sockaddr_in sSever_c_sd[CLENT_NUM];
static int socket_s_fd = 0;
static int socket_c_fd[CLENT_NUM] = {0};
//tcp_server_init()
#if 0
1、创建socket
2、设置本地ip和端口以及协议类型
3、绑定
4、监听
5、等待客户端连接
6、收发数据
7、关闭连接
#endif
int tcp_server_init(int port)
{
int ret;
//1
socket_s_fd = socket(AF_INET, SOCK_STREAM, 0);
if(socket_s_fd == -1)
{
printf("create socket fail\n");
return -1;
}
else
{
printf("create socket ok\n");
}
//2
struct sockaddr_in local_addr,c_addr;
local_addr.sin_family = AF_INET;//IPv4协议
local_addr.sin_port = htons(port);//服务器端口号
local_addr.sin_addr.s_addr = INADDR_ANY;//设置服务器ip
//3
ret = bind(socket_s_fd, &local_addr, sizeof(local_addr));
if(ret == -1)
{
printf("bind fail\n");
close(socket_s_fd);
return -1;
}
else
{
printf("bind ok\n");
}
//4
ret = listen(socket_s_fd, 3);
if(ret == -1)
{
printf("listen fail\n");
close(socket_s_fd);
return -1;
}
else
{
printf("listen ok\n");
}
//5
socklen_t addrlen = 0;
while(1)
{
printf("wait client conect\n");
socket_c_fd[0] = accept(socket_s_fd, &c_addr, &addrlen);
if(addrlen != 0)
break;
sleep(1);
}
printf("client conect\n");
return 0;
}
//tcp_server_send()
int tcp_server_send(char c, char *buff, int len)
{
write(socket_c_fd[c], buff, len);
}
//tcp_server_rcv()
int tcp_server_rcv(char c, char *buff, int len)
{
int ret;
ret = read(socket_c_fd[c], buff, len);
return ret;
}
//tcp_server_close()
int tcp_server_close()
{
close(socket_s_fd);
}
tcp.h
#ifndef __TCP_H
#define __TCP_H
int tcp_client_init(char *ip, int port);
int tcp_client_send(unsigned char *buff, int len);
int tcp_client_rcv(unsigned char *buff, int len);
int tcp_client_close();
int tcp_server_init( int port);
int tcp_server_send(char c, unsigned char *buff, int len);
int tcp_server_rcv(char c, unsigned char *buff, int len);
int tcp_server_close();
#endif
编译脚本,大家要把运行后面的程序名字和ip端口自己改一下
gcc *.c -o netupdatesend -w
./netupdatesend test 192.168.136.130 1030
运行设备端tcp服务```
执行,发送端
结果