shiro

关于树莓派的蓝牙连接调试
今天花了几乎一半的时间用来尝试用完全用C语言控制树莓派的蓝牙,但是这部分的内容网上少之又少,没办法直到后来才采用其...
扫描右侧二维码阅读全文
15
2018/07

关于树莓派的蓝牙连接调试

今天花了几乎一半的时间用来尝试用完全用C语言控制树莓派的蓝牙,但是这部分的内容网上少之又少,没办法直到后来才采用其他的方法进行尝试。还未整合。最后采用SHELL+C语言的方法,还是得益于linux的强大.

主要参考链接:
https://blog.csdn.net/wanyeye/article/details/52909869
https://blog.csdn.net/Lynn_Y_Lin/article/details/80381922
https://blog.csdn.net/qq_25005909/article/details/77512903
https://wiki.archlinux.org/index.php?title=Bluetooth_headset_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)&oldid=396723
在树莓派中提供了一个内置的蓝牙模块
可以通过

sudo apt-get install bluez
//如果库不多的话
sudo apt-get install pi-bluetooth bluez bluez-firmware blueman

最终我这里采用的蓝牙的BlueTooth SPP。

首先先设置好SPP

sudo vi /etc/systemd/system/dbus-org.bluez.service

hciconfig可以查看当前的蓝牙服务
sudo sdptool browse local可以查看适配器提供的服务

通过在shell内输入sudo bluetoothctl
进入蓝牙模块内,可以使用以下几条命令

>
scan on扫描
power on 打开电源
pair MAC地址 配对
agent on 打开代理
devices 获取已配对的设备MAC地址
trust MAC地址 无PIN设备可能需要人工再次认证
connect 连接已配对的蓝牙设备

在这里只需要配对就可以了

sudo rfcomm watch hci0或者sudo rfcomm watch hci0&区别就是在于后面这个程序是后台程序,可以一直执行。
不过在这里要注意,这个在建立蓝牙连接后会在/etc内产生一个文件rfcomm0,这里就是将蓝牙设备转化为一个设备文件进行访问,这个文件也是我们最终需要的东西。在使用这个命令之前,请先将这个任务关闭,否则你将会遇到这个错误。
Can't bind RFCOMM socket: Address already in use
原理基本上是这样,其他的细节将会在代码中体现,我在写代码的时候同时加入了,shell指令,这个指令通过system("string");实现,这个string可以用shell指令代替,其主要原理通过该命令fork()出一个子进程完成的,串口通信可以在手机尚在一个蓝牙调试助手,树莓派上可以使用minicom进行调试,详细方法可以查询网上。

如果使用了sudo rfcomm watch hci0&后并没有中止该程序,可以采用三种方法杀死进程:
1. fg 1 再通过ctrl+c中止该程序。
2. kill 进程ID 这个进程ID可以通过创建该进程时,shell返回的信息中找到,可以查找临时文件中的数据。一种比较的好的方法是通过$!得到上一个后台进程的ID,再通过echo写入文件中,之后就可以读取删除程序即可。
3. sudo pkill -f rfcomm 直接删除相关进程

//system源代码
int system(const char * cmdstring)
{
    pid_t pid;
    int status;

if(cmdstring == NULL)
{
    return (1); //如果cmdstring为空,返回非零值,一般为1
}

if((pid = fork())<0)
{
    status = -1; //fork失败,返回-1
}
else if(pid == 0)
{
    execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
    _exit(127); // exec执行失败返回127,注意exec只在失败时才返回现在的进程,成功的话现在的进程就不存在啦~~
}
else //父进程
{
    while(waitpid(pid, &status, 0) < 0)
    {
        if(errno != EINTR)
        {
            status = -1; //如果waitpid被信号中断,则返回-1
            break;
        }
    }
}

    return status; //如果waitpid成功,则返回子进程的返回状态
}

以下是未整合的代码

//C语言版探测何输出可用蓝牙设备,一个例程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>

int main(int argc, char **argv)
{
    inquiry_info *ii = NULL;
    int max_rsp, num_rsp;
    int dev_id, sock, len, flags;
    int i;
    char addr[19] = {0};
    char name[248] = {0};

    dev_id = hci_get_route(NULL);
    sock = hci_open_dev(dev_id);
    if (dev_id < 0 || sock < 0) {
        perror("opening socket");
        exit(1);
    }

    len = 8;
    max_rsp = 255;
    flags = IREQ_CACHE_FLUSH;
    ii = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info));

    num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &ii, flags);
    if( num_rsp < 0 ) perror("hci_inquiry");

    for (i = 0; i < num_rsp; i++) {
        ba2str(&(ii+i)->bdaddr, addr);
        memset(name, 0, sizeof(name));
        if (hci_read_remote_name(sock, &(ii+i)->bdaddr, sizeof(name), name, 0) < 0)
            strcpy(name, "[unknown]");
        printf("%s %s\n", addr, name);
    }

    free(ii);
    close(sock);

    return 0;
}

//C语言版蓝牙基于Socket实现读写的方法,不过这个demo 我没成功过
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>

int main(int argc, char **argv)
{
    struct sockaddr_rc addr = { 0 };
    int s, status, len = 0;
    char dest[18] = "B0:E2:35:A1:81:75";
    char buf[256];
    // allocate a socket
    s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);

    // set the connection parameters (who to connect to)
    addr.rc_family = AF_BLUETOOTH;
    addr.rc_channel = (uint8_t)1;
    str2ba(dest, &addr.rc_bdaddr);

    // connect to server
    status = connect(s, (struct sockaddr *)&addr, sizeof(addr));

    if(status){
        printf(" failed to connect the device!\n");
        return -1;
    }

    int i = 0;
    do{
        len = read(s, buf, sizeof(buf));
        printf("i = %d\n", ++i);
        if(len > 0) {
            buf[len]=0;
            printf("%s\n", buf);
            write(s, buf, strlen(buf));
        }
    }while(len > 0);

    close(s);
    return 0;
}

//将shell指令与C相结合的方法

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>


int main(){
    int fd = open("/dev/rfcomm0", O_RDWR | O_NOCTTY | O_NDELAY);
    int nByte = 0;
    if(fd < 0)
        return -1;
    struct termios options;
    tcgetattr(fd, &options);
    cfsetispeed(&options, B9600);
    cfsetospeed(&options, B9600);
    options.c_lflag &= ~(ICANON | ECHO | ECHOE);
    options.c_oflag &= ~OPOST;

    char data1[1024] = "";
    char data2[1024] = "Hello, world";
    pid_t pid;

    while((pid = fork()) == -1);
    if(pid == 0) {
        nByte = write(fd, data2, sizeof(data2));
    }
    else{
        do {
            read(fd, data1, 1024);
            printf("%s", data1);
        }while(strlen(data1) == 0);
    }

    close(fd);
    return 0;
}

//待完善
#include "bluetooth.h"


void scan_on(){
    printf("扫描服务开启\n");
    inquiry_info *ii = NULL;
    int max_rsp, num_rsp;
    int dev_id, sock, len, flags;
    int i;
    char addr[19] = {0};
    char name[248] = {0};

    dev_id = hci_get_route(NULL);
    sock = hci_open_dev(dev_id);
    if (dev_id < 0 || sock < 0) {
        perror("opening socket");
        exit(1);
    }

    len = 8;
    max_rsp = 255;
    flags = IREQ_CACHE_FLUSH;
    ii = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info));

    num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &ii, flags);
    if(num_rsp < 0) perror("hci_inquiry");

    for (i = 0; i < num_rsp; i++) {
        ba2str(&(ii+i)->bdaddr, addr);
        memset(name, 0, sizeof(name));
        if (hci_read_remote_name(sock, &(ii+i)->bdaddr, sizeof(name), name, 0) < 0)
            strcpy(name, "[unknown]");
        printf("%s %s\n", addr, name);
    }

    strcpy(addr, name);

    free(ii);
    close(sock);
}


void conn(){
    system("sudo touch process.dlg");
    system("sudo chmod 0666 process.dlg");
    system("sudo rfcomm watch hci0&");
    system("sudo ps -ef|grep \"rfcomm watch hci0\" > process.dlg");
    printf("蓝牙已连接\n");
}

void disconn(){
    system("sudo pkill -f rfcomm");
    printf("蓝牙断开\n");
}

void post(){
    int fd = open("/dev/rfcomm0", O_RDWR | O_NOCTTY | O_NDELAY);
    int nByte = 0;
    if(fd < 0)
        exit(-1);
    struct termios options;
    tcgetattr(fd, &options);
    cfsetispeed(&options, B9600);
    cfsetospeed(&options, B9600);
    options.c_lflag &= ~(ICANON | ECHO | ECHOE);
    options.c_oflag &= ~OPOST;

    char sen[1024] = "";

    nByte = write(fd, sen, 1024);

    close(fd);
}

void receive(){
    int fd = open("/dev/rfcomm0", O_RDWR | O_NOCTTY | O_NDELAY);
    int nByte = 0;
    if(fd < 0)
        exit(-1);
    struct termios options;
    tcgetattr(fd, &options);
    cfsetispeed(&options, B9600);
    cfsetospeed(&options, B9600);
    options.c_lflag &= ~(ICANON | ECHO | ECHOE);
    options.c_oflag &= ~OPOST;

    char rec[1024] = "";

    do {
        read(fd, rec, 1024);
        printf("%s", rec);
        strcpy(rv, rec);
    }while(strlen(rec) == 0);

    close(fd);
}


Last modification:August 27th, 2018 at 02:38 pm
If you think my article is useful to you, please feel free to appreciate

Leave a Comment