Track bluetooth LE keyring with RPi - bluetooth

I have bought a Chipolo (https://chipolo.net/) it is like other bluetooth low energy keyring (Tile, Keeper, Nut, ...)
I would like track it without the android application. I want to use a RPi for that.
If I put the device in association mode (press on it) I manage to discover it :
user#indigene:~ $ sudo hcitool lescan
LE Scan ...
C8:59:6F:2D:XX:XX Chipolo
I manage to make some request :
user#indigene:~ $ for d in $(sudo gatttool -t random --char-read --uuid 0x2a00 -b C8:59:6F:2D:XX:XX | sed 's,.*value: ,,'); do echo "0x$d" | xxd -r; done; echo
Chipolo
user#indigene:~ $ sudo gatttool -t random -b C8:59:6F:2D:XX:XX --characteristics
handle = 0x0002, char properties = 0x02, char value handle = 0x0003, uuid = 00002a00-0000-1000-8000-00805f9b34fb
handle = 0x0004, char properties = 0x02, char value handle = 0x0005, uuid = 00002a01-0000-1000-8000-00805f9b34fb
handle = 0x0006, char properties = 0x02, char value handle = 0x0007, uuid = 00002a04-0000-1000-8000-00805f9b34fb
handle = 0x0009, char properties = 0x20, char value handle = 0x000a, uuid = 00002a05-0000-1000-8000-00805f9b34fb
handle = 0x000d, char properties = 0x1a, char value handle = 0x000e, uuid = 0000fff0-0000-1000-8000-00805f9b34fb
handle = 0x0010, char properties = 0x0a, char value handle = 0x0011, uuid = 0000ffe0-0000-1000-8000-00805f9b34fb
handle = 0x0012, char properties = 0x1a, char value handle = 0x0013, uuid = 0000ffe1-0000-1000-8000-00805f9b34fb
handle = 0x0016, char properties = 0x0a, char value handle = 0x0017, uuid = 0000ff00-0000-1000-8000-00805f9b34fb
handle = 0x0018, char properties = 0x18, char value handle = 0x0019, uuid = 0000ff10-0000-1000-8000-00805f9b34fb
handle = 0x001b, char properties = 0x18, char value handle = 0x001c, uuid = 0000ff20-0000-1000-8000-00805f9b34fb
But when I leave the keyring without any command (for 2 minutes or more) it can't contact it anymore.
user#indigene:~ $ sudo gatttool -t random --char-read --uuid 0x2a01 -b C8:59:6F:2D:XX:XX | sed 's,.*value: ,,'
connect error: Connection refused (111)
Is there a way to request a connection or to pair with it ?
With the phone application, even if I let it for 5 minutes, when I get closer the keyring share data with the phone. Moreover I can make it ring with phone.
Is there a way to recover/simulate this behaviour with a RPi ?
Otherwise is there a way to analyse the bluetooth traffic between phone and keyring ?
Thanks in advance for your help,
BDR

Related

STM32F4 ADXL345 I2C communication

I have started to work on I2C communication by examining adxl345 sensor. I wrote basic code to test if my code works or not. According to the ADXL345 technical documentation, the 0x00 register should return device id which is 0xE5.When I tried this register , the return value is 0. This application should be basic but I guess , I still missing something. Beside my experience, I also make a search at this community about the adxl345 problems,but I could not find answer. I would be very appreciated if you guide me in this problems. I attached my code.
void SysTick_Handler(void){
HAL_IncTick();
HAL_SYSTICK_IRQHandler();}
void SysClockEn();
/*System Configuration PA8-> I2C Clock , PC9-> I2C Data Lane*/
int main(){
SysClockEn();
HAL_Init();
/*------GPIO Configuration For I2C3------*/
__GPIOA_CLK_ENABLE();
GPIO_InitTypeDef *ptrB6,addrB6;
ptrB6 = &addrB6;
ptrB6->Alternate = GPIO_AF4_I2C3;
ptrB6->Pin = GPIO_PIN_8;
ptrB6->Pull = GPIO_NOPULL;
ptrB6->Speed =GPIO_SPEED_FREQ_HIGH;
ptrB6->Mode = GPIO_MODE_AF_OD;
HAL_GPIO_Init(GPIOA,ptrB6);
__GPIOC_CLK_ENABLE();
GPIO_InitTypeDef *ptrC,addrC;
ptrC = &addrC;
ptrC->Alternate =GPIO_AF4_I2C3;
ptrC->Mode =GPIO_MODE_AF_OD;
ptrC->Pin =GPIO_PIN_9;
ptrC->Pull =GPIO_NOPULL;
ptrC->Speed =GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC,ptrC);
/*-----I2C Configurations-----*/
//__HAL_RCC_I2C3_CLK_ENABLE();
__I2C3_CLK_ENABLE();
I2C_HandleTypeDef *ptrI2C,addrI2C;
ptrI2C = &addrI2C;
ptrI2C->Instance = I2C3;
ptrI2C->Init.ClockSpeed = 100000; //100Khz
ptrI2C->Init.DutyCycle = I2C_DUTYCYCLE_2;
ptrI2C->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
ptrI2C->Mode =HAL_I2C_MODE_MASTER;
//ptrI2C->Init.GeneralCallMode =I2C_GENERALCALL_DISABLE;
//ptrI2C->Init.NoStretchMode=I2C_NOSTRETCH_DISABLE;
HAL_I2C_Init(ptrI2C);
__HAL_I2C_ENABLE(ptrI2C);
uint8_t data=0x00;
unsigned char buffer[2];
uint8_t *buf;
unsigned char pt;
uint32_t ptr;
uint8_t val
while(1){
val=HAL_I2C_IsDeviceReady(ptrI2C,0x1D,0xe5,1000);
pt=HAL_I2C_GetState(ptrI2C);
//HAL_I2C_Master_Transmit(ptrI2C,0x1d,0x00,1,0);
//HAL_I2C_Master_Receive(ptrI2C,0x1d,buffer,1,100);
//HAL_Delay(2);
HAL_I2C_Mem_Read(ptrI2C,SensAddr,0x00,1,buffer,2,1000);
ptr=HAL_I2C_GetError(ptrI2C);
}
}
void SysClockEn(){
__PWR_CLK_ENABLE();
}
The documentation of the sensor says:
the 7-bit I2C address for the device is 0x1D
So in your code your should write:
#define SensAddr (0x1D<<1)
...
HAL_I2C_Mem_Read(ptrI2C,SensAddr,0x00,1,buffer,2,1000);
...
This is because ST HAL considers the 7 bit address left shifted.
The documentation also says:
An alternate I2C address of 0x53 (followed by the R/W bit) can be chosen by grounding the SDO/ALT ADDRESS
If this is the case of your hardware, change the code to:
#define SensAddr (0x53<<1)
...
HAL_I2C_Mem_Read(ptrI2C,SensAddr,0x00,1,buffer,2,1000);
...

Turn off power to a USB port

I'm looking for a way to turn power off (and back on) for a USB port. Solution can be in C, bash, etc. I'm using a BeagleBone running 32-bit Ubuntu 16.04 for armhf.
> uname -srvm
Linux 4.4.6-ti-r15 #1 SMP Tue Apr 5 12:32:22 UTC 2016 armv7l
I've tried many things discussed on StackOverflow and AskUbuntu, including:
#include <linux/usbdevice_fs.h>
int main(void)
{
int fd = open( "/dev/bus/usb/001/002", O_WRONLY );
if (fd < 0) return 1;
int rc = ioctl( fd, USBDEVFS_RESET, 0 );
if (rc < 0) return 2;
close( fd );
return 0;
}
The USB device I need to turn off (and eventually back on) is a Champtek FS310 barcode reader which shows up as a magnetic card strip reader when I run lsusb:
> lsusb
Bus 001 Device 002: ID 040b:6543 Weltrend Semiconductor Manhattan Magnetic Card Strip Reader
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
> lsusb -t
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=musb-hdrc/1p, 480M
|__ Port 1: Dev 2, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M
|__ Port 1: Dev 2, If 1, Class=Human Interface Device, Driver=usbhid, 1.5M
I've found that running these two commands results in the device turning off:
echo "1-1" > /sys/bus/usb/drivers/usb/unbind
echo "1-1" > /sys/bus/usb/drivers/usb/bind
Strangely enough, it only turns off during "bind", not "unbind". But once it turns off this way, the only way I've found to turn it back on is to reboot the computer, which is not a usable solution.
Indeed, that other question did have a technique that worked for what I was trying to do. Note this isn't a generic Linux answer, it will only work on BeagleBone Black and similar devices. (I tested on a BeagleBone Green.) Working backwards from the devmem2 example, this block of C++ code turns the USB power off, then back on:
const size_t page_size_in_bytes = getpagesize();
const size_t address_gpio3_13 = 0x47401c60; // see comment below
const size_t address_start = address_gpio3_13 / page_size_in_bytes * page_size_in_bytes;
const size_t address_offset = address_gpio3_13 - address_start;
int fd = open("/dev/mem", O_RDWR);
void *addr = mmap( 0, page_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, fd, address_start );
uint8_t *byte_ptr = reinterpret_cast<uint8_t*>(addr);
byte_ptr[address_offset] = 0x00; // turn off USB
std::this_thread::sleep_for( std::chrono::milliseconds(500) );
byte_ptr[address_offset] = 0x01; // turn on USB
munmap( addr, page_size_in_bytes );
close(fd);
(Error handling not included.)
The magic number 0x47401c60 really is a magic number. According to some posts, it looks like a NDA needs to be signed to get access to some of the USB-related documentation. In the ARM335X Technical Reference Manual, the only mention of the 0x47401Cxx address space is the following on page 156:
Block Name Start Address End Address
USB1 Core 0x4740_1C00 0x4740_1FFF

why repeated start based i2c operation are not supported in linux?

I want to read from i2c slave which need multi start operation to read its register values.
As up-to some extent I have traced I2C driver in Linux kernel 3.18.21, I found it do not support multi start operation and I have no way to read from this I2C slave (Power Over Ethernet manager PD69104B1).
I am still finding the way I can extended driver if needed for this i2c slave or anything else needed.
I use i2c-tools 3.2.1.
I try to
$ i2cdump -y 0 0x20
but I can see same values which means it read first register every time.
$ i2cget -y 0 0x20 0x12
or any other register address returns the same value as a first register.
This slave support two read operation:
byte read - write address get its value but this need multi start
block read - start reading and i2c slave will give register values in sequence like 0x00 0x01.... (first register, second , third, fourth....etc)
I try all possible ways:
i2c_smbus_access()
i2c_smbus_write_byte()
i2c_smbus_read_block_data()
write()
read()
but then most of the time i2c bus goes into timeout error and hang situations.
Anyone has idea how to achieve this in Linux?
Update0:
This I2C slaves need unique Read cycles:
Change of Direction: S Addr Wr [A] RegAddress [A] S Addr Rd [A] [RegValue] P
Short Read: S Addr Rd [A] [RegValue] P
here last value returned from i2c slave do not expect ACK.
I tried to use I2C_M_NO_RD_ACK but with not much help. I read some value and then get FF.
This POE I2C slave have i2c time out of 14ms on SCL which is bit of doubt. This looks like i2c non standard as i2c can work on 0HZ i.e. SCL can be stretched by master as long as it want. Linux is definitely not real time OS so achieving this time out can not be guaranteed and i2c slave SCL timeout reset may happen. This is what my current conclusion is!
I2C Message notation used is from:
https://www.kernel.org/doc/Documentation/i2c/i2c-protocol
why repeated start based i2c operation are not supported in linux?
As a matter of fact, they are supported.
If you are looking for a way to perform repeated start condition in user-space, you probably need to do ioctl() with I2C_RDWR request, like it's described here (see last code snippet in original question) and here (code in question).
Below described the way to perform repeated start in kernel-space.
In Linux kernel I2C read operations with repeated start condition are performed by default for combined (write/read) messages.
Here is an example how to perform combined I2C transfer:
/**
* Read set of registers via I2C using "repeated start" condition.
*
* Two I2C messages are being sent by this function:
* 1. I2C write operation (write register address) with no STOP bit in the end
* 2. I2C read operation
*
* #client: I2C client structure
* #reg: register address (subaddress)
* #len: bytes count to read
* #buf: buffer which will contain read data
*
* Returns 0 on success or negative value on error.
*/
static int i2c_read_regs(struct i2c_client *client, u8 reg, u8 len, u8 *buf)
{
int ret;
struct i2c_msg msg[2] = {
{
.addr = client->addr,
.len = 1,
.buf = &reg,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = len,
.buf = buf,
}
};
ret = i2c_transfer(client->adapter, msg, 2);
if (ret < 0) {
dev_err(&client->dev, "I2C read failed\n");
return ret;
}
return 0;
}
To read just 1 byte (single register value) you can use next helper function:
/**
* Read one register via I2C using "repeated start" condition.
*
* #client: I2C client structure
* #reg: register address (subaddress)
* #val: variable to store read value
*
* Returns 0 on success or negative value on error.
*/
static int i2c_read_reg(struct i2c_client *client, u8 reg, u8 *val)
{
return i2c_read_regs(client, reg, 1, val);
}
Below is the illustration for i2c_read_regs(client, reg, 1, val) call:
device address is client->addr
register address is reg
1 means that we want to read 1 byte of data (pink rectangle on picture)
read data will reside at val
NOTE: If your I2C controller (or its driver) doesn't support repeated starts in combined messages, you still can use bit-bang implementation of I2C, which is i2c-gpio driver.
If nothing works, you can try next as a last resort. For some reason I can't quite remember, in order to make repeated start work I was needed to add I2C_M_NOSTART to .flags of first message, like this:
struct i2c_msg msg[2] = {
{
.addr = client->addr,
.flags = I2C_M_NOSTART,
.len = 1,
.buf = &reg,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = len,
.buf = buf,
}
};
As noted in Documentation/i2c/i2c-protocol:
If you set the I2C_M_NOSTART variable for the first partial message,
we do not generate Addr, but we do generate the startbit S.
References:
[1] I2C on STLinux

AVR UART - Java Android bluetooth communication

I have bluetooth module connected to AVR (Atmega32A) via UART. Some bytes that are transmit from bluetooth module to AVR are not properly recived.
For example the bytes that are properly transmit/recived (UTF-8):
Bluetooth module transmit byte X->recived byte X'
'w'->'w'
's'->'s'
'z'->'z'
'm'->'m'
bytes recived not properly:
'q'->'y'
'p'->'~'
'1'->'9'
Bluetooth connection settings:
Bps/Par/Bits: 115200 8N1
init UART:
#define F_CLK 16000000
#define BAUD 115200
uint16_t ubrr_value = (uint16_t) (((F_CLK)/(16 * BAUD)) - 1);
UBRRL = ubrr_value;
UBRRH = (ubrr_value>>8);
// 8 bit frame, async mode
UCSRC=(1<<URSEL) | (3<<UCSZ0);
//recive and transmit mode
UCSRB = (1<<TXEN) | (1 << RXEN);
transmit/recive byte by uart:
char USART_ReceiveByte()
{
while(!(UCSRA & (1<<RXC)));
return UDR;
}
void uart_sendRS(char VALUE)
{
while(!(UCSRA & (1<<UDRE)));
UDR = VALUE;
}
main loop:
while(1)
{
recivedByte = USART_ReceiveByte();
uart_sendRS(recivedByte);
}
i would be so glad to know why it does not work properly
EDIT: if i change the order there is result:
'y'->'y'
'~'->'~'
'9'->'9'
EDIT2: probably there is something wrong with setting UBRRL and UBRRH (ubrr_value = 7 in this case), does someone can confirm if it is proper and if the microcontroller can handle such a high BAUD?
#define F_CLK 16000000
#define BAUD 115200
uint16_t ubrr_value = (uint16_t) (((F_CLK)/(16 * BAUD)) - 1);
UBRRL = ubrr_value;
UBRRH = (ubrr_value>>8);
The problem here is that you are not initialising the UART properly. You need to set the U2X bit in UCSRA if you wish to use the baud rate as you wish it configured. If you are using avr-libc you may use the following code to properly compute the BAUD rate.
void uart0_init(void) {
# define BAUD 115200
# include <util/setbaud.h>
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
# if USE_2X
UCSRA |= _BV(U2X);
# else
UCSRA &= ~_BV(U2X);
# endif
# undef BAUD
/* other uart stuff you may need */
}
If you look at the datasheet for your microcontroller, section 20.12, you will find a table with this information precomputed for you. Cheers.

directions about customized Layer 2 implementation in linux

I have some machines running on the same network. One node is the control node which distributes traffic coming to it to the other nodes. The thing is that I want to have a custom protocol header between MAC header and IP(or whatever) payload incoming to the control node.
Control node receives this any packet like this:
------------------------------------------------
| Layer 2 | IP(or whatever protocol) | Payload |
------------------------------------------------
This packet should be distributed like this to other nodes
----------------------------------------------------------------
| Layer 2 | Custom Header | IP(or whatever protocol) | Payload |
----------------------------------------------------------------
I want some directions to do such a thing, Is there any current solution which I can use and I have to hack kernel for it from the scratch. A similar approach is to use L2TP but that runs over IP layer so I dont want that.
I also want this communication to be appeared as a seperate interface in linux like tun0 apart from physical eth0 interface.
Any help or ideas would be highly appreciated.
I dont know in what stack-exchange website this question belongs to so directions to correct website are also appreciated.
Your case is very similar to VLAN, where VLAN header also sits between L2 header and IP header. You can take a look at VLAN code, especially net/8021q/vlan_dev.c.
The key here is you need to construct your own L2 header, so you need to register your own header_ops like what VLAN does:
static const struct header_ops vlan_header_ops = {
.create = vlan_dev_hard_header,
.rebuild = vlan_dev_rebuild_header,
.parse = eth_header_parse,
};
and register it during initialization:
dev->header_ops = &vlan_header_ops;
dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN;
The ->create() function pointer here is used to create the custom header:
static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type,
const void *daddr, const void *saddr,
unsigned int len)
{
struct vlan_hdr *vhdr;
unsigned int vhdrlen = 0;
u16 vlan_tci = 0;
int rc;
if (!(vlan_dev_priv(dev)->flags & VLAN_FLAG_REORDER_HDR)) {
vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN);
vlan_tci = vlan_dev_priv(dev)->vlan_id;
vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
vhdr->h_vlan_TCI = htons(vlan_tci);
/*
* Set the protocol type. For a packet of type ETH_P_802_3/2 we
* put the length in here instead.
*/
if (type != ETH_P_802_3 && type != ETH_P_802_2)
vhdr->h_vlan_encapsulated_proto = htons(type);
else
vhdr->h_vlan_encapsulated_proto = htons(len);
skb->protocol = htons(ETH_P_8021Q);
type = ETH_P_8021Q;
vhdrlen = VLAN_HLEN;
}
/* Before delegating work to the lower layer, enter our MAC-address */
if (saddr == NULL)
saddr = dev->dev_addr;
/* Now make the underlying real hard header */
dev = vlan_dev_priv(dev)->real_dev;
rc = dev_hard_header(skb, dev, type, daddr, saddr, len + vhdrlen);
if (rc > 0)
rc += vhdrlen;
return rc;
}

Resources