`
isiqi
  • 浏览: 16484408 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

比较老的蓝牙通讯(L2CAP)代码

阅读更多
#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)));
分享到:
评论

相关推荐

    C++实现蓝牙bluetooth通讯功能

    蓝牙通信基于蓝牙核心规范,其中包括一系列协议栈,从物理层到应用层,如射频(RF)通信、链路管理、逻辑链路控制与适应协议(L2CAP)、服务发现协议(SDP)等。 在C++中实现蓝牙通信,你需要选择一个合适的库或API...

    蓝牙监控通讯

    蓝牙协议栈是一系列协议的集合,包括链路管理协议(LMP)、逻辑链路控制与适应协议(L2CAP)、服务发现协议(SDP)等,它们负责数据的编码、解码、路由和错误检测;应用程序则基于这些底层协议,实现具体的监控和通讯功能...

    windows 蓝牙通信 Bluetooth Api接口功能说明

    4. **设备连接**:`BluetoothConnect`函数用于建立与目标蓝牙设备的连接,可以是基于RFCOMM(串口模拟)或L2CAP(逻辑链路控制与适应协议)的连接。 5. **服务发现**:通过SDP服务发现协议,`...

    使用Java蓝牙无线通讯技术API

    在"使用Java蓝牙无线通讯技术API.pdf"这个文档中,应该包含了更详尽的教程和示例代码,帮助读者深入理解并实践Java蓝牙通信。通过学习和实践,开发者可以创建出能够在各种蓝牙设备之间进行数据交换的应用,如文件...

    基于windows的蓝牙通信

    4. **蓝牙协议栈**:蓝牙通信基于一系列标准协议,包括基础射频层(Bluetooth Core Specification)、逻辑链路控制和适配器层(L2CAP)、服务发现协议(SDP)等。开发者需要理解这些协议以实现不同设备间的通信。 5...

    蓝牙图片上传pc

    下面将详细阐述蓝牙通讯的基本原理、蓝牙图片传输的过程以及可能涉及的关键技术。 蓝牙是一种短距离无线通信技术,它允许设备之间建立无线连接,进行数据交换和语音通信。蓝牙工作在2.4GHz的ISM频段,采用分时跳频...

    蓝牙调频通信系统(使用Matlab编程)

    此外,理解蓝牙协议栈也是重要的一步,它包括物理层(PHY)、链路层(L2CAP)、逻辑链路控制和适应协议(L2CAP)、服务发现协议(SDP)等层次。这些协议定义了如何编码、打包、传输和解码数据,以确保蓝牙设备之间的...

    基于stm32的蓝牙通信.rar

    1. **蓝牙协议栈**:蓝牙通信依赖于蓝牙协议栈,它由多个层次组成,包括链路层(LL)、物理层(PHY)、主机控制接口(HCI)、逻辑链路控制和适配协议(L2CAP)、服务发现协议(SDP)等。在STM32中,我们通常不直接处理这些底层...

    基于arm的蓝牙通讯协议的设计,以实现嵌入式芯片的无线传输.zip

    总结,基于ARM的蓝牙通讯协议设计涉及到硬件接口、驱动开发、协议栈实现、连接管理、数据传输、安全机制以及应用接口等多个方面。利用C++的强大功能,我们可以构建高效且可靠的无线通信系统,实现嵌入式芯片间的无线...

    单片机像计算机发送、接收数据、串口中断、蓝牙通讯

    1. **蓝牙协议栈**:蓝牙通信基于蓝牙核心规范,包括蓝牙基本射频层(BLE或Classic)、链路管理层、主机控制器接口(HCI)、逻辑链路控制和适配协议(L2CAP)、服务发现协议(SDP)等层次。 2. **设备角色**:在蓝牙...

    在VC6.0上编译通过的蓝牙通信演示程序

    5. **数据传输**:蓝牙通信通常使用串行端口模拟(RFCOMM)或L2CAP(逻辑链路控制和适配协议)进行数据传输。程序中可能包含了打开串口、设置波特率、校验位等参数,以及发送和接收数据的函数。 6. **COM1口控制**...

    蓝牙协议库

    描述中的"蓝牙通讯协议的集合,适合用于蓝牙通讯开发"进一步明确了这个库的用途,它是为开发蓝牙应用而设计的。蓝牙通信协议是确保不同蓝牙设备间有效、可靠通信的一系列标准和规范。这些协议定义了如何建立连接、...

    android蓝牙通讯

    Android提供了两种类型的蓝牙socket,即`RFCOMM`(串行端口协议)和`L2CAP`(逻辑链路控制与适应协议)。在大多数情况下,我们使用`RFCOMM`进行点对点通信。使用`BluetoothDevice`的`...

    Java蓝牙无线技术

    蓝牙无线通信基于蓝牙核心规格,包括物理层、链路层、主机控制接口(HCI)、逻辑链路控制与适配协议(L2CAP)、服务发现协议(SDP)等层次。在Java中,这些功能由Java Bluetooth API(JSR-82)提供,它定义了一个...

    基于STC52单片机的蓝牙通信app

    蓝牙通信涉及的技术点包括蓝牙协议栈的理解,如L2CAP(逻辑链路控制和适应协议)、RFCOMM(蓝牙串行端口协议)等,以及如何在Android平台上使用BluetoothAdapter、BluetoothServerSocket、BluetoothSocket等类来建立...

    Bluetooth_Main.rar

    在蓝牙协议栈中,CRC校验通常应用于L2CAP(Logical Link Control and Adaptation Protocol)层,确保数据包的完整性。 在Android系统中,与蓝牙设备通信涉及到的主要类包括`BluetoothAdapter`、`BluetoothDevice`、...

    IIR滤波器单片机实现蓝牙通讯基于stm32的IIR滤波器设计,50HZ陷波器和高通滤波器,包括AD转换、串口打印等功能.zip

    蓝牙协议栈通常包括主机控制器接口(HCI)、逻辑链路控制和适配层(L2CAP)、连接管理层(CM)、服务发现协议(SDP)等层次,使得设备间能进行数据交换。 5. **串口打印**:串行通信接口如UART(通用异步收发传输器...

    Bluetooth for Programmers

    本书内容丰富,涵盖了ble(蓝牙低功耗)基础概念,包括HCI(主机控制器接口)、GATT(通用属性配置文件)和L2CAP(逻辑链路控制与适应协议)层的详细说明,以及如何使用C语言进行蓝牙编程。书中提供了大量的编程实例...

    基于MSP430F149的蓝牙点对点通讯

    - **协议栈**: 包括链路层(LL)、主机控制接口(HCI)、逻辑链路控制与适配协议(L2CAP)、服务发现协议(SDP)等层次,MSP430F149需要实现相应的固件来处理这些协议。 3. **硬件连接与配置** - **连接蓝牙模块*...

Global site tag (gtag.js) - Google Analytics