OpenHD改造实现廉价高清数字图传(树莓派+PC)—(二)Wifibroadcast Wifi广播通信

2023-05-16

        上一篇文章重点介绍了数字图传的整体构建思路,以及主要的软件模块和最终效果。接下来几篇文章将针对其中的几个主要关键技术点进行阐述。一方面是为了将这些知识点做一个整理记录,方便后续查阅,另一方面也是将学习到知识点与大家分享,希望能够给他人有所启发。不恰当之处请在评论区批判指正。

一、wifibroadcast基本原理        

        本文主要是针对其中的通信相关技术。说到通信,在看OpenHD代码之前,我一直以为通信使用的是Wifi+TCP/IP这种方式,但实际上OpenHD并没有使用wifi和TCP/IP协议,使用wifi网卡也只是作为一个信道而已。

        核心原理就是在发送方采用Inject模式,以广播的方式直接发送802.11数据帧,在数据帧中包括了我们需要传输的数据;在接收方,使用monitor模式,接收数据帧并提取出其中的数据。        (这里有一个视频,讲Wifibroadcast的原理,How to convert standard wifi dongles into digital broadcast transmitters。media.ccc.de -Wifibroadcast 可以看一下)

        这里最关键的就是如何直接注入数据,这就要求网卡本身支持注入模式。这种传输方式的好处就是:无需进行WiFi连接,直接广播数据,避免建立连接带来的稳定性问题。因为空中飞行,由于各种因素影响,连接不是很稳定,可能出现短暂的断线或者失联,影响传输。如果是基于普通Wifi连接,一方面就要重新建立wifi连接才能通信,可能导致当前的画面会立刻中断;另一方面,即使上层的传输协议使用UDP这类无连接协议,但是在802.11协议中,链路层还是会有数据的回执,一旦链路层回执丢失,可能会在链路层发生重传,从而降低整体的传输效率,增加了延迟和抖动。

        所以,wifibroadcast技术使用的是wifi网卡的监听和注入来实现数据的发送,传输时无需建立wifi连接,类似于广播一样,将网卡当作无线电发送的前端,直接发送数据。接收端在收到数据后底层也无需确认,就算数据包丢失,由于发送端是持续发送数据,下一包数据到来后,画面也会能一直跟上,不会出现断线的情况。

二、数据注入和接收

        我们一般在编写网络程序时候,使用系统提供的socket函数进行编程,数据会根据我们选择的协议封装成TCP或者UDP格式交付给网络IP层发送。这应该都是比较熟悉的了,但是如何直接绕过传输层和网络层,而是直接与链路层打交道,封装出802.11协议的数据包进行发送呢?

        有两种方法可以实现直接跟链路层打交道,实现数据收发:一种是使用socket编程中的raw_socket接口;另一种,是使用libpcap库来收发数据

1、原始套接字接口(SOCK_RAW

        首先看一下socket()函数的定义

        #include <sys/socket.h>
        int socket(int domain, int type, int protocol);

        domain :指定通信协议族(protocol family/address)
        type:指定socket类型(type)
        protocol:指定具体协议

        一般我们做网络编程时都只关注要发送和接收的数据内容,也就是payload,不关注链路层、网络层、传输层的协议头,所以socket通过系统底层的协议栈已经帮我们填充了各层的协议头。但是,如果我们要直接发送网络层数据包或链路层数据帧时,就需要用到原始套接字了。它能够帮我们直接操作底层的协议头,从而实现跨层的数据直接发送和接收。

        Socket()函数主要提供了对L2和L3两种原始的套接字的处理,三个参数决定使用哪个层级的套接字接口。

  • L3 Socket 是Network Socket,网络层socket

        创建方式socket(AF_INET, SOCK_RAW, protocol),用于操作IP层的一些header,实现直接发送IP数据包。

  • L2 Socket 是Data-Link Socket,链路层socket

      创建方式socket(PF_PACKET, SOCK_RAW, protocol),用于处理链路层和网络层的header,实现直接发送链路层数据帧。

        所以我们主要研究的是如何使用L2层的socket。使用SOCK_RAW的时候,用户可以直接向底层的驱动程序发送或接收没有任何处理的完整原始报文需要自己手动构建链路层的协议头。协议头的分析将在后面章节详细描述。

        创建完成socket之后,我们就可以操作发送数据了。

        首先需要使用bind()函数来绑定到具体的地址和网口上,进行数据的收发。这里主要用到的一个结构体是sockaddr_ll,这是一种多种物理层的通用地址结构体,具体格式如下。

struct sockaddr_ll{
    unsigned short sll_family; /* 总是 AF_PACKET */
    unsigned short sll_protocol; /* 物理层的协议 */
    int sll_ifindex; /* 接口号 */
    unsigned short sll_hatype; /* 报头类型 */
    unsigned char sll_pkttype; /* 分组类型 */
    unsigned char sll_halen; /* 地址长度 */
    unsigned char sll_addr[8]; /* 物理层地址 */
};
  • 这里有几个值需要设置为固定的几个参数
ll_addr.sll_family = AF_PACKET;

ll_addr.sll_protocol = 0;

ll_addr.sll_halen = ETH_ALEN;
  • 另外有2个需要通过ioctrl()来查询

        可以通过网卡的名称,例如wlan0来查询一个是网卡名称的index:

struct ifreq ifr;

strcpy(ifr.ifr_name, "wlan0");

ioctl(sockfd, SIOCGIFINDEX, &ifr);

sll.sll_ifindex = ifr.ifr_ifindex;

        一个是当前的物理地址:

struct ifreq ifr;

strcpy(ifr.ifr_name, "eth0");

ioctl(sockfd, SIOCGIFHWADDR, &ifr);

memcpy(ll_addr.sll_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
  • 调用bind()函数绑定到某个网卡和地址上
bind(sock, (struct sockaddr *)&ll_addr, sizeof(ll_addr))
  • 最后还要设置socket参数还有发送超时和缓冲区

        发送超时时间:

struct timeval timeout;

timeout.tv_sec = 0;

timeout.tv_usec = 8000;

setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout))

        发送缓冲区大小:

setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff));
  •         这些设置完成后,就可以正常使用write()函数直接向网卡写入数据了
write(sock, packet_transmit_buffer, plen)

        具体可以参考OpenHD的源代码(注意:本文使用的是OpenHD的V2.0.8版本,后面的文章都是基于这个版本),路径wifibroadcast-base/tx_rawsock.c,这里给出一个完整的打开原始套接字的代码。

static int open_sock(char *ifname) {
    struct sockaddr_ll ll_addr;
    struct ifreq ifr;

    sock = socket(AF_PACKET, SOCK_RAW, 0);
    if (sock == -1) {
        fprintf(stderr, "Error:\tSocket failed\n");
        
        exit(1);
    }

    ll_addr.sll_family = AF_PACKET;
    ll_addr.sll_protocol = 0;
    ll_addr.sll_halen = ETH_ALEN;

    strncpy(ifr.ifr_name, ifname, IFNAMSIZ);

    if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0) {
        fprintf(stderr, "Error:\tioctl(SIOCGIFINDEX) failed\n");

        exit(1);
    }

    ll_addr.sll_ifindex = ifr.ifr_ifindex;

    if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
        fprintf(stderr, "Error:\tioctl(SIOCGIFHWADDR) failed\n");

        exit(1);
    }

    memcpy(ll_addr.sll_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);

    if (bind(sock, (struct sockaddr *)&ll_addr, sizeof(ll_addr)) == -1) {
        fprintf(stderr, "Error:\tbind failed\n");
        close(sock);

        exit(1);
    }

    if (sock == -1) {
        fprintf(stderr, "Error:\tCannot open socket\n"
                        "Info:\tMust be root with an 802.11 card with RFMON enabled\n");

        exit(1);
    }

    struct timeval timeout;
    timeout.tv_sec = 0;
    timeout.tv_usec = 8000;
    if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0) {
        fprintf(stderr, "setsockopt SO_SNDTIMEO\n");
    }

    int sendbuff = 131072;
    if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)) < 0) {
        fprintf(stderr, "setsockopt SO_SNDBUF\n");
    }


    return sock;
}

PS: 不知道为何OpenHD要把发送这部分代码使用rawsock去写,而接收使用pcap库来接收,难道的pcap在注入的时候有问题?但是EZ-WifiBroadcast、svpcom的wifibroadcast,以及原版的wifibroadcast用的都是pcap的pcap_inject()来发送数据。

2、libpcap接口

        这个库也可以操作相关注入功能,同时OpenHD接收数据就用的这个库。一句话就可以安装这个开发包。

sudo apt-get install  libpcap-dev

        主要分析一下数据的接收过程和步骤:

  • 先打开网卡
interface->ppcap = pcap_open_live(name, 2350, 0, -1, szErrbuf);
  • 设置为nonblock模式
pcap_setnonblock(interface->ppcap, 1, szErrbuf)
  • 设置方向为读取数据
pcap_setdirection(interface->ppcap, PCAP_D_IN)
  • 获取数据链路层的包格式,应该只能是DLT_IEEE802_11_RADIO
pcap_datalink(interface->ppcap);
  • 通过pcap_compile来构建编译过滤器参数
pcap_ sprintf(szProgram, "(ether[0x00:2] == 0x0801 || ether[0x00:2] == 0x0802 || ether[0x00:4] == 0xb4010000) && ether[0x04:1] == 0x%.2x", port_encoded);

pcap_compile(interface->ppcap, &bpfprogram, szProgram, 1, 0);
  • 通过pcap_setfilter设置过滤器
pcap_setfilter(interface->ppcap, &bpfprogram)
  • 在拿到fd,用于后续的select函数来进行判断选择是否有数据已具备状态待读取
interface->selectable_fd = pcap_get_selectable_fd(interface->ppcap);
  • 然后通过循环判断是否有数据已接收到
//通过select选择有数据准备读取的socketfd

select(30, &readset, NULL, NULL, &to);

//调用pcap_next_ex函数读取数据

pcap_next_ex(interface->ppcap, &ppcapPacketHeader, (const u_char **)&pu8Payload);

        如果不熟悉这个接口的,看起来还比较复杂,但是基本的思路和操作socket也还是类似的。

三、图传数据帧格式

        有了上面的两种方式就可以进行数据的注入(发送)和接收了。

        但是数据帧如何封装呢?主要是用802.11相关的数据帧直接封装图传数据。

802.11这个协议头可以参考相关的标准,有很详细的解释,本文就不再赘述。可参考文章:

802.11帧结构、wifi连接过程、加密方式_xinyuan0214的博客-CSDN博客

4. 802.11 Framing in Detail - 802.11 Wireless Networks: The Definitive Guide, 2nd Edition [Book]

        这里简要分析一下我们用到的帧头数据。802.11分为三种帧:管理帧、数据帧、控制帧,用framecontrol里面的type字段进行区分,802.11帧头格式如下。

static u8 u8aIeeeHeader_data[] = {
    0x08, 0x02, 0x00, 0x00, // frame control field (2bytes), duration (2 bytes)
    0xff, 0x00, 0x00, 0x00, 0x00, 0x00, // port = 1st byte of IEEE802.11 RA (mac) must be something odd (wifi hardware determines broadcast/multicast through odd/even check)
    0x13, 0x22, 0x33, 0x44, 0x55, 0x66, // mac
    0x13, 0x22, 0x33, 0x44, 0x55, 0x66, // mac
    0x00, 0x00  // IEEE802.11 seqnum, (will be overwritten later by Atheros firmware/wifi chip)
};

        要注意的是,在wifi的monitor模式下,网卡驱动将数据通过socket交付出来之前,还会在802.11帧前面添加包一个叫radiotap的额外帧头。这个帧头里面是一些信号强度、噪声强度、信道、时间戳等内容,这个额外的头是不上信道发送的。在收到数据帧时候,内核内部添加上去这个头,再交给上层应用,主要是留给向wireshark这样的抓包软件来获取信道信息用的;在发送数据帧时,如果不加这个头,内核可能会认为这是一个错误的数据帧,就会直接丢弃了,导致不能发送。因此需要手动添加这个额外的帧头,但这个帧头前面说了,是不上信道发送的,在驱动程序中被剥离掉。radiotap的格式如下。

static u8 u8aRadiotapHeader[] = {
    0x00, 0x00,             // <-- radiotap version
    0x0c, 0x00,             // <- radiotap header length
    0x04, 0x80, 0x00, 0x00, // <-- radiotap present flags (rate + tx flags)
    0x00,             // datarate (will be overwritten later in packet_header_init)
    0x00,                   // ??
    0x00, 0x00              // ??
};

        帧头数据初始化的时候,主要将802.11帧头里面的mac地址type填一下,以及radiotap帧头里面的rate填一下。MAC地址根据指定的端口来设置,这个端口不是什么udp/tcp端口,就是自己定义的一种区分不同应用或接收方的方式,主要影响mac地址的第一位;Type,默认就填写数据帧,我们图传发送的数据都是使用数据帧格式发送。 

关于不同应用(端口)的概念

        OpenHD中使用端口来区分不同的应用数据。注意这个端口不是UDP或者TCP的端口,是wifibroadcast自己定义的一种区分不同应用的方式。使用MAC地址的第一位来区分不同的端口(应用)。由于网卡认为奇数的MAC地址才是广播的地址,所以一共可以有128个不同的端口可以使用。看了代码,主要有以下几个端口。

  • 0端口:MAC地址01:22:33:44:55:66. tx_rawsock程序的默认端口,主要是用来传输视频流;
  • 1端口:MAC地址03:22:33:44:55:66. tx_telemetry程序的默认端口,主要用来传输飞机的mavlink遥测数据;
  • 63端口:MAC地址7F:22:33:44:55:66. Rssitx程序的默认端口,主要用来传输RSSI信号数据,用来接收对端发送的信号强度数据,用于显示信号强度。

        目前看到的代码主要就是这些,可能还有别的端口,回头再研究研究。

四、前向纠错和数据加密

        1、前向纠错

        针对出现错误数据的情况,wifibroadcast还使用了FEC(Forward Error Correction)前向纠错机制。当传输中出现错误,将允许接收端利用冗余数据再建数据包。默认应该是每8包数据多4包冗余数据,确保可靠。(This means that FEC block size is 12 packets and up to 4 (12 - 8) can be recovered if lost)。

        另外,在接收方还可以使用多个网卡同时接收数据,这样增加了接收到正确数据的概率。

        2、数据加密

        由于这是广播机制,也没有使用wifi建立任何连接,所以只要有一个网卡就可以直接接收到广播的数据,因此如果信息比较敏感就必须使用加密了。

        Wifibroadcast原版项目中使用了数据的加密,基于libsodium库。

        发送端会生成一个session key,加上packet index作为随机数,两个数一起作为密钥对发送的数据进行加密。发送端默认每1秒钟更新发送一次session key,key本身使用不对称密钥的公钥进行加密,接收端接收到之后进行解密和更新key,然后再用可以对数据包进行解密。在编译的时候,会生成一个wfb_keygen软件,用来生成gs.key和drone.key,分别给地面站和飞机使用。

        但是在OpenHD中,貌似没有使用加密,数据都是透明的发送的也就是,其他人如果知道你的频率,可以直接通过监听获取你的视频,所以这个要注意。

五、wifibroadcast的几个版本

        wifibroadcast 是一个单独的项目,有好几个版。

  • wifibroadcast原版

        Wifibroadcast FPV manual setup | befinitiv,befinitiv 有一个简单单位wifibroadcast开源项目,只要安装了pcap就能编译通过了。

  • wifibroadcast 改造版(PX4官方网站上提到的)

        svpcom/wifibroadcast     https://github.com/svpcom/wifibroadcast

        https://docs.px4.io/master/en/tutorials/video_streaming_wifi_broadcast.html (px4 官方网站的说明 )

        这个作者把原版的wifibroadcast做了改进,PX4的官方网站上说到的就是这个版本。
        原版的wifibroadcast使用的是固定长度的packet(1024 by default),在这版本中改成了可变的长度,只要小于1466,例如 x264 inside RTP or Mavlink.
        通过UDP作为数据源,1:1的将数据包写到radio packet中。作者说,可以很好的利用FEC前向纠错,而且延迟大大降低,特别针对视频。

Camera -> gstreamer --[RTP stream (UDP)]--> wfb_tx --//--[ RADIO ]--//--> wfb_rx --[RTP stream (UDP)]--> gstreamer --> Display

六、图传网卡

1、网卡芯片选择

        可以选择的网卡很多,但是好像基本上就是主要两种芯片解决方案:

  1. RTL8812au
  2. AR9271

        华硕的AC56 和AC56R网上说差别不大,而且可能AC56R还要好一些;另外,淘宝上也卖一些通用的RTL8812AU芯片的网卡,我就买了这个,很便宜。

        官网推荐在地面用两个网卡接收,保证效果。

We highly recommend at least 2 WiFi cards on the GroundPi. This will enable diversity and give you significant gains! The Pi3 can support 2-3 USB connections, and the Pi4 can support 4 or more.


2、频段选择

       在频段选择上,官方也是推荐5.8GHz频段,用的人少,干扰少。

3、网卡供电

       由于网卡耗电较大,可能直接接到树莓派上会带不动,所以PX4官方网站上说道,最好要将网卡单独供电,不要接Pi上的USB供电,所以要把usb线重新做一下。我画了个示意图,如下图所示。

        5V电源---------------------------------------+
       GND ----------------------------------+       | 
                                                          |       |
                  +5V      ------------X           |      +------------------       +5V
raspi USB  GND    -----------------------+-----------------------       GND      MicroUSB 网卡
                  D+       ------------------------------------------------       D+
                  D-        ------------------------------------------------       D-

        但是实际情况看,我直接接到数据派的USB口,似乎也没有什么问题,可以正常使用。

        但是为了安全起见,建议还是对网卡进行单独供电

4、网卡工作模式

  • 混杂模式,需要建立wifi连接,在有线和无线网卡上都支持这种模式,所有经过网卡的数据包都被提交给上层应用;
  • 监听模式,不需要建立wifi连接,只在无线网卡上有这个模式。  
#设置混杂模式
ifconfig wlan0 promisc  #设置混杂模式
ifconfig  wlan0  -promisc #取消混杂模式

#设置监听模式
ifconfig wlan1 down
iwconfig wlan1 mode monitor
ifconfig wlan1 up
iwconfig #可以查询当前网卡的模式
iwconfig wlan0 mode monitor #可以设置wlan0为监听模式
iwlist wlan0 channel #查看当前的信道
iwconfig wlan0 channel 11 #设置当前信道为11

        查询无线网卡的模式支持情况,我发现树莓派自带的无线网卡不支持监听模式(monitor)

iw list


Supported interface modes:
* IBSS
                 * managed
                 * AP
                 * P2P-client
                 * P2P-GO
                 * P2P-device

5、网卡驱动编译和安装

        网卡的驱动不能使用系统中自带的,需要打补丁

        从github上找到这个修改后驱动,地址:https://github.com/svpcom/rtl8812au
        基本上可以看说明跟着安装,这个说明基本上是比较靠谱的。

        要编译就要有linux header,在/lib/modules/ 下面有对应版本的头文件,但是没有build目录 /lib/modules/5.10.17-v7+/build 无法编译
        要先安装 sudo apt install raspberrypi-kernel-headers   
        然后建立一个软连接到这里,ln -s /usr/src/linux-headers-5.10.63-v7+ /lib/modules/5.10.17-v7+/build
        这样就能编译了。


        准备好之后,就可以进行安装了,重点就以下两个语句。

#编译,安装驱动
sudo make dkms_install  

#用来删除驱动
sudo make dkms_remove 

        问题:
        sudo apt-get install raspberrypi-kernel-headers只能安装最新的版本,可能与当前的操作系统的版本不一致。
        所以要手动下载deb包,https://archive.raspberrypi.org/debian/pool/main/r/raspberrypi-firmware/
        到这个网站找一下版本号。
        因为版本不太好找,所以要查一下对应的linux内核编译的时间,可以通过一下指令
        strings /boot/start.elf | grep VC_BUILD_ID
        然后找到对应的deb包,下载,sudo apt install ./XXXX.deb
        注意,要先把之前的raspberrypi-kernel-headers最好卸载掉
        安装时间比较长,主要是因为会把module下面的模块全部编译一遍。。。

6、关于网卡自动配网等功能禁用的问题

        必须要禁用自动配置功能,这样才能使用wifibroadcast相关功能。

        查看还有哪些后台服务用到了网卡(wlan1 替换成你的网卡名称)

ps uaxwwww | grep wlan1

(1)禁用 wpa服务

sudo systemctl disable wpa_supplicant

        这种比较直接,可以立竿见影。但是如果你还是需要使用自动登录wifi的话,可能导致无法使用另一个WiFi网卡了。

(2)指定网卡禁用配网服务

thank you very much @svpcom
the issue was with wpa_supplicant, i just disable it by having 'denyinterfaces wlan1' in /etc/dhcpcd.conf

        将denyinterfaces wlan1写到/etc/dhcpcd.conf,可以禁用wlan1。然后重启即可。这样可以保证另外一个网卡还可以使用。

        但是可能存在网卡加载顺序的问题,导致被禁用的网卡不一定是你想要的。

(3)修改网卡生成规则,确保网卡名称和mac地址对应

        修改 /etc/udev/rules.d/70-persistent-net.rules
        如果没有,就增加一个文件,内容如下:

#MAC 0c:91:60:0a:5a:b9 ====> PC用的WiFi网卡
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="0c:91:60:0a:5a:b9", ATTR{dev_id}=="0x0", ATTR{type}=="1", NAME="wlan1"       
#MAC 0c:91:60:0a:59:29 ====> 树莓派用的WiFi网卡
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="0c:91:60:0a:59:29", ATTR{dev_id}=="0x0", ATTR{type}=="1", NAME="wlan1"

        重启系统就可以了,确保插入的无线网卡是wlan1,并且只禁用wlan1自动配网功能。

七、wifibroadcast测试 

        可以用nc命令来测试

注意,一定要将networkmanager禁用,然后重启才行

// 1.先要把可能影响接收的应用都关闭掉
sudo airmon-ng check kill

// 2.在Netmanager的配置上,一定要将网卡添加到umanager里面
sudo vim /etc/Networkmanager/Networkmanager.conf
修改里面的网卡

1、发送端

sudo ./tx_my.sh wlan1

      

  tx_my.sh脚本内容如下。

#!/bin/bash

####
#"Usage: tx_rawsock [options] <interfaces>
#           Options:
#           -b <count>  Number of data packets in a block (default 8). Needs to match with rx.
#           -r <count>  Number of FEC packets per block (default 4). Needs to match with rx.
#           -f <bytes>  Number of bytes per packet (default %d, max. %d). This is also the FEC block size. Needs to match with rx.
#           -m <bytes>  Minimum number of bytes per frame (default: 28)
#           -p <port>   Port number 0-127 (default 0)
#           -t <type>   Frame type to send. 0 = DATA short, 1 = DATA standard, 2 = RTS
#           -d <rate>   Data rate to send frames with. Currently only supported with Ralink cards. Choose 6,12,18,24,36 Mbit
#           -y <mode>   Transmission mode. 0 = send on all interfaces, 1 = send only on interface with best RSSI
#           -z          Start measurement for auto bandwidth
#           -M          Use 802.11N MCS modes: 0,1,2,3
#           -S          Use STBC. Only for 802.11N\n  0\1
#           -L          Use LDPC. Only for 802.11n and 8812AU 0\1
#           Example:
#             cat /dev/zero | tx_rawsock -b 8 -r 4 -f 1024 -t 1 -d 24 -y 0 wlan0 (reads zeros from stdin and sends them out on wlan0) as standard DATA frames
####


WLAN=$1

BAND="5G"
#BAND="2G"

CHANNEL2G="6"
CHANNEL5G="149"

ifconfig $WLAN down
iw dev $WLAN set monitor otherbss
#iw reg set BO
ifconfig $WLAN up

case $BAND in
  "5G")
      echo "Setting $WLAN to channel $CHANNEL5G"
      iw dev $WLAN set channel $CHANNEL5G HT40+
      ;;
  "2G")
      echo "Setting $WLAN to channel $CHANNEL2G"
      iw dev $WLAN set channel $CHANNEL2G HT40+
      ;;
   *)
      echo "Select 2G or 5G band"
      exit -1;
      ;;
esac

# TX
sudo ./tx_rawsock -b 8 -r 4 -f 1024 -t 1 -d 24 -y 0 $WLAN

        程序会打开本地的5600端口,用来接收需要广播发送出去的数据。
        再开一个窗口,输入以下命令。      

nc -u 127.0.0.1 5600

        然后,可以通过键盘输入要发送的数据了。       

2、接收端

sudo ./rx_my.sh wlan1

   rx_my.sh脚本内容如下

#!/bin/bash

####
#           Usage: rx [options] <interfaces>
#           -p <port>   Port number 0-255 (default 0)
#           -b <count>  Number of data packets in a block (default 8). Needs to match with tx.
#           -r <count>  Number of FEC packets per block (default 4). Needs to match with tx.
#           -f <bytes>  Bytes per packet (default %d. max %d). This is also the FEC block size. Needs to match with tx
#           -d <blocks> Number of transmissions blocks that are buffered (default 1). This is needed in case of diversity if one
#                       adapter delivers data faster than the other. Note that this increases latency.
#           Example:
#             rx -b 8 -r 4 -f 1024 -t 1 wlan0 | cat /dev/null (receive standard DATA frames on wlan0 and send payload to /dev/null)

		   
		   

WLAN=$1

BAND="5G"
#BAND="2G"

CHANNEL2G="6"
CHANNEL5G="149"

ifconfig $WLAN down
iw dev $WLAN set monitor otherbss
#iw reg set BO
ifconfig $WLAN up

case $BAND in
  "5G")
      echo "Setting $WLAN to channel $CHANNEL5G"
      iw dev $WLAN set channel $CHANNEL5G HT40+
      ;;
  "2G")
      echo "Setting $WLAN to channel $CHANNEL2G"
      iw dev $WLAN set channel $CHANNEL2G HT40+
      ;;
   *)
      echo "Select 2G or 5G band"
      exit -1;
      ;;
esac

# TX
sudo ./rx -b 8 -r 4 -f 1024 $WLAN

        将接收到的wifi广播数据推送到本地的UDP 5600端口上
        再打开一个窗口,输入以下命令。

nc -ul 5600

        监听5600上接收到的数据并显示。

        如果再发送端输入字符串并回车,接收端能看到,说明wifi广播可以使用了。

此外还可以使用tcpdump来直接监控接收到的数据包:

对于wifibroadcast项目,地址变化在最后一位mac地址

sudo tcpdump  -i wlan1 wlan host 13:22:33:44:55:01

对于openhd项目,地址变化在第一位,其余为0

sudo tcpdump  -i wlan1 wlan host 01:00:00:00:00:00
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenHD改造实现廉价高清数字图传(树莓派+PC)—(二)Wifibroadcast Wifi广播通信 的相关文章

  • 房卡麻将分析之“代开房间”

    什么是代开房间 代开房间 xff0c 就是可以创建一个新的房间 xff0c 让其它玩家加入 为什么要做代开房间 xff08 1 xff09 可以帮助没有房卡的朋友开房 xff0c 提升未买卡玩家玩游戏的积级性 xff08 2 xff09 代
  • 信号量sem_wait()的使用

    闲来无事 xff0c 我给大家讲下UNIX Linux下信号量函数的使用 首先你得知道什么叫信号量 xff0c 什么时候要用信号量 这个嘛 xff0c 主要就是用来保护共享资源的 xff0c 也就是说如果你想限制某个 xff08 些 xff
  • 房卡麻将分析之“俱乐部功能”

    什么是俱乐部 群主 xff08 代理 xff09 创建俱乐部后 xff0c 可以邀请自已的群成员成为自已的俱乐部会员 xff0c 方便管理 俱乐部玩法由创始人设置 xff0c 只有俱乐部成员才能加入 xff0c 并且俱乐部房间全部消耗创始人
  • 红孩儿网狐Cocos经典棋牌开发教程-卞安-专题视频课程

    红孩儿网狐Cocos经典棋牌开发教程 4750人已学习 课程介绍 由知名Cocos技术讲师红孩儿讲解的基于网狐源码进行棋牌开发的系列教程 课程收益 1 快速理解掌握网狐棋牌的源码框架 2 能够学会使用网狐棋牌快速换皮产品 3 能够在网狐棋牌
  • STM32F407VET6 普通 IO 口模拟串口发送数据

    1 只实现了 xff0c 使用普通 IO 口模拟串口的发送 xff0c 没有实现接收 2 由于是模拟发送的是 TTL 电平 xff0c 所以在使用串口助手验证发送数据的准确性时 xff0c 应该使用 USB 转 TTL xff0c 而不能使
  • 虹科知识分享|关于阻塞函数和非阻塞函数

    在CAN和LIN相关的开发库里 xff0c 不可避免的会出现 收 和 发 的函数 如何快速有效的处理数据 xff0c 是开发中重要的事项 但实际上单路CAN由于波特率的限制 xff0c 数据量并不会很大 xff1a 以常用的500k为例 x
  • 车用技术总线 | 从应用角度了解下LIN总线

    注意 xff1a 本文约4850字 xff0c 完整阅读时间约13分钟 主要内容 LIN总线概述 LIN总线的应用 示例 xff1a LIN总线和CAN总线的窗户控制 LIN总线的信号报文 记录LIN总线数据 LIN总线数据记录应用案例 本
  • 工业通讯 | CAN基础内容详解(二)——物理层

    往期回顾 工业通讯 CAN基础内容详解 xff08 一 xff09 物理层主要完成设备间的信号传送 xff0c 把各种信号转换成物理信号 xff0c 并将这些信号传输到其他目标设备 在这一层中 xff0c CAN bus对信号电平 通信时使
  • 04ROS中的头文件与源文件

    ROS中的头文件与源文件 本节主要介绍ROS的C 43 43 实现中 xff0c 如何使用头文件与源文件的方式封装代码 xff0c 具体内容如下 设置头文件 xff0c 可执行文件作为源文件 xff1b 分别设置头文件 xff0c 源文件与
  • TX2系统安装

    手头新拿到块TX2 xff0c 从零开始搞 xff0c 特此记录以备后续查看 xff0d 2017 07 16 乐 参考官方网址 JetPack下载网址 准备刷机环境 下载JetPack L4T 3 1 linux x64 run pc环境
  • 单片机是嵌入式的子类

    1系统组成结构上的区别 xff08 1 xff09 单片机基本结构 单片机由运算器 控制器 存储器 输入输出设备构成 xff08 2 xff09 嵌入式系统成部分 嵌入式系统一般由嵌入式微处理器 外围硬件设备 嵌入式操作系统 特定的应用程序
  • STM32串口协议概念及结构体初始化详解+串口点灯+串口收发程序

    文章目录 一 串口通信协议简介1 RS232标准2 USB转串口3 原生的串口到串口 二 初始化结构体解1 USART初始化结构体2 同步时钟初始化结构体3 编程时需要用到的固件库函数 三 串口点灯代码实现1 USART C文件2 USAR
  • 无人机光流定位系列——(一)原理剖析

    这次参加深圳的高交会 xff0c 在qualcomm展区看到了多款mini无人机 xff0c 大家稍微细心一点就可以发现这些无人机都使用了一种叫光流定位的技术 xff0c 很多人可能都还不明白光流定位是个什么东西 xff0c 是如何进行定位
  • 现代控制理论2——状态空间分析法

    注 xff1a 本文是在MOOC平台上学习西北工业大学 现代控制理论基础 xff08 郭建国 赵斌 郭宗易 xff09 的课程进行随笔记录与整理 一 状态空间描述的相关概念 1 系统模型包括 xff1a 内部结构 xff0c 以及内部结构反
  • 输出调节——内模原理(1)

    浏览了百度和部分文献 xff08 主要为 xff1a 调节问题系统综述 xff0c 线性系统的内模原理 xff09 xff0c 在此尝试进行一些归纳 一 问题描述 输出调节问题 xff1a output regulation problem
  • RGB-D相机建图——2、openvins安装、测试与连接自己设备

    基础内容贴推荐 xff1a https zhuanlan zhihu com p 93814423 https blog csdn net weixin 39752599 article details 105906652 https zh
  • RGB-D相机建图——3、使用kalibr进行相机标定

    Kalibr 视觉惯性校准工具箱 官方网站 xff1a https github com ethz asl kalibr Kalibr是一个工具箱 xff0c 可以解决以下校准问题 xff1a 多摄像机校准 xff1a 具有非全局共享重叠视
  • 02.构建项目流程梳理及总结

    02 构建项目流程梳理及总结
  • Nuttx学习入门

    Nuttx学习 NuttX 是一个实时操作系统 RTOS xff0c 强调标准合规性和占用空间小 可从 8 位扩展到 64 位微控制器环境 xff0c NuttX 中的主要管理标准是 POSIX 和 ANSI 标准 NuttX 的主要环境依
  • 软件测试之如何介绍自己的项目

    测试人员在找工作的过程中 xff0c 通常有一个问题是很难绕开的 就是要如何向别人介绍自己之前做过的项目 要解决这个问题 xff0c 大致可以分为如下几个步骤 xff1a 1 对项目进行基本介绍 2 说明自己负责测试的模块 3 针对部分模块

随机推荐

  • FreeRTOS多任务管理

    文章目录 1 任务1 1 任务简介1 2 任务调度1 3 任务的状态 就绪态 运行态 阻塞态 挂起态 1 4 空闲任务 2 动态创建两个任务2 1 定义动态内存空间的堆2 2 定义任务函数2 3 定义 任务控制块 指针2 4 动态创建任务
  • 计算机类期刊投稿心得 [ 添加中...现35种 ]

    1 杂志名称 计算机应用研究 杂志文章包含专业 建模 xff0c 仿真 xff0c 网络 xff0c 人工智能 xff0c 比较杂 投稿联系方式 http www arocmag com 注册在线投稿审稿 投稿费用 250元 页 杂志级别
  • Minix下的汇编

    Minix下的汇编 大多数的编译器 xff0c 如Turbo C C 43 43 xff0c Borland C C 43 43 xff0c M C C 43 43 xff0c GCC xff0c VC 43 xff0c 编译过程都是 xf
  • 解决Xshell 7 报错 “要继续使用此程序,您必须应用最新的更新或使用新版本”

    1 先创建一个文本文档 xff0c 同时把该文档名称和后缀改为xshell7 bat xff1b 2 打开编辑这个xshell7 bat文件 xff0c 并且把以下文字复制进去 xff0c 注意set XSHELL 61 这一项需要改成你自
  • 多任务操作系统的任务切换

    在学习OS时 xff0c 对于多任务操作系统的任务切换 xff0c 一直不能理解 xff1a 控制权是怎么么回到调度程序上的 xff1f 记得在描述任务切换时 xff0c 一般都是这么描述的 xff1a 在每一个时钟滴答 xff0c 都将检
  • Minix下的汇编2

    似乎minix平台并没有带一个真正的汇编编译器 xff0c 看看makefile xff0c 几乎都是清一色的用cc来编译汇编代码的 而且 xff0c 即使是一个最简单功能的汇编程序 xff0c 也少不了一个 main 标签 在minix的
  • 原来在/var/spool/mail中

    fetchmail会把从mail server收到的邮件投递到 var spool mail 中去 而mutt也会自动地到 var spool mail里取信 xff0c 解码 xff0c 并显示 但 xff0c fetchmail的速度不
  • 汉字编码标准与识别(一)代码页(Code Page)初识

    BBS水木清华站 精华区 发信人 yanglc 魂归燕园 别理我 xff0c 烦着呢 信区 Linux 标 题 汉字编码标准与识别 一 发信站 BBS 水木清华站 Sat Apr 29 17 19 05 2000 http www linu
  • 让xpdf支持中文(C++primer中文版)

    首先到http www linuxfans org nuke modules php name 61 Site Downloads amp op 61 geninfo amp did 61 2385下载一个打了补丁的xpdf 安装 xff0
  • Xpdf-3 for MDK

    http www linuxfans org nuke modules php name 61 Site Downloads amp op 61 geninfo amp did 61 2385 Xpdf 3 for MDK 类别 其它软件
  • 不同公司的牛

    本文转自 C 43 43 Builder 研究 http www ccrun com other go asp i 61 264 amp d 61 sgz5id 传统公司 xff1a 你有两头母牛 你卖掉一头 xff0c 买了一头公牛 你的
  • 从词法分析开始

    刚开始时 xff0c 用lex的确是很方便 xff0c 但是这样却不能将词法分析的思想实践出来 最好的方法还是自己写一个lex 当然龙书上写得很详细了 xff0c 但是写得再详细 xff0c 把它实现出来还是很难的 我的计划是 xff1a
  • Python 获取当前路径几种方法

    Python 获取当前路径的几种方法 绝对路径 1 os path 方法 span class token comment coding utf 8 span span class token comment usr bin python
  • [pixhawk笔记]2-飞行模式

    本文翻译自px4官方开发文档 xff1a https dev px4 io en concept flight modes html xff0c 有不对之处 xff0c 敬请指正 pixhawk的飞行模式如下 xff1a MANUAL xf
  • 扩展卡尔曼滤波详解

    Extened Kalman Filter 简单介绍 卡尔曼滤波详解讲解的基本的卡尔曼滤波算法是通过一个线性随机差分方程来估计当前状态 xff0c 但是如果状态估计关系以及测量关系使非线性的怎么办 xff0c 而且在实际使用中大部分的问题都
  • 关于PX4中的高度若干问题

    飞行的高度是如何测量的 xff1f 地面的高度和海平面的高度差别很大 xff0c 飞控又是如何有效判别进行降落的 xff1f 这是我脑子里的疑问 搜索的一圈发现很少有人讨论这方面的问题 xff0c 于是本次我就直接看一下源代码 xff0c
  • 基于4G网卡和树莓派zero实现低延时数字图传(250-300ms左右)

    方案本身并不复杂 xff0c 都是采用成熟的产品 xff0c 只需要几个命令行就能解决问题 0 准备工作 硬件 xff1a 树莓派zero 4G网卡 linux台式机 笔记本 虚拟机 软件 xff1a raspivid netcat nc
  • 树莓派zero w 使用AV接口连接电视机

    树莓派zero本身板子上有一个mini HDMI xff0c 但是我看到好像板子上还有一个小接口 xff0c 上面写着TV xff0c 感觉应该可以输出AV信号 xff0c 于是网上搜索了一番 xff0c 果然可以 首先 xff0c 手工做
  • OpenHD改造实现廉价高清数字图传(树莓派+PC)—(一)概述

    一 缘由 数字图传网上有开源的解决方案 xff0c 最为出名的应该就是OpenHD了 如果按照官方网站的内容 xff0c 构建起来也不是很复杂 xff0c 直接可以烧录两个TF卡就能完成 但是 xff0c 你需要用到两个树莓派板卡 xff0
  • OpenHD改造实现廉价高清数字图传(树莓派+PC)—(二)Wifibroadcast Wifi广播通信

    上一篇文章重点介绍了数字图传的整体构建思路 xff0c 以及主要的软件模块和最终效果 接下来几篇文章将针对其中的几个主要关键技术点进行阐述 一方面是为了将这些知识点做一个整理记录 xff0c 方便后续查阅 xff0c 另一方面也是将学习到知