#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <ws2bth.h>
#include <BluetoothAPIs.h>
#ifdef __cplusplus
}
#endif
typedef PerlIO * InOutStream;
#define UUID_BASE_128 "00000000-0000-1000-8000-00805F9B34FB"
// Code from PyBlueZ
static void
ba2str( BTH_ADDR ba, char *addr )
{
int i;
unsigned char bytes[6];
for( i=0; i<6; i++ ) {
bytes[5-i] = (unsigned char) ((ba >> (i*8)) & 0xff);
}
sprintf(addr, "%02X:%02X:%02X:%02X:%02X:%02X",
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5] );
}
// Code from PyBlueZ
static int
str2uuid( const char *uuid_str, GUID *uuid )
{
// Parse uuid128 standard format: 12345678-9012-3456-7890-123456789012
int i;
char buf[20] = { 0 };
strncpy(buf, uuid_str, 8);
uuid->Data1 = strtoul( buf, NULL, 16 );
memset(buf, 0, sizeof(buf));
strncpy(buf, uuid_str+9, 4);
uuid->Data2 = (unsigned short) strtoul( buf, NULL, 16 );
memset(buf, 0, sizeof(buf));
strncpy(buf, uuid_str+14, 4);
uuid->Data3 = (unsigned short) strtoul( buf, NULL, 16 );
memset(buf, 0, sizeof(buf));
strncpy(buf, uuid_str+19, 4);
strncpy(buf+4, uuid_str+24, 12);
for( i=0; i<8; i++ ) {
char buf2[3] = { buf[2*i], buf[2*i+1], 0 };
uuid->Data4[i] = (unsigned char)strtoul( buf2, NULL, 16 );
}
return 0;
}
static int
build_uuid(GUID *uuid, char *service)
{
char service_buf[37];
if(service == NULL || strcmp(service, "0") == 0 || strlen(service) == 0) {
// Use public browse group
strcpy(service_buf, UUID_BASE_128);
service_buf[4] = '1';
service_buf[5] = '0';
service_buf[6] = '0';
service_buf[7] = '2';
str2uuid(service_buf, uuid);
}
// 128 bit
else if(strlen(service) == 36) {
if(service[8] != '-' || service[13] != '-' ||
service[18] != '-' || service[23] != '-' ) {
return(-1);
}
str2uuid(service, uuid);
}
// they left 0x on?
else if(strlen(service) == 6){
if(service[0] == '0' && service[1] == 'x' || service[1] == 'X') {
strcpy(service_buf, UUID_BASE_128);
service_buf[4] = service[2];
service_buf[5] = service[3];
service_buf[6] = service[4];
service_buf[7] = service[5];
str2uuid(service_buf, uuid);
}
else {
return(-1);
}
}
// 16 bit
else if(strlen(service) == 4) {
strcpy(service_buf, UUID_BASE_128);
service_buf[4] = service[0];
service_buf[5] = service[1];
service_buf[6] = service[2];
service_buf[7] = service[3];
str2uuid(service_buf, uuid);
}
else {
return(-1);
}
return(0);
}
MODULE = Net::Bluetooth PACKAGE = Net::Bluetooth
void
_init()
CODE:
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(2, 0);
if(WSAStartup(wVersionRequested, &wsaData) != 0) {
croak("Could not init Winsock!");
}
void
_deinit()
CODE:
WSACleanup();
InOutStream
_perlfh(fd)
int fd
CODE:
InOutStream fh = PerlIO_fdopen(fd, "r+");
RETVAL = fh;
OUTPUT:
RETVAL
void
_close(sock)
int sock
PPCODE:
closesocket(sock);
unsigned int
_use_service_handle()
CODE:
// We dont use the service handle on Windows
RETVAL = 0;
OUTPUT:
RETVAL
void
get_remote_devices()
PPCODE:
int done = 0;
int iRet;
int error;
DWORD flags = 0;
DWORD qs_len;
HANDLE hLookup;
char addr_buf[64];
WSAQUERYSET *qs;
BTH_ADDR result;
HV *return_hash = NULL;
qs_len = sizeof(WSAQUERYSET);
qs = (WSAQUERYSET*) malloc(qs_len);
ZeroMemory(qs, sizeof(WSAQUERYSET));
qs->dwSize = sizeof(WSAQUERYSET);
qs->dwNameSpace = NS_BTH;
qs->lpcsaBuffer = NULL;
flags |= LUP_FLUSHCACHE | LUP_RETURN_NAME | LUP_RETURN_ADDR | LUP_CONTAINERS;
iRet = WSALookupServiceBegin(qs, flags, &hLookup);
// return undef if error and empty hash if no devices found?
if(iRet == SOCKET_ERROR) {
error = WSAGetLastError();
if(error == WSASERVICE_NOT_FOUND) {
// No device
WSALookupServiceEnd(hLookup);
free(qs);
}
else {
free(qs);
}
}
else {
EXTEND(sp, 1);
while(! done) {
if(WSALookupServiceNext(hLookup, flags, &qs_len, qs) == NO_ERROR) {
result = ((SOCKADDR_BTH*)qs->lpcsaBuffer->RemoteAddr.lpSockaddr)->btAddr;
ba2str(result, addr_buf);
if(return_hash == NULL)
return_hash = newHV();
if(qs->lpszServiceInstanceName == NULL || strlen(qs->lpszServiceInstanceName) == 0) {
hv_store(return_hash, addr_buf, strlen(addr_buf), newSVpv("[unknown]", 0), 0);
}
else {
hv_store(return_hash, addr_buf, strlen(addr_buf), newSVpv(qs->lpszServiceInstanceName, 0), 0);
}
}
else {
error = WSAGetLastError();
if(error == WSAEFAULT) {
free(qs);
qs = (WSAQUERYSET*) malloc(qs_len);
ZeroMemory(qs, qs_len);
}
else if(error == WSA_E_NO_MORE) {
done = 1;
}
else {
done = 1;
}
}
}
// only return if has values
if(return_hash != NULL)
PUSHs(sv_2mortal(newRV_inc((SV*) return_hash)));
WSALookupServiceEnd(hLookup);
}
void
sdp_search(addr, service, name)
char *addr
char *service
char *name
PPCODE:
char *addrstr = NULL;
char *uuidstr = "0";
char localAddressBuf[32];
DWORD qs_len;
WSAQUERYSET *qs;
DWORD flags;
HANDLE h;
GUID uuid;
SOCKADDR_BTH sa;
int sa_len = sizeof(sa);
int local_fd = 0;
int done = 0;
int proto;
int port;
int error;
HV *return_hash = NULL;
EXTEND(sp, 1);
// this prolly doesnt need to be malloced
// inquiry data structure
qs_len = sizeof(WSAQUERYSET);
qs = (WSAQUERYSET*) malloc(qs_len);
flags = LUP_FLUSHCACHE | LUP_RETURN_ALL;
ZeroMemory(qs, qs_len);
qs->dwSize = sizeof(WSAQUERYSET);
qs->dwNameSpace = NS_BTH;
// ignored for queries?
qs->dwNumberOfCsAddrs = 0;
if(_stricmp(addr, "localhost") == 0 || _stricmp(addr, "local") == 0 ) {
memset(&sa, 0, sizeof(sa));
local_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
if(local_fd < 1) {
free(qs);
XSRETURN_UNDEF;
}
sa.addressFamily = AF_BTH;
sa.port = BT_PORT_ANY;
if(bind(local_fd,(LPSOCKADDR)&sa,sa_len) != NO_ERROR) {
free(qs);
close(local_fd);
XSRETURN_UNDEF;
}
if(getsockname(local_fd, (LPSOCKADDR)&sa, &sa_len) != NO_ERROR) {
free(qs);
close(local_fd);
XSRETURN_UNDEF;
}
ba2str(sa.btAddr, localAddressBuf);
qs->lpszContext = (LPSTR) localAddressBuf;
close(local_fd);
}
else {
qs->lpszContext = (LPSTR) addr;
}
memset(&uuid, 0, sizeof(uuid));
if(build_uuid(&uuid, service) != 0) {
free(qs);
XSRETURN_UNDEF;
}
qs->lpServiceClassId = &uuid;
if(WSALookupServiceBegin(qs, flags, &h) == SOCKET_ERROR) {
free(qs);
XSRETURN_UNDEF;
}
else {
// iterate through the inquiry results
while(! done) {
if(WSALookupServiceNext(h, flags, &qs_len, qs) == NO_ERROR) {
return_hash = newHV();
// If name is valid, then compare names.
if(name && strlen(name) > 0) {
if(qs->lpszServiceInstanceName && strlen(qs->lpszServiceInstanceName) > 0) {
if(_stricmp(name, qs->lpszServiceInstanceName) == 0) {
hv_store(return_hash, "SERVICE_NAME", strlen("SERVICE_NAME"),
newSVpv(qs->lpszServiceInstanceName, 0), 0);
}
else {
continue;
}
}
else {
continue;
}
}
else if(qs->lpszServiceInstanceName && strlen(qs->lpszServiceInstanceName) > 0) {
hv_store(return_hash, "SERVICE_NAME", strlen("SERVICE_NAME"), newSVpv(qs->lpszServiceInstanceName, 0), 0);
}
if(qs->lpszComment && strlen(qs->lpszComment) > 0) {
hv_store(return_hash, "SERVICE_DESC", strlen("SERVICE_DESC"), newSVpv(qs->lpszComment, 0), 0);
}
// set protocol and port
proto = qs->lpcsaBuffer->iProtocol;
port = ((SOCKADDR_BTH*)qs->lpcsaBuffer->RemoteAddr.lpSockaddr)->port;
if(proto == BTHPROTO_RFCOMM) {
if(port) {
hv_store(return_hash, "RFCOMM", strlen("RFCOMM"), newSViv(port), 0);
}
}
else if(proto == BTHPROTO_L2CAP) {
if(port) {
hv_store(return_hash, "L2CAP", strlen("L2CAP"), newSViv(port), 0);
}
}
else {
if(port) {
hv_store(return_hash, "UNKNOWN", strlen("UNKNOWN"), newSViv(port), 0);
}
}
// qs->lpBlob->pBlobData and qs->lpBlob->cbSize give access to the raw service records
PUSHs(sv_2mortal(newRV_inc((SV*) return_hash)));
}
else {
error = WSAGetLastError();
if(error == WSAEFAULT) {;
free(qs);
qs = (WSAQUERYSET*) malloc(qs_len);
}
else if(error == WSA_E_NO_MORE) {
done = 1;
}
else {
done = 1;
}
}
}
}
WSALookupServiceEnd(h);
free(qs);
void
_register_service(serverfd, proto, port, service_id, name, desc, advertise)
int serverfd
char *proto
int port
char *service_id
char *name
char *desc
int advertise
PPCODE:
WSAQUERYSET qs;
WSAESETSERVICEOP op;
SOCKADDR_BTH sa;
int sa_len = sizeof(sa);
char *service_name = NULL;
char *service_desc = NULL;
char *service_class_id_str = NULL;
CSADDR_INFO sockInfo;
GUID uuid;
EXTEND(sp, 1);
memset(&qs, 0, sizeof(qs));
memset(&sa, 0, sizeof(sa));
memset(&sockInfo, 0, sizeof(sockInfo));
memset(&uuid, 0, sizeof(uuid));
op = advertise ? RNRSERVICE_REGISTER : RNRSERVICE_DELETE;
if(getsockname(serverfd, (SOCKADDR*) &sa, &sa_len) == SOCKET_ERROR) {
PUSHs(sv_2mortal(newSViv(1)));
XSRETURN_IV(0);
}
if(build_uuid(&uuid, service_id) != 0) {
XSRETURN_IV(0);
}
sockInfo.iProtocol = BTHPROTO_RFCOMM;
sockInfo.iSocketType = SOCK_STREAM;
sockInfo.LocalAddr.lpSockaddr = (LPSOCKADDR) &sa;
sockInfo.LocalAddr.iSockaddrLength = sizeof(sa);
sockInfo.RemoteAddr.lpSockaddr = (LPSOCKADDR) &sa;
sockInfo.RemoteAddr.iSockaddrLength = sizeof(sa);
qs.dwSize = sizeof(qs);
qs.dwNameSpace = NS_BTH;
qs.lpcsaBuffer = &sockInfo;
qs.lpszServiceInstanceName = name;
qs.lpszComment = name;
qs.lpServiceClassId = (LPGUID) &uuid;
qs.dwNumberOfCsAddrs = 1;
if(WSASetService(&qs, op, 0) == SOCKET_ERROR) {
PUSHs(sv_2mortal(newSViv(0)));
}
else {
PUSHs(sv_2mortal(newSViv(1)));
}
int
_stop_service(sdp_addr)
unsigned int sdp_addr
CODE:
// don't do anything here since we don't use handles
RETVAL = 0;
OUTPUT:
RETVAL
int
_socket(proto)
char *proto
CODE:
if(_stricmp(proto, "RFCOMM") == 0) {
RETVAL = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
}
else if(_stricmp(proto, "L2CAP") == 0) {
RETVAL = socket(AF_BTH, SOCK_STREAM, BTHPROTO_L2CAP);
}
else {
RETVAL = -1;
}
OUTPUT:
RETVAL
int
_connect(fd, addr, port, proto)
int fd
char *addr
int port
char *proto
CODE:
SOCKADDR_BTH sa;
int sa_len = sizeof(sa);
memset(&sa, 0, sizeof(sa));
if(WSAStringToAddress(addr, AF_BTH, NULL, (LPSOCKADDR)&sa, &sa_len) == SOCKET_ERROR) {
RETVAL = -1;
}
else {
sa.addressFamily = AF_BTH;
sa.port = port;
RETVAL = connect(fd, (LPSOCKADDR)&sa, sizeof(sa));
}
OUTPUT:
RETVAL
int
_bind(fd, port, proto)
int fd
int port
char *proto
CODE:
int status;
SOCKADDR_BTH sa;
int sa_len;
sa_len = sizeof(sa);
memset(&sa, 0, sa_len);
sa.btAddr = 0;
sa.addressFamily = AF_BTH;
sa.port = port;
status = bind(fd, (LPSOCKADDR)&sa, sa_len);
if(status == NO_ERROR) {
RETVAL = 0;
}
else {
RETVAL = -1;
}
OUTPUT:
RETVAL
int
_listen(fd, backlog)
int fd
int backlog
CODE:
int status;
status = listen(fd, backlog);
if(status == NO_ERROR) {
RETVAL = 0;
}
else {
RETVAL = -1;
}
OUTPUT:
RETVAL
void
_accept(fd, proto)
int fd
char *proto
PPCODE:
int addr_len;
int res;
char addr[19];
SOCKADDR_BTH rcaddr;
EXTEND(sp, 2);
addr_len = sizeof(rcaddr);
res = accept(fd, (LPSOCKADDR)&rcaddr, &addr_len);
if(res != INVALID_SOCKET) {
PUSHs(sv_2mortal(newSViv(res)));
ba2str(rcaddr.btAddr, addr);
PUSHs(sv_2mortal(newSVpv(addr, 0)));
}
else {
PUSHs(sv_2mortal(newSViv(-1)));
}
void
_getpeername(fd, proto)
int fd
char *proto
PPCODE:
EXTEND(sp, 2);
// not implemented for Windows yet
PUSHs(sv_2mortal(newSVuv(0)));
PUSHs(sv_2mortal(newSVuv(0)));
分享到:
相关推荐
蓝牙通信基于蓝牙核心规范,其中包括一系列协议栈,从物理层到应用层,如射频(RF)通信、链路管理、逻辑链路控制与适应协议(L2CAP)、服务发现协议(SDP)等。 在C++中实现蓝牙通信,你需要选择一个合适的库或API...
蓝牙协议栈是一系列协议的集合,包括链路管理协议(LMP)、逻辑链路控制与适应协议(L2CAP)、服务发现协议(SDP)等,它们负责数据的编码、解码、路由和错误检测;应用程序则基于这些底层协议,实现具体的监控和通讯功能...
4. **设备连接**:`BluetoothConnect`函数用于建立与目标蓝牙设备的连接,可以是基于RFCOMM(串口模拟)或L2CAP(逻辑链路控制与适应协议)的连接。 5. **服务发现**:通过SDP服务发现协议,`...
在"使用Java蓝牙无线通讯技术API.pdf"这个文档中,应该包含了更详尽的教程和示例代码,帮助读者深入理解并实践Java蓝牙通信。通过学习和实践,开发者可以创建出能够在各种蓝牙设备之间进行数据交换的应用,如文件...
4. **蓝牙协议栈**:蓝牙通信基于一系列标准协议,包括基础射频层(Bluetooth Core Specification)、逻辑链路控制和适配器层(L2CAP)、服务发现协议(SDP)等。开发者需要理解这些协议以实现不同设备间的通信。 5...
下面将详细阐述蓝牙通讯的基本原理、蓝牙图片传输的过程以及可能涉及的关键技术。 蓝牙是一种短距离无线通信技术,它允许设备之间建立无线连接,进行数据交换和语音通信。蓝牙工作在2.4GHz的ISM频段,采用分时跳频...
此外,理解蓝牙协议栈也是重要的一步,它包括物理层(PHY)、链路层(L2CAP)、逻辑链路控制和适应协议(L2CAP)、服务发现协议(SDP)等层次。这些协议定义了如何编码、打包、传输和解码数据,以确保蓝牙设备之间的...
1. **蓝牙协议栈**:蓝牙通信依赖于蓝牙协议栈,它由多个层次组成,包括链路层(LL)、物理层(PHY)、主机控制接口(HCI)、逻辑链路控制和适配协议(L2CAP)、服务发现协议(SDP)等。在STM32中,我们通常不直接处理这些底层...
总结,基于ARM的蓝牙通讯协议设计涉及到硬件接口、驱动开发、协议栈实现、连接管理、数据传输、安全机制以及应用接口等多个方面。利用C++的强大功能,我们可以构建高效且可靠的无线通信系统,实现嵌入式芯片间的无线...
1. **蓝牙协议栈**:蓝牙通信基于蓝牙核心规范,包括蓝牙基本射频层(BLE或Classic)、链路管理层、主机控制器接口(HCI)、逻辑链路控制和适配协议(L2CAP)、服务发现协议(SDP)等层次。 2. **设备角色**:在蓝牙...
5. **数据传输**:蓝牙通信通常使用串行端口模拟(RFCOMM)或L2CAP(逻辑链路控制和适配协议)进行数据传输。程序中可能包含了打开串口、设置波特率、校验位等参数,以及发送和接收数据的函数。 6. **COM1口控制**...
描述中的"蓝牙通讯协议的集合,适合用于蓝牙通讯开发"进一步明确了这个库的用途,它是为开发蓝牙应用而设计的。蓝牙通信协议是确保不同蓝牙设备间有效、可靠通信的一系列标准和规范。这些协议定义了如何建立连接、...
Android提供了两种类型的蓝牙socket,即`RFCOMM`(串行端口协议)和`L2CAP`(逻辑链路控制与适应协议)。在大多数情况下,我们使用`RFCOMM`进行点对点通信。使用`BluetoothDevice`的`...
蓝牙无线通信基于蓝牙核心规格,包括物理层、链路层、主机控制接口(HCI)、逻辑链路控制与适配协议(L2CAP)、服务发现协议(SDP)等层次。在Java中,这些功能由Java Bluetooth API(JSR-82)提供,它定义了一个...
蓝牙通信涉及的技术点包括蓝牙协议栈的理解,如L2CAP(逻辑链路控制和适应协议)、RFCOMM(蓝牙串行端口协议)等,以及如何在Android平台上使用BluetoothAdapter、BluetoothServerSocket、BluetoothSocket等类来建立...
在蓝牙协议栈中,CRC校验通常应用于L2CAP(Logical Link Control and Adaptation Protocol)层,确保数据包的完整性。 在Android系统中,与蓝牙设备通信涉及到的主要类包括`BluetoothAdapter`、`BluetoothDevice`、...
蓝牙协议栈通常包括主机控制器接口(HCI)、逻辑链路控制和适配层(L2CAP)、连接管理层(CM)、服务发现协议(SDP)等层次,使得设备间能进行数据交换。 5. **串口打印**:串行通信接口如UART(通用异步收发传输器...
本书内容丰富,涵盖了ble(蓝牙低功耗)基础概念,包括HCI(主机控制器接口)、GATT(通用属性配置文件)和L2CAP(逻辑链路控制与适应协议)层的详细说明,以及如何使用C语言进行蓝牙编程。书中提供了大量的编程实例...
- **协议栈**: 包括链路层(LL)、主机控制接口(HCI)、逻辑链路控制与适配协议(L2CAP)、服务发现协议(SDP)等层次,MSP430F149需要实现相应的固件来处理这些协议。 3. **硬件连接与配置** - **连接蓝牙模块*...