C中通过UDP套接字的串行接口
Serial interface via UDP sockets in C
我是串行接口的新手,我的公司要求我设计一个 API 来配置陀螺仪 - 连接到 WIFI 芯片 - 使用 C 代码,通过 UDP 套接字发送十六进制命令到WIFI芯片。我确保遵守制造商手册提供的格式,但似乎在串行接口方面我遗漏了一些东西。我正在使用此代码来执行此操作:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "port.h"
#include <time.h>
void waitFor (unsigned int );
unsigned char head1 = 0xff; //head
unsigned char head2 = 0xaa; //head2
unsigned char saveadd = 0x00; //saveconfig address
unsigned char savevalue = 0x00; //save config 0x01 is factory reset
unsigned char endd = 0x00; //end
int
main(int argc, char **argv)
{
struct sockaddr_in myaddr; /* our address */
struct sockaddr_in remaddr; /* remote address */
remaddr.sin_addr.s_addr = inet_addr("192.168.1.1");
remaddr.sin_port = htons(8889);
socklen_t addrlen = sizeof(remaddr); /* length of addresses */
int recvlen; /* # bytes received */
int fd; /* our socket */
int msgcnt = 0; /* count # of messages we received */
remaddr.sin_family = AF_INET;
/* create a UDP socket */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("cannot create socket\n");
return 0;
}
/* bind the socket to any valid IP address and a specific port */
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(SERVICE_PORT);
if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
perror("bind failed");
return 0;
}
printf("waiting on port %d\n", SERVICE_PORT);
// Hex command that turns a builtin LED on
unsigned char comPart1 = 0xFF;
unsigned char comPart2 = 0xAA;
unsigned char comPart3 = 0x1b;
unsigned char comPart4 = 0x00;
unsigned char comPart5 = 0x00;
unsigned char commands [5]; /* unsigned char array to hold command */
commands [0] = comPart1;
commands [1] = comPart2;
commands [2] = comPart3;
commands [3] = comPart4;
commands [4] = comPart5;
unsigned char temp_buf [2]; /*buffer used to send hex command*/
temp_buf [0]= (unsigned char) 0x00;
temp_buf [1]= '[=10=]';
for (int i = 0; i < 5 ; i++)
{
temp_buf [0] = commands[i];
if (sendto(fd, temp_buf, sizeof (temp_buf), 0, (struct sockaddr *)&remaddr, addrlen) < 0)
perror("sendto");
}
waitFor (0.5); /*delay specified by user manual*/
printf ("%s \n", "Now saving the configration");
//save commands as specified by user manual
unsigned char saveConfig [5];
saveConfig [0] = head1;
saveConfig [1] = head2;
saveConfig [2] = saveadd;
saveConfig [3] = savevalue;
saveConfig [4] = endd;
for (int i = 0; i < 5 ; i++)
{
temp_buf [0] = saveConfig [i];
if (sendto(fd, temp_buf, sizeof (temp_buf), 0, (struct sockaddr *)&remaddr, addrlen) < 0)
perror("sendto");
waitFor (0.05);
}
waitFor (0.45);
}
void waitFor (unsigned int secs) {
unsigned int retTime = time(0) + secs; // Get finishing time.
while (time(0) < retTime); // Loop until it arrives.
}
我能够使用 CuteCom 串行配置陀螺仪(如果断开与 WIFI 芯片的连接并连接到 USB-TTL) .所以我知道硬件可以工作。当谈到串行接口时,我错过了什么。如何完成这样的任务?
saveConfig
是二进制数据,但您需要发送 hex 表示形式,因此:
temp_buf [0] = saveConfig [i]
不会工作。
你需要的是:
unsigned int
gethex(unsigned int val,int shf)
{
val >>= shf;
val &= 0x0F;
val = "0123456789ABCDEF"[val];
return val;
}
temp_buf[0] = gethex(saveConfig[i],4);
temp_buf[1] = gethex(saveConfig[i],0);
你said/asked在评论
I am essentially trying to send the following: 0xff 0xaa 0x1b 0x00
0x00 one byte at a time. Do you think the NULL (byte of zeros) are
causing the issue? How would I indicate the end of the buffer if I am
not to use it?
但是,从您的代码中,您发送了一个 NULL 字节 in-between 每个数据字节。 temp_buf
包含 2 个字节,你是 hard-coding 第二个字节到 [=12=]
并将第一个字节设置为数据字节。然后 sendto(fd, temp_buf, sizeof (temp_buf), 0, (struct sockaddr *)&remaddr, addrlen
行发送这个缓冲区的内容。如果您将网络流量困在 wireshark 中,您会看到您正在发送 0xff 0x00 0xaa 0x00 0x1b 0x00 0x00 0x00 0x00 0x00
而不是您打算发送的内容。
为了回答您的问题,c
除了字符串之外,缓冲区的 NULL 字节终止符没有任何通用之处。有效数据字节可以一直为 0x00。如果我通过电子邮件向某人发送一张黑色图片,我将发送整个 0x00 字节流。您的陀螺仪必须具有某种应在其文档中描述的协议。根据我的经验,这是一个固定的消息长度,start/end 字节的 "magic" 序列,甚至是 application-defined header。在你的评论中,你表示陀螺仪一次只需要一个字节,所以你去吧,一次只发送一个字节!我想您将代码更改为如下所示:
// really no need for temp_buf
for (int i = 0; i < 5 ; i++)
{
if (sendto(fd, &saveConfig[i] /* or saveConfig+i */, sizeof(char), 0, (struct sockaddr *)&remaddr, addrlen) < 0)
{
perror("sendto");
// I'm guessing from your indentation you want this wait inside the if-statement. Note that in the code you posted, the if-statement doesn't have any brackets so this will execute each time through the loop whether there is an error or not
waitFor (0.05);
}
waitFor (0.45);
}
一般来说,无论何时您处理此类网络问题,我都强烈建议您使用 wireshark(或等效工具)来准确查看您发送的内容,这非常有帮助!
我是串行接口的新手,我的公司要求我设计一个 API 来配置陀螺仪 - 连接到 WIFI 芯片 - 使用 C 代码,通过 UDP 套接字发送十六进制命令到WIFI芯片。我确保遵守制造商手册提供的格式,但似乎在串行接口方面我遗漏了一些东西。我正在使用此代码来执行此操作:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "port.h"
#include <time.h>
void waitFor (unsigned int );
unsigned char head1 = 0xff; //head
unsigned char head2 = 0xaa; //head2
unsigned char saveadd = 0x00; //saveconfig address
unsigned char savevalue = 0x00; //save config 0x01 is factory reset
unsigned char endd = 0x00; //end
int
main(int argc, char **argv)
{
struct sockaddr_in myaddr; /* our address */
struct sockaddr_in remaddr; /* remote address */
remaddr.sin_addr.s_addr = inet_addr("192.168.1.1");
remaddr.sin_port = htons(8889);
socklen_t addrlen = sizeof(remaddr); /* length of addresses */
int recvlen; /* # bytes received */
int fd; /* our socket */
int msgcnt = 0; /* count # of messages we received */
remaddr.sin_family = AF_INET;
/* create a UDP socket */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("cannot create socket\n");
return 0;
}
/* bind the socket to any valid IP address and a specific port */
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(SERVICE_PORT);
if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
perror("bind failed");
return 0;
}
printf("waiting on port %d\n", SERVICE_PORT);
// Hex command that turns a builtin LED on
unsigned char comPart1 = 0xFF;
unsigned char comPart2 = 0xAA;
unsigned char comPart3 = 0x1b;
unsigned char comPart4 = 0x00;
unsigned char comPart5 = 0x00;
unsigned char commands [5]; /* unsigned char array to hold command */
commands [0] = comPart1;
commands [1] = comPart2;
commands [2] = comPart3;
commands [3] = comPart4;
commands [4] = comPart5;
unsigned char temp_buf [2]; /*buffer used to send hex command*/
temp_buf [0]= (unsigned char) 0x00;
temp_buf [1]= '[=10=]';
for (int i = 0; i < 5 ; i++)
{
temp_buf [0] = commands[i];
if (sendto(fd, temp_buf, sizeof (temp_buf), 0, (struct sockaddr *)&remaddr, addrlen) < 0)
perror("sendto");
}
waitFor (0.5); /*delay specified by user manual*/
printf ("%s \n", "Now saving the configration");
//save commands as specified by user manual
unsigned char saveConfig [5];
saveConfig [0] = head1;
saveConfig [1] = head2;
saveConfig [2] = saveadd;
saveConfig [3] = savevalue;
saveConfig [4] = endd;
for (int i = 0; i < 5 ; i++)
{
temp_buf [0] = saveConfig [i];
if (sendto(fd, temp_buf, sizeof (temp_buf), 0, (struct sockaddr *)&remaddr, addrlen) < 0)
perror("sendto");
waitFor (0.05);
}
waitFor (0.45);
}
void waitFor (unsigned int secs) {
unsigned int retTime = time(0) + secs; // Get finishing time.
while (time(0) < retTime); // Loop until it arrives.
}
我能够使用 CuteCom 串行配置陀螺仪(如果断开与 WIFI 芯片的连接并连接到 USB-TTL) .所以我知道硬件可以工作。当谈到串行接口时,我错过了什么。如何完成这样的任务?
saveConfig
是二进制数据,但您需要发送 hex 表示形式,因此:
temp_buf [0] = saveConfig [i]
不会工作。
你需要的是:
unsigned int
gethex(unsigned int val,int shf)
{
val >>= shf;
val &= 0x0F;
val = "0123456789ABCDEF"[val];
return val;
}
temp_buf[0] = gethex(saveConfig[i],4);
temp_buf[1] = gethex(saveConfig[i],0);
你said/asked在评论
I am essentially trying to send the following: 0xff 0xaa 0x1b 0x00 0x00 one byte at a time. Do you think the NULL (byte of zeros) are causing the issue? How would I indicate the end of the buffer if I am not to use it?
但是,从您的代码中,您发送了一个 NULL 字节 in-between 每个数据字节。 temp_buf
包含 2 个字节,你是 hard-coding 第二个字节到 [=12=]
并将第一个字节设置为数据字节。然后 sendto(fd, temp_buf, sizeof (temp_buf), 0, (struct sockaddr *)&remaddr, addrlen
行发送这个缓冲区的内容。如果您将网络流量困在 wireshark 中,您会看到您正在发送 0xff 0x00 0xaa 0x00 0x1b 0x00 0x00 0x00 0x00 0x00
而不是您打算发送的内容。
为了回答您的问题,c
除了字符串之外,缓冲区的 NULL 字节终止符没有任何通用之处。有效数据字节可以一直为 0x00。如果我通过电子邮件向某人发送一张黑色图片,我将发送整个 0x00 字节流。您的陀螺仪必须具有某种应在其文档中描述的协议。根据我的经验,这是一个固定的消息长度,start/end 字节的 "magic" 序列,甚至是 application-defined header。在你的评论中,你表示陀螺仪一次只需要一个字节,所以你去吧,一次只发送一个字节!我想您将代码更改为如下所示:
// really no need for temp_buf
for (int i = 0; i < 5 ; i++)
{
if (sendto(fd, &saveConfig[i] /* or saveConfig+i */, sizeof(char), 0, (struct sockaddr *)&remaddr, addrlen) < 0)
{
perror("sendto");
// I'm guessing from your indentation you want this wait inside the if-statement. Note that in the code you posted, the if-statement doesn't have any brackets so this will execute each time through the loop whether there is an error or not
waitFor (0.05);
}
waitFor (0.45);
}
一般来说,无论何时您处理此类网络问题,我都强烈建议您使用 wireshark(或等效工具)来准确查看您发送的内容,这非常有帮助!