4G模块发送文件至云服务器

基于嵌入式Linux系统,通过4G模块发送文件至云服务器端

/*
    基于嵌入式linux系统,利用4G模块Quectel EC20,发送文件到云服务器下的FTP服务器中
*/
#include     <stdio.h>      
#include     <stdlib.h>    
#include     <unistd.h>    
#include     <sys/types.h> 
#include     <sys/stat.h>   
#include     <fcntl.h>     
#include     <termios.h>    
#include     <errno.h>
#include     <sys/select.h> 
#include     <stdint.h>
#include     <getopt.h>
#include     <signal.h>
#include     <string.h>
 
#define MAXLINE 32					                                     //一次读取最大的字节数,此处太大容易掉包,改为32;
#define lenToRead 1000                                                   //lenTORead不能太小
#define QUEC_AT_PORT "/dev/ttyUSB2"                                      //设备名
 
static int smd_fd = -1;

void delay(unsigned int xms);

void serial_init(int fd);                                                    //串口初始化函数声明

int Ql_SendAT(char* atCmd, char* finalRsp, long timeout_ms, int should_Add); //函数声明,AT指令发送函数

int main(int argc, char* argv[])                                             //主函数
{
	FILE* from_file;	    
	char  buf[MAXLINE]; 
	char  receive_buf[1000];
	int   read_len; 
 	char  str[10];
	char strsl[1000];
	int   rl_len;
	int rdlen2;
	printf("< Quectel OpenLinux: AT example >\n");                         
	
    smd_fd = open(QUEC_AT_PORT, O_RDWR | O_NONBLOCK | O_NOCTTY);	       //打开虚拟串口,设置成非阻塞,读写模式;其中第一个参数为要打开的设备或者文件,如果文件打开成功,返回文件的文件描述符

	//printf("< open(\"%s\")=%d >\n", QUEC_AT_PORT, smd_fd);               

	serial_init(smd_fd);                                                  //串口初始化
 
	Ql_SendAT("AT+QICSGP=1,1,\"CMNET\",\"\",\"\",1", "OK", 5500, 0);	  //配置PDP上下文(PDP Context),CMNET代表中国移动,若手机卡为联通的,则换成UNINET;
	                                                                      //当手机需要访问网络时,需要获取一个PDP地址,你可以把它看成移动的私网地址;PDP(分组报文协议简写)
		                 
    Ql_SendAT("AT+QIACT=1","OK",5500,0);                                  //激活PDP场景

	Ql_SendAT("AT+QFTPCFG=\"contextid\",1","OK",5500,0);                  //将PDP上的ID配置为1

	Ql_SendAT("AT+QFTPCFG=\"account\",\"uftp\",\"123456\"","OK",5500,0);  //设置用户名和密码,云服务器上FTP服务器的用户名uftp和密码123456

	Ql_SendAT("AT+QFTPCFG=\"filetype\",0","OK",5500,0);                   //设置传输数据类型

	Ql_SendAT("AT+QFTPCFG=\"transmode\",1","OK",5500,0);                  //被动模式,FTP服务器在端口上侦听数据连接

	Ql_SendAT("AT+QFTPCFG=\"rsptimeout\",90","OK",5500,0);                //设置响应超时值

	Ql_SendAT("AT+QFTPOPEN=\"106.15.74.16\",21","OK",7500,0);             //登录到FTP服务器,云服务器的IP为106.15.74.16

	Ql_SendAT("AT+QFTPCWD=\"/home/uftp\"","OK",7500,0);                   //设置当前目录,上传的文件存储到/home/uftp目录下
    
	if(((from_file)=open("/extp/Arm_can/can1.txt",O_RDWR))==NULL)	     //打开要读取的文件
	{
		printf("Can't open the file \n");
		exit(1);
	}

	printf("from_file=%d\n",from_file);                                    
 
	Ql_SendAT("AT+QFTPPUT=\"can1.txt\",\"COM:\",0", "CONNECT", 8000, 0);						
 

	 while((read_len = read(from_file, buf, MAXLINE))>0)                              //数据读取到buf中,MAXLINE为要读取的字节数;
		                                                                              //读取成功的话返回读取到的字节数;如果返回 0 表示读取到了文件末尾;如果返回负值,表示读取失败
	{

		// printf("read_len=%d\n",read_len);

         rl_len = write(smd_fd, buf, read_len);                                       //把文件写入ttyUSB2设备中

		// printf("rl_len=%d\n",rl_len);

		 bzero(buf, MAXLINE);

	}
	
	sleep(1);
	write(smd_fd,"+++",3);                                                          //退出数据传输模式,前后的sleep(1)很关键
	sleep(1);
	sleep(6);
	rdlen2 = read(smd_fd, strsl, lenToRead);
	//printf(">>Read response/urc, len=%d, content:\n%s\n", rdlen2, strsl);
	memset(strsl, 0, sizeof(strsl));
	//printf("read_len = %d\n", read_len);

	Ql_SendAT("AT+QIDEACT=1", "OK", 8500, 0);								           //关闭场景

	close(from_file);			                                                       //关闭文件
   	close(smd_fd);			                                                           //关闭虚拟串口
    printf("< Quectel OpenLinux: AT example end >\n\n");
	return 0;
}
 
 
int Ql_SendAT(char* atCmd, char* finalRsp, long timeout_ms, int should_Add)         //AT指令发送函数,should_Add是判断是否末尾要加入\r\n,如果不添加则还代表atCmd数据的长度
{
    int iRet;
    int iLen;
    fd_set fds;
    int rdLen;
    char strAT[1000];                                                        //存放AT指令
    char strFinalRsp[100];                                                   //存放写入的符号,例如”OK“
    char strResponse[1000];                                                  //存放串口收到的信息
    struct timeval timeout = {0, 0};
    int bRcvFinalRsp = 0;                                                    
 
    memset(strFinalRsp, 0, sizeof(strFinalRsp));
    sprintf(strFinalRsp, "%s", finalRsp);                                   //sprintf的作用是将一个格式化的字符串输出到一个目的字符串中,而printf是将一个格式化的字符串输出到屏幕。
                            
    
	timeout.tv_sec  = timeout_ms / 1000;
	timeout.tv_usec = timeout_ms % 1000;
    
    // Send AT
    if( should_Add != 0 )                                                   //如果末尾不需要回车换行
		    
	   {     delay(1000);
		    iRet = write(smd_fd, atCmd, should_Add);
		    delay(1000);
		   // printf("iLen = %d", should_Add);
	   }
	else
	   {
		    memset(strAT, 0, sizeof(strAT));                                  //初始化strAT[]的内存空间
    	    memset(strResponse, 0, sizeof(strResponse));                    
			iLen = sizeof(atCmd);
    		strncpy(strAT, atCmd, iLen);                                     //将字符串atCmd的前iLen个字符复制到数组strAT中
			iLen = strlen(atCmd);                                            //求字符串的长度
    		if ((atCmd[iLen-1] != '\r') && (atCmd[iLen-1] != '\n'))
    		   {
        		   iLen = sprintf(strAT, "%s\r\n", atCmd);                   //返回写入字符的总数,即strAT字符个数+2
        		   strAT[iLen] = '\0';                                       //相当于=0,是字符串的结尾标志
				   //printf("进入判断\n");
    		   }

		    iRet = write(smd_fd, strAT, iLen);                               //若成功,write函数返回写入的字节数;返回0表示没有写入任何数据;返回负数表示写入失败
		    delay(2000);
	    }
	
    printf(">>Send AT: \"%s\", iRet=%d\n", atCmd, iRet);                
    //printf("strAT:\"%s\", iLen=%d\n",strAT,iLen);                                       
    // Wait for the response
	while (1)
	{
		FD_ZERO(&fds);                                                     //清空集合,都设置为0
		FD_SET(smd_fd, &fds);                                              //将一个给定文件描述符加入集合之中

		memset(strAT, 0, sizeof(strAT));                                
    	memset(strResponse, 0, sizeof(strResponse));
 
		//printf("timeout.tv_sec=%d, timeout.tv_usec= %d \n", (int)timeout.tv_sec, (int)timeout.tv_usec);

		switch (select((smd_fd+1), &fds, NULL, NULL, &timeout))         // 函数原型int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

		//switch (select(smd_fd + 1, &fds, NULL, NULL, NULL))	       // block mode 
		{
		case -1: 
		       {
			    printf("< select error >\n");
			    return -1;
			   }
 
		case 0:
		      {
			   printf("< time out >\n");
			   return 1; 
			  }
 
		default:
		    
			  if (FD_ISSET(smd_fd, &fds))                                    //检查集合中指定的文件描述符是否可以读写
			    {
				  do {  
			            memset(strAT, 0, sizeof(strAT));                                
					    memset(strResponse, 0, sizeof(strResponse));     
					    rdLen = read(smd_fd, strResponse, lenToRead);       //strResponse存放串口收到的信息
					    printf(">>Read response/urc, len=%d, content:\n%s\n", rdLen, strResponse);  
					    //printf("rcv:%s", strResponse);
					    //printf("final rsp:%s", strFinalRsp);
					if ((rdLen > 0) && (strstr(strResponse, strFinalRsp)))    
					     {
					       if (strstr(strResponse, strFinalRsp)     // final OK response   在字符串strResponse中查找第一次出现字符串 strFinalRsp 的位置,不包含终止符 '\0'。若找到返回该位置,若没找到返回NULL。
					           || strstr(strResponse, "+CME ERROR:") // +CME ERROR
					           || strstr(strResponse, "+CMS ERROR:") // +CMS ERROR
					           || strstr(strResponse, "ERROR"))      // Unknown ERROR
					          {
					            printf("\n< match >\n");
					             bRcvFinalRsp = 1;
					          }
						  else
						      {
					          // printf("\n< not final rsp >\n");
					          }
					     }
				    } while((rdLen > 0) && (strstr(strResponse, strFinalRsp)));     //while ((rdLen > 0) && (lenToRead == rdLen)); 
					
					//printf("读到了传回的数据\n");
			    }
			 else
			    {
				printf("FD is missed\n");
			    }

			break;
			
		}
 
		// Found the final response , return back
		if (bRcvFinalRsp)
		{
			memset(strResponse, 0, sizeof(strResponse));
		    break;                                                //跳出while循环
		}	
   	}
   	return 0;
}


void serial_init(int fd)  //串口初始化函数
{   
    struct termios options;
    tcgetattr(fd, &options);
	//CLOCAL和CREAD分别用于本地连接和接受使能,
	//因此,首先要通过位掩码的方式激活这两个选项
    options.c_cflag |= ( CLOCAL | CREAD );
	
	//设置数据位为八位
    options.c_cflag &= ~CSIZE;
    options.c_cflag &= ~CRTSCTS;
    options.c_cflag |= CS8;
    options.c_cflag &= ~CSTOPB;
    options.c_iflag |= IGNPAR;
    options.c_oflag = 0;
    options.c_lflag = 0;
 
    cfsetispeed(&options, B9600);  //波特率设置
    cfsetospeed(&options, B9600);
    //cfsetispeed(&options, B115200);
    //cfsetospeed(&options, B115200);
    tcsetattr(fd,TCSANOW,&options);
 
 } 


void delay(unsigned int xms)  // 延时函数
{
    unsigned int x,y;

    for(x=xms;x>0;x--)
        for(y=110;y>0;y--);
}

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值