I am trying to get the battery level of my headset device with bluetooth 4.1 with AT commands from Windows using the Handsfree Profile (HFP).
I have extracted the bluetooth log from my Android phone (which is able to get the battery level) and the headset is using HFP to send AT command with the battery information (AT+IPHONEACCEV), this is one of the packets extracted from the log (with wireshark):
Frame 1122: 38 bytes on wire (304 bits), 38 bytes captured (304 bits)
Encapsulation type: Bluetooth H4 with linux header (99)
Arrival Time: Jul 16, 2020 12:18:16.449232000 Romance Daylight Time
[Time shift for this packet: 0.000000000 seconds]
Epoch Time: 1594894696.449232000 seconds
[Time delta from previous captured frame: 0.001885000 seconds]
[Time delta from previous displayed frame: 0.018263000 seconds]
[Time since reference or first frame: 21.363811000 seconds]
Frame Number: 1122
Frame Length: 38 bytes (304 bits)
Capture Length: 38 bytes (304 bits)
[Frame is marked: False]
[Frame is ignored: False]
Point-to-Point Direction: Received (1)
[Protocols in frame: bluetooth:hci_h4:bthci_acl:btl2cap:btrfcomm:bthfp]
Bluetooth
[Source: GNAudio_xxxxx (AA:BB:CC:DD:EE:FF)]
[Destination: SamsungE_xxxxx (FF:EE:DD:CC:BB:AA)]
Bluetooth HCI H4
[Direction: Rcvd (0x01)]
HCI Packet Type: ACL Data (0x02)
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
Bluetooth RFCOMM Protocol
Address: E/A flag: 1, C/R flag: 0, Direction: 0, Channel: 2
Control: Frame type: Unnumbered Information with Header check (UIH) (0xef), P/F flag: 0
Payload length: 25
Frame Check Sequence: 0xbf
Bluetooth HFP Profile
[Role: HS - Headset (2)]
AT Stream: AT+IPHONEACCEV=2,1,5,2,0\r
Command 0: +IPHONEACCEV
Command Line Prefix: AT
Command: +IPHONEACCEV (Apple Bluetooth Headset Battery Level Indication)
Type: Action Command (0x003d)
Parameters
Count: 2
Key: Battery Level (1)
Value: 5
Key: Dock State (2)
Value: 0
Now, I am trying to do get this AT commands from the headset in my Windows C# application using the 32feet (InTheHand.Net.Bluetooth) library. To do so I try to connect to the headset using BluetoothService.Handsfree:
BluetoothDevicePicker picker = new BluetoothDevicePicker();
BluetoothDeviceInfo device = await picker.PickSingleDeviceAsync();
BluetoothClient cli = new BluetoothClient();
//device.SetServiceState(BluetoothService.Handsfree, true);
cli.Connect(device.DeviceAddress, BluetoothService.Handsfree);
if (cli.Connected) MessageBox.Show("OK");
NetworkStream stream;
stream = cli.GetStream();
if (stream.CanRead)
{
byte[] buff = new byte[1024];
int n = 0;
StringBuilder str = new StringBuilder();
while (stream.DataAvailable)
{
n = await stream.ReadAsync(buff, 0, buff.Length);
str.AppendFormat("{0}", Encoding.ASCII.GetString(buff, 0, n));
}
MessageBox.Show(str.ToString());
}
When executing the code it gives the following error in cli.Connect(device.DeviceAddress, BluetoothService.Handsfree);:
System.Net.Sockets.SocketException: 'A socket operation failed because the destination host was down'
With cli.Connect(device.DeviceAddress, BluetoothService.SerialPort);it connects (so the host it is not down) but i do not get any reply from the stream.ReadAsync call.
How can i do this? Thanks!
I've found another attempt to implement this: https://github.com/SpartanX1/bluetooth_classic_battery_windows
In the README it says that device should be paired but disconnected. This way when you run the code, socket is able to connect and send/read AT reports. And device is switched to connected state automatically. This works but is absolutely insane.
If device is already connected, socket returns same error (destination host was down).
Related
Assistance in trying to detect when an actual smart-card is inserted into a USB smart-card reader attached to a handheld Android device.
I have an existing (and completely working) instance of the BroadcastReceiver and am successfully detecting when the actual smart-card reader device is connected via the filters of
myFilter.AddAction(UsbManager.ActionUsbDeviceAttached);
myFilter.AddAction(UsbManager.ActionUsbDeviceDetached);
What I am looking for now is when an actual card is inserted or removed from the device.
By using ADB (Android Debug Bridge) program and using the logcat, I can redirect the output to a file to see what is going on such as
adb logcat -c (to clear log)
adb logcat > c:\SomeFolder\MyAndroidLog.txt
Before starting the log above, I have my handheld device ready, the smart-card reader attached. Immediately after that is when I clear the log and start a fresh capture. Then I insert my smart card, wait a few seconds and then stop the log with Ctrl+C. Upon viewing the log, I am getting
--------- beginning of main
10-07 11:43:26.458 827 827 I chatty : uid=1000(system) /system/bin/surfaceflinger expire 14 lines
10-07 11:43:26.459 827 827 I ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
10-07 11:43:26.861 556 556 W hwservicemanager: getTransport: Cannot find entry vendor.qti.hardware.servicetracker#1.0::IServicetracker/default in either framework or device manifest.
10-07 11:43:26.925 556 556 I chatty : uid=1000(system) hwservicemanage identical 14 lines
10-07 11:43:26.928 556 556 W hwservicemanager: getTransport: Cannot find entry vendor.qti.hardware.servicetracker#1.0::IServicetracker/default in either framework or device manifest.
10-07 11:43:26.930 7529 7529 D BoundBrokerSvc: onUnbind: Intent { act=com.google.android.gms.feedback.internal.IFeedbackService dat=chimera-action:com.google.android.gms.feedback.internal.IFeedbackService cmp=com.google.android.gms/.chimera.GmsBoundBrokerService }
10-07 11:43:27.481 827 827 I ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
10-07 11:43:27.483 827 827 I chatty : uid=1000(system) /system/bin/surfaceflinger identical 2 lines
10-07 11:43:27.484 827 827 I ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
10-07 11:43:27.780 1170 1170 I HSMCOUNTER: Wrote to EEPROM: ret: 0
10-07 11:43:28.444 827 827 I ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
So it is showing some context of a ConfigStore, but nothing that indicates the "intent" action that other activities are capturing such as when the USB device is connected such as:
10-07 12:05:15.068 1512 1828 I ActivityManager: START u0 {act=android.hardware.usb.action.USB_DEVICE_ATTACHED flg=0x11000000 cmp=com.gemalto.gempcsc.gempcscserviceactivity/com.gemalto.gempcsc.gempcscservice.USBBroadcastReceiver (has extras)} from uid 1000
Additionally, if there is a generic way to capture ALL intents going on vs having to manually add all filters and not even knowing what they all COULD be, might help me narrow it down.
You need to talk to the reader using the CCID protocol. See my previous answer.
For example (sequence numbers in bold):
Send PC_to_RDR_GetSlotStatus (message 0x65 for slot 0):
-> 65000000000000000000
And receive RDR_to_PC_SlotStatus (message 0x81):
Example response for no card present:
<- 81000000000000020000
Example response for inserted unpowered card
<- 81000000000000010000
Below is a base-64 encoded wireshark USB trace detecting card in a GemPC Twin Reader(decode it to binary file and open it in Wireshark, then right-click any packet and select "Decode As...", change to "USB Device" tab, select "USBCCID" protocol and click "OK"):
-----BEGIN PCAP-NG CAPTURE FILE-----
H4sIAAAAAAAAA+Pi5eWSYWBg8LXRlmIE0v+hACQG4usA8R0GEGBhYGJgZygtTsrNzzNg4ATKsjFA
AEgNiJ0D5X96xcrA/SrFzgvIBmGGA9Pfnpn0/38wM5MCI4Muw8opHskg4dO6rAy9QLu4gGwuBtwg
FYmdg8WumteYdjkzN6HYZaPPClaP0y4mCNWIxMNml7LHFLhdB8S6FiH7aw3ULuWjbCT4iw2nvxZ7
YtoF8xfMrsXH2EjwFxsjzC5WNLsi2HztGRlkGJzzS/NKUouKFQqK8ssyU1JTFJIqFVJKcwuSEwuY
GDjAas8cN7NjhrIDgPpYgOwUZohZrEA2MgDZAQDbbEGJZAIAAA==
-----END PCAP-NG CAPTURE FILE-----
(Note: Sequence numbers in capture file have holes as packets are extracted from a longer dump)
i'm try to develop Project RFID Reader in windows 10 IOT in c#
i'm use RFID sticker buy from china. refer link below
https://www.aliexpress.com/item-img/10-NFC-13-56-NTAG-213-RFID/32709729334.html
and i'm use example from like below
RFID RC522 Raspberry PI 2 Windows IOT
During test RFID reader. it's work to read UID 4 byte.but i'm try to read 7 byte UID. It 's not working to read.
i'm modify some part of RC522 RFID
internal Uid(byte[] uid)
{
FullUid = uid;
//================ Change to 7 byte ======================
Bcc = uid[7];
Bytes = new byte[7];
System.Array.Copy(FullUid, 0, Bytes, 0, 7);
//Bcc = uid[4];
//Bytes = new byte[4];
//System.Array.Copy(FullUid, 0, Bytes, 0, 4);
foreach (var b in Bytes)
{
if (b != 0x00)
IsValid = true;
}
}
And
public Uid ReadUid()
{
// Run the anti-collision loop on the card
//Transceive(false , PiccCommands.Anticollision_1, PiccCommands.Anticollision_2);
Transceive(false, PiccCommands.Anticollision_1, PiccCommands.Anticollision_2);
// Return tag UID from FIFO
//return new Uid(ReadFromFifo(5));
return new Uid(ReadFromFifo(8));
}
it's still not reading.
So please advise.
There are RC522-based readers on the market that fail to read some IC cards, especially the ones with 7-byte UID. The problem is in slight differences in their antenna coil and capacitors.
The solution is either
to buy a "good" reader (which is hard to distinguish if you are buying it online)
or
to replace the capacitors C8 to C11 (C8+C9 150pF, C10+C11 33pF).
Here you can find a thorough analysis of the problem and the solution:
https://www.eluke.nl/2018/03/08/fixed-rc522-rfid-reader-not-reading-some-cards-part-1/
If the card is an S50 (aka Mifare 1K Classic) card type ISO14444A, they respond with 2Bytes (Cascade 1), 4Bytes (Cascade2) or 7Bytes (Cascade3) as their UID but you have to 'S'elect the card after starting the COM serial port. If, however you are using a reader that uses either ATR or ATS then you get back a string of hexadecimals that describe the card's characteristics. How do you know the difference - its in the documentation about the reader. Chinese cards typically are difficult to read off the starting block - try initialising a card using NFC on your mobile phone first, or just try reading the card with your phone - use TagWriter available on Google Play. Additionally look up the standards for ISO1444A cards - ISO15693 are similar but not the same. Also look at https://lastminuteengineers.com/how-rfid-works-rc522-arduino-tutorial/
i have a question about windows 10 iot and the SPI communication. I try to communicate with an extension board for the Raspberry PI. To communicate with the board i use SPI0. The 1st slave is on GPIO 7 (Pin 26), the 2nd Chip Select is on GPIO 24 (Pin 18) and the 3rd is on GPIO 08 (Pin 24).
The Position from the Pins is fixed by the manufacturer, the system is originally for linux.
The communication with slave 1 (CS1) works very well. But that's all. My problem is to speak with the 2nd and 3rd Slave. I tryed to use the GPIO 24 as an Input/Output GPIO to set up the communication before Read from CS0 as an dummy but no chance.
At the moment, I am using a hardware hack. I am connecting PIN 18 to PIN 24 with a cable, however, I don't want to open each system to place a cable bridge.
Is there a possibility to setup an customized windows 10 iot image for the raspberry pi to use the Pin 26 as CS0, Pin 24 as CS1 and Pin 18 as CS2 ?
As #Rita Han points out, the on-board SPI controller does not support pin 18 multiplexing for SPI chip select. However, I think it's still quite possible using the Pin 18 as the CS pin if you hack the spi driver a little bit.
So the inbox SPI driver is located in here, https://github.com/ms-iot/bsp/tree/master/drivers/spi/bcm2836, if you look at the source code, you can see before and after every SPI data transfer, it's setting up the SPI register to toggle the chip select pin.
So what you can do in here is instead of using the default on-board spi driver, try using the GPIO controller to toggle the pin 18 voltage, in the inbox SPI driver.
The SPI chip select pin has slack timing requirement, so i think it should be OK to use the GPIO timing.
After which, you'll need to follow some tutorial to create custom windows iot image.
You just have to indicate the device to which you are calling.
First, set the configuration of the SPI for example, using chip select line 0
settings = new SpiConnectionSettings(0); //chip select line 0
settings.ClockFrequency = 1000000;
settings.Mode = SpiMode.Mode0;
String spiDeviceSelector = SpiDevice.GetDeviceSelector();
devices = await DeviceInformation.FindAllAsync(spiDeviceSelector);
_spi1 = await SpiDevice.FromIdAsync(devices[0].Id, settings);
You can not use this pin in further actions! So now you should configure the output ports using GpioPin class, which you will use to indicate the device.
GpioPin_19 = IoController.OpenPin(19);
GpioPin_19.Write(GpioPinValue.High);
GpioPin_19.SetDriveMode(GpioPinDriveMode.Output);
GpioPin_26 = IoController.OpenPin(26);
GpioPin_26.Write(GpioPinValue.High);
GpioPin_26.SetDriveMode(GpioPinDriveMode.Output);
GpioPin_13 = IoController.OpenPin(13);
GpioPin_13.Write(GpioPinValue.High);
GpioPin_13.SetDriveMode(GpioPinDriveMode.Output);
Always before transfer indicate device: (example method)
private byte[] TransferSpi(byte[] writeBuffer, byte ChipNo)
{
var readBuffer = new byte[writeBuffer.Length];
if (ChipNo == 1) GpioPin_19.Write(GpioPinValue.Low);
if (ChipNo == 2) GpioPin_26.Write(GpioPinValue.Low);
if (ChipNo == 3) GpioPin_13.Write(GpioPinValue.Low);
_spi1.TransferFullDuplex(writeBuffer, readBuffer);
if (ChipNo == 1) GpioPin_19.Write(GpioPinValue.High);
if (ChipNo == 2) GpioPin_26.Write(GpioPinValue.High);
if (ChipNo == 3) GpioPin_13.Write(GpioPinValue.High);
return readBuffer;
}
I am using Modbus RTU protocol to read data. I have Slave Id = 1 and Modbus Address = 40023. I am configuring Start Address = 22. Is it correct with my Modbus Address?
If I am configuring following details:
Slave Id= 1 Baud Rate = 19200 Stop Bits = 2 Data Bits = 8 Parity =
None Start Address = 22
I am reading data with following code
var master = ModbusSerialMaster.CreateRtu(port);
ushort[] registers = master.ReadHoldingRegisters(slaveId, startAddress, 1); //2 is number of points
With these details I am getting this response in console:
INFO Modbus.IO.ModbusSerialTransport - TX: 1, 3, 2, 0, 0, 184, 68
In above response I only know some of them what they indicate like first digit 1 indicate Slave Id, 3 indicate function Code, 22 indicate Start Address, 2 indicate number of points.
Can anyone please explain me remaining code? What they indicate?
Thanks!
Start address is encoded in two bytes (0, 22). Number of registers is also encoded in two bytes (0, 2). (37, 207) is the CRC, needed in all Modbus RTU frames.
I think your console text is a request package.
Its meaning is in the image below
I have an Arduino Uno with a Bluesmirf Silver module connected. My Arduino has a temperature sensor which records the temp regularly. The Arduino listens for any string being sent to it over bluetooth and responds with the latest data.
I have written a C# application to fetch this data but I am seeing some strange behaviour. I am using the following code to connect, send a string and get the returned data.
mPort = new SerialPort(mPortName, 115200, Parity.None, 8, StopBits.One);
mPort.Open();
mPort.Write("download");
Thread.Sleep(1000);
while (mPort.BytesToRead > 0)
{
String data = mPort.ReadExisting();
this.BeginInvoke(new Action<String>(AddMessage), data);
}
The data I get back looks like this:
Line added locally within C# application:
Send: download
Lines added based on data received from Arduino:
Read: d???+?
GotData
------
Total Readings, 1069
Num Readings, 360
Lost Readings, 709
Reading Interval, 240000
------
350,19.34
351,19.34
352,19.34
353,20.31
....
All the text looks fine apart from the string which is being echoed back which I sent to the Arduino. Have I done something wrong with the way I sent the data?
FYI - The datasheet for the bluetooth module is here: http://www.sparkfun.com/datasheets/Wireless/Bluetooth/rn-bluetooth-um.pdf
#Jeff - This is the code which I use on my Arduino to receive data: https://github.com/mchr3k/arduino/blob/master/tempsensor/StringReader.cpp
#Jeff - stringDataLen defines the length and I call the overall function from this file: https://github.com/mchr3k/arduino/blob/master/tempsensor/tempsensor.ino
EDIT: Here is the complete source code
Arduino - https://github.com/mchr3k/arduino/tree/master/tempsensor
C# application - https://github.com/mchr3k/arduino/tree/master/serialdownload
The C# code is definitely getting the flow control wrong for some reason. I have switched to use the following code in C# and this gets a string through without corruption.
private void write(SerialPort mPort, string str)
{
foreach (char c in str)
{
mPort.Write(new char[] {c}, 0, 1);
Thread.Sleep(10);
}
}
An incorrect encoding perhaps?
mPort = new SerialPort(mPortName, 115200, Parity.None, 8, StopBits.One);
mPort.Encoding = System.Text.Encoding.ASCII; // Or System.Text.Encoding.UTF8
mPort.Open();
mPort.Write("download");
Read byte-by-byte and check each byte one by one to debug lower level problems. ReadExisting() converts bytes to a String based on the Encoding property.
My issue was caused by me using the SoftwareSerial class to communicate with my Bluetooth module on pins 2 & 3. I was using a baud rate of 115200 which is claimed to be supported on this page: http://arduino.cc/en/Reference/SoftwareSerial
However, this page ( http://arduino.cc/en/Reference/SoftwareSerialBegin ) states that the maximum baud rate supported is actually 9600. I'm not sure whether this is accurate but reducing my baud rate to 9600 has fixed my issue.
I suggest you to decrease communication speed, because there is no reason to use 115200bps (only if your module demand this speed, then it's ok). Also you are sending string "download" which is not good, rather use markers something like "#D" which internally for your Arduino device means, send data to computer. In this way you are sending only two bytes instead eight, and you will decrease probability of error, and Arduino code will be better.
Now, let's try fix the problem. First try use something like this when you are reading data from Arduino device:
ArayList dataReceaved=new ArrayList():
while(serialPort.BytesToRead>0 && serialPort.IsOpen){
dataReceaved.Add(serialPort.ReadByte());
}
So I suggest you to read byte by byte, in this or similar way. Also you shold be careful if you are sending numbers from Arduino device. If you are, then use something like this:
Serial.print(temperatureValue,BYTE);
With this code you explicitly say that data you are sending is byte long. If this not help, please let me know, so we can try something else.