相关文章
1、移远 EC20 模组(4G通信模组)AT指令测试 TCP 通信过程----https://blog.csdn.net/Mculover666/article/details/105877183?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight
我们公司和移远有合作所以得到了他们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