串行接口通过UDP套接字在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 socketn");
        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 %dn", 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]= '';

        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)。所以我知道硬件可以工作。当涉及到串行接口时,我错过了什么。如何去完成这样的任务呢?

你在评论中说过/问过

我基本上试图发送以下内容:0xff 0xaa 0x1b 0x000x00一次一个字节。你认为NULL(字节的零)是造成这个问题?如果是,我该如何指示缓冲区的结束不用它?

然而,在你的代码中,你在每个数据字节之间发送了一个NULL字节。temp_buf包含2个字节,将第二个字节硬编码为,并将第一个字节设置为数据字节。然后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字节的流。你的陀螺仪必须有某种协议,应该在它的文档中描述。根据我的经验,这是一个固定的消息长度,一个"神奇"字节的开始/结束序列,甚至是一个应用程序定义的报头。在你的评论中,你指出陀螺仪一次只需要一个字节,所以你去吧,每次只发送一个字节!我想象您将代码更改为如下内容:

// 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(或类似的)来查看你发送的内容,它非常有用!

saveConfig是二进制数据,但您需要发送十六进制表示,因此:

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);

最新更新