Writing to 2 seperate BLE devices with same Tx Characteristics - bluetooth-lowenergy

I am using Windows 10, VS 2019, C++, WinRT
I have a questions about writing to a Tx characteristic after I have connected 2 devices with the same Tx characteristics. I want to control 2 identical BLE devices separately. I have all of the code in place for connecting and running 1 of these devices but as I studied my existing code I don't see that the characteristic write refers to a particular device object.
The device objects are created with
auto device1 = co_await BluetoothLEDevice::FromBluetoothAddressAsync(deviceAddress1); // Same with device2
I then get the main service and the Tx and Rx characteristics which are the same for device1 and 2.
After setting up the writer with
auto writer = Windows::Storage::Streams::DataWriter();
and then filling in the command to be written with
writer.WriteString(wstrCommand);
I then do the actual write to the Tx characteristic with
status = co_await TxCharacteristic.WriteValueWithResultAsync(writer.DetachBuffer(),
winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::GattWriteOption::WriteWithoutResponse);
To which device would this command be sent? Am I leaving out a reference to the device1 or device2 object?
Edit
Is it that the TxCharacteristic object contains the Service object with contains the deviceID and therefore if I write to TxCharacteristic1 and 2 it will write to the proper device? I guess I will have to do the code and find out.
Thanks.
Ed

The answer is that the Characteristic object will write to the device object from which it was read. My original mistake was to be thinking of the characteristic as the GUID and forgetting that in WinRT the characteristic is an object that contains properties (one of which is the Uuid) which contain properties. I have not looked at the WriteValueWithResultAsync code but it appears that the code will direct the write to the characteristic of the device associated with that characteristic so you need to keep the characteristic objects separate.
What I had to do was alter my memory variable names from TxCharacteristic to TxCharacteristic1 and TxCharacteristic2 and, of course, put in a lot of if...else clauses. I also had to create RxCharacteristic1 and RxCharacteristic2 and to create 2 separate Rx callbacks. Live and Learn.

Related

Reading output pin level on SAMDG55

I'm building a firmware for a device based on Atmel/Microchip AT SAMG55.
In a simple function, trigger some relais connected to GPIO pins.
Because I want to interlock different I/O, avoiding that 2 specific outputs are high level on the same time, I need to know the pin level I set before.
In another project, based on the SAMD21, there was a function that reads output pin state
static inline bool port_pin_get_output_level(const uint8_t gpio_pin)
The SAMG55 port library in ASF is quite different, so i tried ioport_get_pin_level(pin), but i'm not getting expected result. I think that it works only with pins configured as inputs.
Are there any recommended solutions?
Referring to Figure 16-2 in the SAMG55 data sheet, and to sections 16.5.4 and 16.5.8:
16.5.4 Output Control
... The level driven on an I/O line can be determined by writing in the Set Output Data Register (PIO_SODR) and
the Clear Output Data Register (PIO_CODR). These write operations,
respectively, set and clear the Output Data Status Register
(PIO_ODSR), which represents the data driven on the I/O lines. ...
16.5.8 Inputs
The level on each I/O line can be read through PIO_PDSR. This register indicates the level of the I/O lines regardless of their
configuration, whether uniquely as an input, or driven by the PIO
Controller, or driven by a peripheral. Reading the I/O line levels
requires the clock of the PIO Controller to be enabled, otherwise
PIO_PDSR reads the levels present on the I/O line at the time the
clock was disabled.
So, as long as the pin is configured such that the actual level on the pin always corresponds to the level we're trying to drive - which is not the case with an open collector configuration, for example - then Tarick Welling's answer is correct: you can read the output state from the Output Data Status Register (PIO_ODSR).
However the true state of the pin, regardless of driver configuration, can be read (subject to a resynchronisation delay that may or may not be relevant in any given application) from the Pin Data Status Register (PIO_PDSR).
You can do some low level programming. You use the high level HAL functions to configure, set and reset the pins but before you do that you would. Read the value for the pin by addressing the data value of the register. In AVR that would be done by reading PORTx. In a STM32 this can be done by reading the value of GPIOx->ODR. You would of course then need to extract the correct pin but this can be done.
You can also look inside the definition of port_pin_get_output_level and check how they did it and convert that into the way this board/vendor/HAL does its addressing.
update:
When looking inside the datasheet for the SAM G55G/J. Page 340 gives us the answer we need.
The level driven on an I/O line can be determined by writing in the Set Output Data Register (PIO_SODR) and the
Clear Output Data Register (PIO_CODR). These write operations, respectively, set and clear the Output Data
Status Register (PIO_ODSR), which represents the data driven on the I/O lines.
So we can drive the output by writing to PIO_SODR and PIO_CODR to set and reset the pins respectively. But also read from PIO_ODSR this is a register which contains the state of the pin.
A quick google search turns up two options for Atmel/AVR controllers:
read back from the same location you used to set your output value (PORTx register)
This will give you the value that you have written into the register before.
read the actual value using the PINx registers
This will give you the value that you could actually measure on your device.
The difference between the two can be important: if you set a GPIO that is pulled down below the logic voltage threshold (i.e. if connected to GND) to HIGH, PORTx will read HIGH (the value you set) while PINx will read LOW (the actual value).
https://www.avrfreaks.net/forum/reading-pin-set-output

read a well defined frame with qtserialport

I'm developing a desktop application with qt which communicates with stm32 to send and receive data.
The thing is, the data to transfer, follow a well-defined shape, with a previously defined fields. My problem is that I can't find how read () or readall() work or how Qserialport even treats the data. So my question is how can I read data (in real time, whenever there is data in the buffer) and analyze it field by field (or per byte) in order to be displayed in the GUI.
There's nothing to it. read() and readAll() give you bytes, optionally wrapped in a QByteArray. How you deal with those bytes is up to you. The serial port doesn't "treat" or interpret the data in any way.
The major point of confusion is that somehow people think of a serial port as if it was a packet oriented interface. It's not. When the readyRead() signal fires, all that you're guaranteed is that there's at least one new byte available to read. You must cope with such fragmentation.

HM-10 AT Commands: Using Beacon Way to Broadcast Sensor's Data

I try to use beacon(HM-10) to broadcast my sensor's data, but there is a problem that I use a loop to write AT commands, after a while, it doesn't respond anything.
Here is the part of the code:
String pre = "AT+MARJ0x";
int sensorData = 0;
loop () {
sensorData = getSensorData(); // always returns 100 ~180
String atCommand = pre + sensorData; // ex: AT+MARJ0x100
BTSerial.print (atCommand);
delay (200);
}
It initially work successfully about 3-mins, and then it doesn't work and can't be sent any at commands.
Can anybody help me fix this problem?
What you are trying is not possible with an Ibeacon.
All you do is set-up the major number of Ibeacon data in your HM-10device over and over again with sensor data.
major number is a part of the Ibeacon data spec:
(source: https://developer.mbed.org/blog/entry/BLE-Beacons-URIBeacon-AltBeacons-iBeacon/)
Data Spec:
IBeacons broadcast four pieces of information:
A UUID that identifies the beacon.
A Major number identifying a subset of beacons within a large group.
A Minor number identifying a specific beacon.
A TX power level in 2's compliment, indicating the signal strength one meter from the device.
This number must be calibrated for each device by the user or manufacturer.
A scanning application reads the UUID, major number and minor number and references them against a database
to get information about the beacon;
the beacon itself carries no descriptive information - it requires this external database to be useful.
The TX power field is used with the measured signal strength to determine how far away the beacon is from the smart phone.
Please note that TxPower must be calibrated on a beacon-by-beacon basis by the user to be accurate.
For a HM-10 device AT-commands are normally only used to set-up the device, not for sending data.
Google some examples and learn how to setup communication between BLE devices.

Reading/writing long values to BLE device via Qt

I'm writing a Qt 5.5.0 app that communicates with a BLE peripheral LinkitONE. The peripheral is pre-programmed in such a way that to read or change a variable first I have to write the variable name into a specific characteristic and then either read or write the data from another characteristic.
I write with QLowEnergyService::writeCharacteristic and read with QLowEnergyService::readCharacteristic. It all works well unless I have to read or write anything longer than 20 bytes in which case the data is cut at the end. Is there any way to either increase the write buffer size or specify the offset for writing?

Device tree bindings?

Do we have to go through the Device tree bindings documentation of a linux kernel when you start working on it.
Is there no standard set of fields in the device tree which are followed by all distros/kernel sources?
Secondly I need some guidance regarding adding nodes for devices on gpio bus using device tree. I have already consulted http://devicetree.org/Device_Tree_Usage.
stackoverflow-query here should point you to documentation on device tree. And yes it is a good idea to go through the documentation before you dive into using it.
As for your gpio devices (I assume you already have a gpio controller in place in your dts/dtsi file in place), there should be plenty under arch/arc/boot/dts . Pick one :)!
Eg: gpio1_8 for mmc dts and gpio1 controller dtsi
Device Tree Binding for peripherals in an SoC:
As an example for the v5.1 kernel, here are the device tree bindings listed for various peripherals available on an SoC.
Link:
https://elixir.bootlin.com/linux/v5.1/source/Documentation/devicetree/bindings
Device Tree Binding for a particular peripheral in an SoC:
To explain a bit about the device tree binding for a particular peripheral let's take an example of an SPI for a very popular TI OMAP family.
Link:
https://elixir.bootlin.com/linux/v5.1/source/Documentation/devicetree/bindings/spi/omap-spi.txt
The text in this particular link introduces basically the key-value pairs. The 'key' is the device tree property and the 'value' is the possible place holder values for the corresponding 'key'. As an example, in the above link the "compatible" property, which holds one of the value as "ti,omap2-mcspi".
Another example is the "dma-names" property which holds txN, rxN .
Now, in the below link you can clearly see how these device tree properties are used in the real device trees:
https://elixir.bootlin.com/linux/v5.1/source/arch/arm/boot/dts/omap3.dtsi#L365
mcspi1: spi#48098000 {
compatible = "ti,omap2-mcspi";
reg = <0x48098000 0x100>;
...
}
The value "ti,omap2-mcspi" for the key "compatible" is one of the available value in accordance with the device tree binding document for omap-spi.txt (as seen in the second listed link).
So now based on SoC and the peripheral used, the device tree property can be written consulting the device tree binding document.

Resources