mirror of
https://dev.iopsys.eu/feed/iopsys.git
synced 2025-12-10 07:44:50 +01:00
Add Proof of concept Bluetooth agent
This commit is contained in:
commit
aa9d058747
3 changed files with 408 additions and 0 deletions
36
Makefile
Normal file
36
Makefile
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=btle_alarm
|
||||
PKG_VERSION:=1.0.6
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/btle_alarm-utils-$(PKG_VERSION)
|
||||
PKG_SOURCE:=btle_alarm-utils-$(PKG_VERSION).tar.gz
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/btle_alarm
|
||||
SECTION:=base
|
||||
CATEGORY:=Utillities
|
||||
TITLE:=Ethernet bridging configuration utility
|
||||
#DESCRIPTION:=This variable is obsolete. use the Package/name/description define instead!
|
||||
URL:=http://btle_alarm.sourceforge.net/
|
||||
DEPENDS:=+bluez +libncurses
|
||||
endef
|
||||
|
||||
define Package/btle_alarm/description
|
||||
Ethernet bridging configuration utility
|
||||
Manage ethernet bridging; a way to connect networks together to
|
||||
form a larger network.
|
||||
endef
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
define Package/btle_alarm/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/btle_alarm $(1)/usr/bin/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,btle_alarm))
|
||||
16
src/Makefile
Normal file
16
src/Makefile
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
.SUFFIXES: .tar.gz .c
|
||||
override CFLAGS += -Wall -O0 -g -lbluetooth -lncurses
|
||||
VERSION=0.0.1
|
||||
LIBS=-lbluetooth -lm
|
||||
btle_alarm:btle_alarm.c
|
||||
all: btle_alarm btle_alarm.tar.gz
|
||||
%.tar.gz: DIR=$(subst .tar.gz,,$@)
|
||||
%.tar.gz: %.c
|
||||
@mkdir -p ./$(DIR)-0.1
|
||||
@cp $^ Makefile ./$(DIR)-$(VERSION)
|
||||
tar -cz -f $@ ./$(DIR)-$(VERSION)
|
||||
clean:
|
||||
rm -f *.tar.gz
|
||||
rm -f btle_alarm
|
||||
rm -f *.o
|
||||
rm -rf btle_alarm-*
|
||||
356
src/btle_alarm.c
Normal file
356
src/btle_alarm.c
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <curses.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/hci.h>
|
||||
#include <bluetooth/hci_lib.h>
|
||||
|
||||
#define HCI_STATE_NONE 0
|
||||
#define HCI_STATE_OPEN 2
|
||||
#define HCI_STATE_SCANNING 3
|
||||
#define HCI_STATE_FILTERING 4
|
||||
|
||||
struct hci_state {
|
||||
int device_id;
|
||||
int device_handle;
|
||||
struct hci_filter original_filter;
|
||||
int state;
|
||||
int has_error;
|
||||
char error_message[1024];
|
||||
} hci_state;
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned int battery : 2;
|
||||
unsigned int panic :1;
|
||||
unsigned int fall :1;
|
||||
unsigned int clear :1;
|
||||
unsigned int reserved :3;
|
||||
} activePersAlarm;
|
||||
|
||||
#define EIR_FLAGS 0X01
|
||||
#define EIR_NAME_SHORT 0x08
|
||||
#define EIR_NAME_COMPLETE 0x09
|
||||
#define EIR_MANUFACTURE_SPECIFIC 0xFF
|
||||
static void write_call_file(int id);
|
||||
struct hci_state open_default_hci_device()
|
||||
{
|
||||
struct hci_state current_hci_state = {0};
|
||||
|
||||
current_hci_state.device_id = hci_get_route(NULL);
|
||||
|
||||
if((current_hci_state.device_handle = hci_open_dev(current_hci_state.device_id)) < 0)
|
||||
{
|
||||
current_hci_state.has_error = TRUE;
|
||||
snprintf(current_hci_state.error_message, sizeof(current_hci_state.error_message), "Could not open device: %s", strerror(errno));
|
||||
return current_hci_state;
|
||||
}
|
||||
|
||||
// Set fd non-blocking
|
||||
int on = 1;
|
||||
if(ioctl(current_hci_state.device_handle, FIONBIO, (char *)&on) < 0)
|
||||
{
|
||||
current_hci_state.has_error = TRUE;
|
||||
snprintf(current_hci_state.error_message, sizeof(current_hci_state.error_message), "Could set device to non-blocking: %s", strerror(errno));
|
||||
return current_hci_state;
|
||||
}
|
||||
|
||||
current_hci_state.state = HCI_STATE_OPEN;
|
||||
|
||||
return current_hci_state;
|
||||
}
|
||||
|
||||
void start_hci_scan(struct hci_state current_hci_state)
|
||||
{
|
||||
if(hci_le_set_scan_parameters(current_hci_state.device_handle, 0x00, htobs(0x0010), htobs(0x0010), 0x00, 0x01, 1000) < 0)
|
||||
{
|
||||
current_hci_state.has_error = TRUE;
|
||||
snprintf(current_hci_state.error_message, sizeof(current_hci_state.error_message), "Failed to set scan parameters: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if(hci_le_set_scan_enable(current_hci_state.device_handle, 0x01, 1, 1000) < 0)
|
||||
{
|
||||
current_hci_state.has_error = TRUE;
|
||||
snprintf(current_hci_state.error_message, sizeof(current_hci_state.error_message), "Failed to enable scan: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
current_hci_state.state = HCI_STATE_SCANNING;
|
||||
|
||||
// Save the current HCI filter
|
||||
socklen_t olen = sizeof(current_hci_state.original_filter);
|
||||
if(getsockopt(current_hci_state.device_handle, SOL_HCI, HCI_FILTER, ¤t_hci_state.original_filter, &olen) < 0)
|
||||
{
|
||||
current_hci_state.has_error = TRUE;
|
||||
snprintf(current_hci_state.error_message, sizeof(current_hci_state.error_message), "Could not get socket options: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
// Create and set the new filter
|
||||
struct hci_filter new_filter;
|
||||
|
||||
hci_filter_clear(&new_filter);
|
||||
hci_filter_set_ptype(HCI_EVENT_PKT, &new_filter);
|
||||
hci_filter_set_event(EVT_LE_META_EVENT, &new_filter);
|
||||
|
||||
if(setsockopt(current_hci_state.device_handle, SOL_HCI, HCI_FILTER, &new_filter, sizeof(new_filter)) < 0)
|
||||
{
|
||||
current_hci_state.has_error = TRUE;
|
||||
snprintf(current_hci_state.error_message, sizeof(current_hci_state.error_message), "Could not set socket options: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
current_hci_state.state = HCI_STATE_FILTERING;
|
||||
}
|
||||
|
||||
void stop_hci_scan(struct hci_state current_hci_state)
|
||||
{
|
||||
if(current_hci_state.state == HCI_STATE_FILTERING)
|
||||
{
|
||||
current_hci_state.state = HCI_STATE_SCANNING;
|
||||
setsockopt(current_hci_state.device_handle, SOL_HCI, HCI_FILTER, ¤t_hci_state.original_filter, sizeof(current_hci_state.original_filter));
|
||||
}
|
||||
|
||||
if(hci_le_set_scan_enable(current_hci_state.device_handle, 0x00, 1, 1000) < 0)
|
||||
{
|
||||
current_hci_state.has_error = TRUE;
|
||||
snprintf(current_hci_state.error_message, sizeof(current_hci_state.error_message), "Disable scan failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
current_hci_state.state = HCI_STATE_OPEN;
|
||||
}
|
||||
|
||||
void close_hci_device(struct hci_state current_hci_state)
|
||||
{
|
||||
if(current_hci_state.state == HCI_STATE_OPEN)
|
||||
{
|
||||
hci_close_dev(current_hci_state.device_handle);
|
||||
}
|
||||
}
|
||||
|
||||
void error_check_and_exit(struct hci_state current_hci_state)
|
||||
{
|
||||
if(current_hci_state.has_error)
|
||||
{
|
||||
printf("ERROR: %s\n", current_hci_state.error_message);
|
||||
endwin();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void process_data(uint8_t *data, size_t data_len, le_advertising_info *info)
|
||||
{
|
||||
int cec=0;
|
||||
printf("Test: %p and %d\n", data, data_len);
|
||||
if(data[0] == EIR_NAME_SHORT || data[0] == EIR_NAME_COMPLETE)
|
||||
|
||||
{
|
||||
size_t name_len = data_len - 1;
|
||||
char *name = malloc(name_len + 1);
|
||||
memset(name, 0, name_len + 1);
|
||||
memcpy(name, &data[2], name_len);
|
||||
|
||||
char addr[18];
|
||||
ba2str(&info->bdaddr, addr);
|
||||
|
||||
printf("addr=%s name=%s\n", addr, name);
|
||||
|
||||
free(name);
|
||||
}
|
||||
else if(data[0] == EIR_FLAGS)
|
||||
{
|
||||
printf("Flag type: len=%d\n", data_len);
|
||||
int i;
|
||||
for(i=1; i<data_len; i++)
|
||||
{
|
||||
printf("\tFlag data: 0x%0X\n", data[i]);
|
||||
}
|
||||
}
|
||||
else if(data[0] == EIR_MANUFACTURE_SPECIFIC)
|
||||
{
|
||||
printf("Manufacture specific type: len=%d\n", data_len);
|
||||
|
||||
// TODO int company_id = data[current_index + 2]
|
||||
|
||||
int i;
|
||||
printf("data : ");
|
||||
for(i=1; i<data_len; i++)
|
||||
{
|
||||
printf("0x%0X ", data[i]);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Unknown type: type=%X\n", data[0]);
|
||||
}
|
||||
unsigned char d=data[3];
|
||||
|
||||
activePersAlarm.battery=d&0x03;
|
||||
activePersAlarm.panic=activePersAlarm.fall=activePersAlarm.clear=0;
|
||||
if(0x04 & data[3])
|
||||
activePersAlarm.panic=1;
|
||||
if(0x08 & data[3])
|
||||
activePersAlarm.fall=1;
|
||||
if(0x10 & data[3])
|
||||
activePersAlarm.clear=1;
|
||||
printf("Test: 0x%0X \n Fall: %d\n Alarm: %d\n Battery: %d\n Clear: %d\n",data[3],activePersAlarm.fall,activePersAlarm.panic,activePersAlarm.battery,activePersAlarm.clear);
|
||||
if((activePersAlarm.panic || activePersAlarm.fall) && !(activePersAlarm.clear))
|
||||
{
|
||||
for(cec=0;cec<6;cec++)
|
||||
write_call_file(cec);
|
||||
(void)system("mv /tmp/btle_* /var/spool/asterisk/outgoing/.");
|
||||
}
|
||||
}
|
||||
|
||||
static void write_call_file(int id)
|
||||
{
|
||||
char str[94];
|
||||
char fname[22];
|
||||
FILE *fp;
|
||||
sprintf(str,"Channel: BRCM/%d\nMaxRetries: 2\nRetryTime: 60\nWaitTime: 30\nContext: call-file-test\nExtension: %d\0",id,10);
|
||||
sprintf(fname,"/tmp/btle_alarm_%d.call",id);
|
||||
fp=fopen(fname,"w");
|
||||
fwrite(str , 1 , sizeof(str) , fp );
|
||||
fclose(fp);
|
||||
}
|
||||
int get_rssi(bdaddr_t *bdaddr, struct hci_state current_hci_state)
|
||||
{
|
||||
struct hci_dev_info di;
|
||||
if (hci_devinfo(current_hci_state.device_id, &di) < 0) {
|
||||
perror("Can't get device info");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
uint16_t handle;
|
||||
// int hci_create_connection(int dd, const bdaddr_t *bdaddr, uint16_t ptype, uint16_t clkoffset, uint8_t rswitch, uint16_t *handle, int to);
|
||||
// HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5
|
||||
if (hci_create_connection(current_hci_state.device_handle, bdaddr, htobs(di.pkt_type & ACL_PTYPE_MASK), 0, 0x01, &handle, 25000) < 0) {
|
||||
perror("Can't create connection");
|
||||
// TODO close(dd);
|
||||
return(-1);
|
||||
}
|
||||
sleep(1);
|
||||
|
||||
struct hci_conn_info_req *cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
|
||||
bacpy(&cr->bdaddr, bdaddr);
|
||||
cr->type = ACL_LINK;
|
||||
if(ioctl(current_hci_state.device_handle, HCIGETCONNINFO, (unsigned long) cr) < 0) {
|
||||
perror("Get connection info failed");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int8_t rssi;
|
||||
if(hci_read_rssi(current_hci_state.device_handle, htobs(cr->conn_info->handle), &rssi, 1000) < 0) {
|
||||
perror("Read RSSI failed");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
printf("RSSI return value: %d\n", rssi);
|
||||
|
||||
free(cr);
|
||||
|
||||
usleep(10000);
|
||||
hci_disconnect(current_hci_state.device_handle, handle, HCI_OE_USER_ENDED_CONNECTION, 10000);
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
|
||||
timeout(0);
|
||||
|
||||
struct hci_state current_hci_state = open_default_hci_device();
|
||||
|
||||
error_check_and_exit(current_hci_state);
|
||||
|
||||
start_hci_scan(current_hci_state);
|
||||
|
||||
error_check_and_exit(current_hci_state);
|
||||
|
||||
printf("Scanning...\n");
|
||||
|
||||
int done = FALSE;
|
||||
int error = FALSE;
|
||||
while(!done && !error)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned char buf[HCI_MAX_EVENT_SIZE];
|
||||
while((len = read(current_hci_state.device_handle, buf, sizeof(buf))) < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
{
|
||||
done = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
{
|
||||
if(getch() == 'q')
|
||||
{
|
||||
done = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
usleep(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
error = TRUE;
|
||||
}
|
||||
|
||||
if(!done && !error)
|
||||
{
|
||||
evt_le_meta_event *meta = (void *)(buf + (1 + HCI_EVENT_HDR_SIZE));
|
||||
|
||||
len -= (1 + HCI_EVENT_HDR_SIZE);
|
||||
|
||||
if (meta->subevent != EVT_LE_ADVERTISING_REPORT)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
le_advertising_info *info = (le_advertising_info *) (meta->data + 1);
|
||||
|
||||
printf("Event: %d\n", info->evt_type);
|
||||
printf("Length: %d\n", info->length);
|
||||
|
||||
if(info->length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int current_index = 0;
|
||||
int data_error = 0;
|
||||
|
||||
while(!data_error && current_index < info->length)
|
||||
{
|
||||
size_t data_len = info->data[current_index];
|
||||
|
||||
if(data_len + 1 > info->length)
|
||||
{
|
||||
data_error = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
process_data(info->data + current_index + 1, data_len, info);
|
||||
current_index += data_len + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(error)
|
||||
{
|
||||
printf("Error scanning.");
|
||||
}
|
||||
|
||||
stop_hci_scan(current_hci_state);
|
||||
|
||||
error_check_and_exit(current_hci_state);
|
||||
|
||||
close_hci_device(current_hci_state);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue