移远EC20二次开发之4G图像传输

  • Post author:
  • Post category:其他

       我们公司和移远有合作所以得到了他们EC20的二次开发的开发板。下面是我开发4G图像传输的总结(工作方式有两种,一种AT一种socket)。

     下面先是AT命令

      一.在linux下解压文件

              解压如下文件

           

      二.安装SDK

             每次开新的终端进行编译都要进行环境变量的设置

      三.进入历程

           

      四.修改历程

           

#include "ql_oe.h"
#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>

//those define was added by myself
#define MAXLINE 1024														//一次读取最大的字节数

#define QUEC_AT_PORT    "/dev/smd8"

static int smd_fd = -1;
int Ql_SendAT(char* atCmd, char* finalRsp, long timeout_ms, int should_Add);

int main(int argc, char* argv[])
{
	FILE                   *from_file;	//need send to server
	char                   buf[MAXLINE]; 
	char 		       receive_buf[100];
	int                    read_len; 
 	char		       str[10];
	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);

	Ql_SendAT("AT+COPS?", "OK", 1000, 0);									//检查网络

	if((from_file=open("timg.jpg",O_RDWR))==NULL)							//打开要读取的文件
	{
		printf("Can't open the file \n");
		exit(1);
	}

	Ql_SendAT("AT+QIOPEN=1,2,\"UDP SERVICE\",\"127.0.0.1\",0,3030,0", "OK", 1000, 0);	//建立UDP服务
	Ql_SendAT("AT+QISTATE=0,1", "OK", 1000, 0);										

	while ( (read_len = read(from_file, buf, MAXLINE)) > 0 )							//读取文件知道读完
	{

		printf("read_len = %d\n", read_len);								
		sprintf(str,"%d",read_len);														//将int型整数转为char型		

		sprintf(receive_buf, "AT+QISEND=2,%s,\"148.70.42.237\",3333", str);				//合成发送命令

		Ql_SendAT(receive_buf, "OK", 1000, 0);											//发送发送命令

		Ql_SendAT(buf, "SEND OK", 5000, read_len);										//添加发送的数据
		bzero(receive_buf, 100);														//清空数组
		bzero(buf, MAXLINE);
	}
	printf("read_len = %d\n", read_len);
	Ql_SendAT("AT+QICLOSE=2", "OK", 1000, 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)//should_Add是判断是否末尾要加入\r\n,如果不添加则还代表atCmd数据的长度
{
    int iRet;
    int iLen;
    fd_set fds;
    int rdLen;
#define lenToRead 100
    char strAT[100];
    char strFinalRsp[100];
    char strResponse[100];
    struct timeval timeout = {0, 0};
    boolean bRcvFinalRsp = FALSE;

    sprintf(strFinalRsp, "\r\n%s", finalRsp);
    
	timeout.tv_sec  = timeout_ms / 1000;
	timeout.tv_usec = timeout_ms % 1000;
    
    // Send AT
    if( should_Add != 0 )
	{
		iRet = write(smd_fd, atCmd, should_Add);
		printf("iLen = %d", should_Add);
	}
	else
	{
		memset(strAT, 0x0, sizeof(strAT));
    		iLen = sizeof(atCmd);
    		strncpy(strAT, atCmd, iLen);iLen = strlen(atCmd);
    		if ((atCmd[iLen-1] != '\r') && (atCmd[iLen-1] != '\n'))
    		{
        		iLen = sprintf(strAT, "%s\r\n", atCmd); 
        		strAT[iLen] = 0;
    		}
		iRet = write(smd_fd, strAT, iLen);
	}
    //printf(">>Send AT: \"%s\", iRet=%d\n", atCmd, iRet);
    
    // Wait for the response
	while (1)
	{
		FD_ZERO(&fds); 
		FD_SET(smd_fd, &fds); 

		//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))
		//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(strResponse, 0x0, sizeof(strResponse));
					rdLen = read(smd_fd, strResponse, lenToRead);
					//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
					       || strstr(strResponse, "+CME ERROR:") // +CME ERROR
					       || strstr(strResponse, "+CMS ERROR:") // +CMS ERROR
					       || strstr(strResponse, "ERROR"))      // Unknown ERROR
					    {
					        //printf("\n< match >\n");
					        bRcvFinalRsp = TRUE;
					    }else{
					        printf("\n< not final rsp >\n");
					    }
					}
				} while ((rdLen > 0) && (lenToRead == rdLen));
			}else{
				printf("FD is missed\n");
			}
			break;
		}

		// Found the final response , return back
		if (bRcvFinalRsp)
		{
		    break;
		}	
   	}
   	return 0;
}

    然后make编译   注意字符串格式获取长度少用strlen,因为0x00是字符串的结束符。如果发送二进制遇到0x13,0x10这些出问题可以修改串口的属性。

    五.进入开发板的linux系统

         

   六.上传文件

        使用Zmoden上传文件。注意移远给的系统只有usrdata是可写的。然后修改权限为可执行。

chmod 777 example_at

   七.运行程序

    

./example_at

 

  下面是socket程序,运行方法和上方一样

   先要拨号,不然无法socket运行起来,下面是拨号程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <getopt.h>
#include <unistd.h>
#include "ql_wwan_v2.h"

static void data_call_state_callback(ql_data_call_state_s *state)
{
	printf("profile id %d ", state->profile_idx);
	printf("IP family %s ", QL_DATA_CALL_TYPE_IPV4 == state->ip_family ? "v4" : "v6");
	if(QL_DATA_CALL_CONNECTED == state->state) {
		printf("is Connected\n");
		printf("Interface Name: %s\n", state->name);
		if(QL_DATA_CALL_TYPE_IPV4 == state->ip_family) {
			printf("IP address:          %s\n", inet_ntoa(state->v4.ip));
			printf("Gateway address:     %s\n", inet_ntoa(state->v4.gateway));
			printf("Primary DNS address: %s\n", inet_ntoa(state->v4.pri_dns));
			printf("Second DNS address:  %s\n", inet_ntoa(state->v4.sec_dns));
		} else {
			char ipv6_buffer[INET6_ADDRSTRLEN];
			inet_ntop(AF_INET6, (void *)&state->v6.ip, ipv6_buffer, INET6_ADDRSTRLEN);
			printf("IP address:          %s\n", ipv6_buffer);
			inet_ntop(AF_INET6, (void *)&state->v6.gateway, ipv6_buffer, INET6_ADDRSTRLEN);
			printf("Gateway address:     %s\n", ipv6_buffer);
			inet_ntop(AF_INET6, (void *)&state->v6.pri_dns, ipv6_buffer, INET6_ADDRSTRLEN);
			printf("Primary DNS address: %s\n", ipv6_buffer);
			inet_ntop(AF_INET6, (void *)&state->v6.sec_dns, ipv6_buffer, INET6_ADDRSTRLEN);
			printf("Second DNS address:  %s\n", ipv6_buffer);
		}
		printf("\n");
	} else {
		printf("is disconnected, and reason code 0x%x\n", state->err);
	}
}

int main(int argc, char **argv)
{
    int retry = 10;
    int loop;
    ql_data_call_s data_call[3];
    ql_data_call_info_s data_call_info;
    ql_data_call_error_e err = QL_DATA_CALL_ERROR_NONE;

    memset(&data_call, 0, sizeof(data_call));

    /*
     * The dialup API relies on the Quectel Manager service. If the program is not initialized successfully, 
     * debugging these API interfaces will fail, so here is judged whether the service is started normally.
     */
    while(0 != QL_Data_Call_Init_Precondition() && 0 != retry) {
        printf("The Quectel manager service is not initialized, about 500ms try again.\n");
        usleep(500*1000);
        retry--;
    }

    if(0 == retry) {
        printf("Data call failure\n");
        exit(0);
    }

    if(QL_Data_Call_Init(data_call_state_callback)) {
        printf("Initialization data call failure\n");
        exit(0);
    }

    for(loop = 0; loop < sizeof(data_call)/sizeof(data_call[0]); loop++) {
        memset(&data_call_info, 0, sizeof(data_call_info));
        err = QL_DATA_CALL_ERROR_NONE;
        data_call[loop].profile_idx = loop+1;
        /*
         * If your data call program is coredump, the data call status will not disappear automatically. 
         * When your program is start again, you need to call the QL_Data_Call_Info_Get interface to get 
         * the data call status. Because it is already in the data call state, you call QL_Data_Call_Start 
         * again without callback function
         */
        if(QL_Data_Call_Info_Get(data_call[loop].profile_idx, QL_DATA_CALL_TYPE_IPV4, &data_call_info, &err)) {
            printf("get profile index %d information failure: errno 0x%x\n", data_call[loop].profile_idx, err);
            continue;
        }
        if(QL_DATA_CALL_CONNECTED == data_call_info.v4.state) {
            printf("the profile index %d is already connected, don't up\n", data_call[loop].profile_idx);
            continue;
        }
        data_call[loop].ip_family = QL_DATA_CALL_TYPE_IPV4;
        data_call[loop].reconnect = true;
        err = QL_DATA_CALL_ERROR_NONE;
        if(QL_Data_Call_Start(&data_call[loop], &err)) {
            printf("the profile index %d start data call failure: 0x%x\n", data_call[loop].profile_idx, err);
            
        }
        printf("the profile index %d start data call success\n", data_call[loop].profile_idx);
        usleep(500*1000);
    }
    sleep(3600);
    return 0;
}

   然后soket传输图像

#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     <string.h>
#include     <netdb.h>
#include     <sys/socket.h>
#include     <sys/types.h>
#include     <arpa/inet.h>

#define SERVER_PORT 3333 
#define MAXLINE 1024 

int main(int argc,char **argv) 
{  
   //new add
   /*int retry = 10;
   int loop;
   ql_data_call_s data_call[3];
   ql_data_call_info_s data_call_info;
   ql_data_call_error_e err = QL_DATA_CALL_ERROR_NONE;

   memset(&data_call, 0, sizeof(data_call));*/

   int sockfd; 
   int read_len;
   FILE                   *from_file;	//need send to server
   char                   buf[MAXLINE]; 
   struct sockaddr_in cliaddr;
    
   bzero(&cliaddr, sizeof(cliaddr));
   cliaddr.sin_family = AF_INET;
   cliaddr.sin_port = htons(3333);
   cliaddr.sin_addr.s_addr = inet_addr("148.70.42.237");

   sockfd=socket(AF_INET,SOCK_DGRAM,0); 
   if(sockfd<0) 
   { 
        fprintf(stderr,"Socket Error:%s\n",strerror(errno)); 
        exit(1); 
   }

   if((from_file=open("timg.jpg",O_RDWR))==NULL)
   {
	printf("Can't open the file \n");
	exit(1);
   }

   while ( (read_len = read(from_file, buf, MAXLINE)) > 0 )
   {
	sendto(sockfd, buf ,read_len, 0 , (struct sockaddr*)&cliaddr, sizeof(cliaddr));
	bzero(buf, MAXLINE);
   }

   close(from_file);
   close(sockfd);
} 

 程序也是先运行拨号的再运行socket


版权声明:本文为qq_35570735原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。