I need to work on a Bluetooth hardware and need to send the bytes data. I know the format but not sure about the last byte:-
[0x6E,0x01,0x00,0x24,0x93]
The last byte is the - byte5(verify). The preceding bytes add up, but I am not sure how value 93 came up.
Is there any specific logic that needs to be added for this.
Related
I'm trying to send data over BLE from my iPhone to an ESP32 board. I'm developing in flutter platform and I'm using flutter_reactive_ble library.
My iPhone can connect to the other device and it can also send 1 byte using writeCharacterisiticWithResponse function. But when I try to send my real data which is large (>7000 bytes), it then gives me the error:
flutter: Error occured when writing 9f714672-888c-4450-845f-602c1331cdeb :
Exception: GenericFailure<WriteCharacteristicFailure>(
code: WriteCharacteristicFailure.unknown,
message: "Error Domain=CBATTErrorDomain Code=17
"Resources are insufficient."
UserInfo={NSLocalizedDescription=Resources are insufficient.}")
I tried searching for this error but didn't find additional info, even in Apple Developer website. It just says:
Resources are insufficient to complete the ATT request.
What does this error really means? Which resources are not sufficient and how to work around this problem?
This is almost certainly larger than this characteristic's maximum value length (which is probably on the order of 10s of bytes, not 1000s of bytes). Before writing, you need to call maximumWriteValueLength(for:) to see how much data can be written. If you're trying to send serial data over a characteristic (which is common, but not really what they were designed for), you'll need to break your data up into chunks and reassemble them on the peripheral. You will likely either need an "end" indicator of some kind, or you will need to send the length of the payload first so that the receiver knows how much to excpect.
First of all, a characteristic value cannot be larger than 512 bytes. This is set by the ATT standard (Bluetooth Core Specification v5.3, Vol 3, Part F (ATT), section 3.2.9). This number has been set arbitrarily by the protocol designers and does not map to any technical limitation of the protocol.
So, don't send 7000 bytes in a single write. You need to keep it at most 512 to be standard compliant.
If you say that it works with another Bluetooth stack running on the GATT server, then I guess CoreBluetooth does not enforce/check the maximum length of 512 bytes on the client side (I haven't tested). Therefore I also guess the error code you see was sent by the remote device rather than by CoreBluetooth locally as a pre-check.
There are three different common ways of writing a characteristic on the protocol level (Bluetooth Core Specification v5.3, Vol 3, Part G (GATT), section 4.9 Characteristic Value Write):
Write Without Response (4.9.1)
Write Characteristic Value (4.9.3)
Write Long Characteristic Values (4.9.4)
Number one is unidirectional and does not result in a response packet. It uses a single ATT_WRITE_CMD packet where the value must be at most ATT_MTU-3 bytes in length. This length can be retrieved using maximumWriteValueLength(for:) with .withoutResponse. The requestMtu method in flutter_reactive_ble uses this method internally. If you execute many writes of this type rapidly, be sure to add flow control to avoid CoreBluetooth dropping outgoing packets before they are sent. This can be done through peripheralIsReadyToSendWriteWithoutResponse by simply always waiting for this callback after each write, before you write the next packet. Unfortunately, it seems flutter_reactive_ble does not implement this flow control mechanism.
Number two uses a single ATT_WRITE_REQ where the value must be at most ATT_MTU-3 bytes in length, just as above. Use the same approach as above to retrieve that maximum length (note that maximumWriteValueLength with .withResponse always returns 512 and is not what you want). Here however, either an ATT_WRITE_RSP will be returned on success or an error packet will be received with an error code. Only one ATT transaction can be outstanding at a time, which significantly lowers throughput compared to Write Without Response.
Number three uses a sequence of multiple ATT_PREPARE_WRITE_REQ packets (containing offset and value) followed by an ATT_EXECUTE_WRITE_REQ. The maximum length of the value in each each chunk is ATT_MTU-5. Each _REQ packet also requires a corresponding _RSP packet before it can continue (alternatively, an error code could be sent by the remote device). This approach is used when the characteristic value to be written is too long to be sent using a single ATT_WRITE_REQ.
For any of the above write methods, you are always also limited by the maximum attribute size of 512 bytes as per the specification.
Any Bluetooth stack I know of transparently chooses between "Write Characteristic Value" and "Write Long Characteristic Values" when you tell it to write with response, depending on the value length and MTU. Server side it's a bit different. Some stacks put the burden on the user to combine all packets but it seems nimble handles that on its own. From what I can see in the source code (https://github.com/apache/mynewt-nimble/blob/26ccb8af1f3ea6ad81d5d7cbb762747c6e06a24b/nimble/host/src/ble_att_svr.c#L2099) it can return the "Insufficient Resources" error code when it tries to allocate memory but fails (most likely due to too much buffered data). This is what might happen for you. To answer your first actual question, the standard itself does not say anything else about this error code than simply "Insufficient Resources to complete the request".
The error has nothing to do with LE Data Length extension, which is simply an optimization for a lower layer (BLE Link Layer) that does not affect the functionality of the host stack. The L2CAP layer will take care of the reassembling of smaller link layer packets if necessary, and must always support up to the negotiated MTU without overflowing any buffers.
Now, to answer your second question, if you send very large amounts of data (7000 bytes), you must divide the data in multiple chunks and come up with a way to correctly be able to combine them. Each chunk is written as a full characteristic value. When you do this, be sure to send values at most of size ATT_MTU-3 (but never larger than 512 bytes), to avoid the inefficient overheads of "Write Long Characteristic Values". It's then up to your application code to make sure you don't run out of memory in case too much data is sent.
Edit (abstract)
I tried to interpret Char/String data as Byte, 4 bytes at a time. This was because I could only get TComport/TDatapacket to interpret streamed data as String, not as any other data type. I still don't know how to get the Read method and OnRxBuf event handler to work with TComport.
Problem Summary
I'm trying to get data from a mass spectrometer (MS) using some Delphi code. The instrument is connected with a serial cable and follows the RS232 protocol. I am able to send commands and process the text-based outputs from the MS without problems, but I am having trouble with interpreting the data buffer.
Background
From the user manual of this instrument:
"With the exception of the ion current values, the output of the RGA are ASCII character strings terminated by a linefeed + carriage return terminator. Ion signals are represented as integers in units of 10^-16 Amps, and transmitted directly in hex format (four byte integers, 2's complement format, Least Significant Byte first) for maximum data throughput."
I'm not sure whether (1) hex data can be stored properly in a string variable. I'm also not sure how to (2) implement 2's complement in Delphi and (3) the Least Significant Byte first.
Following #David Heffernan 's advice, I went and revised my data types. Attempting to harvest binary data from characters doesn't work, because not all values from 0-255 can be properly represented. You lose data along the way, basically. Especially it your data is represented 4 bytes at a time.
The solution for me was to use the Async Professional component instead of Denjan's Comport lib. It handles datastreams better and has a built-in log that I could use to figure out how to interpret streamed resposes from the instrument. It's also better documented. So, if you're new to serial communications (like I am), rather give that a go.
I'm currently developing a modbus server to control a device.
The device manual says about holding registers:
Adress 6000: ValueA, 2 Byte
Adress 6001: ValueB, 1 Byte; ValueC, 4 Byte; ValueD, 4 Byte
Adress 6005: ValueE, 2 Byte
The only supported read function is FC 03 / Read Multiple Holding Registers
To my knowledge, one can see the register as a memory block of numbered 16Bit values, and could read it in one go by reading 6 registers / 12 Byte beginning at 6000.
I think the 1Byte-value isn't an issue, the register simply contains a value not exceeding 255.
But expanding the table above gives:
Adress 6000: ValueA, 2 Byte
Adress 6001: ValueB, 1 Byte
Adress 6002-6003: ValueC, 4 Byte
Adress 6004-6005: ValueD, 4 Byte
Adress 6005: ValueE, 2 Byte
so, there is an overlap last line at 6005.
My device manual is full of such occurences, and meanwhile, I'm thinking that modbus registers ain't such a simple, linear memory as I thought.
Does anybody know if modbus registers are linear, or not?
I stumbled across a similar situation and asked about it in a more specialized forum. The "to long, didn`t read" was, that the address space is linear most of the time, but not always.
Check out the following example:
Excuse the German parts, but what you can see here, is that register address 0x2021 holds data made up of eight words or eight 16-bit blocks. Following your above logic you would expect the second word to be stored in the register 0x2022, but I checked on my local device and they are not the same. So, in summary, there are some devices out there which decide, that they give one register more memory than it's ought to have. So, register 0x2021 really holds 8 words on his own and does not use register 0x2022 to hold memory.
you might have a similar case.
I'm developing an IOS app that reads Arduino serial output via redpark cable.
In the Arduino side, it uses Serial.println() to send out strings.
The string is in the format of "12.34x334.45x0.34x123x33". Essentially it's a combination of doubles with "x" in between as a special split character.
My initial thought was that in the app side, it would get the Arduino output line by line so I would just use
NSString *testString= #"12.34x334.45x0.34x123x33";
NSArray *array = [testString componentsSeparatedByString:#"x"];
to get a NSArray contains 12.34 334.45 0.34 123 and 33.
Somehow after reading questions and answers posted here, I figured out there is no way for redpark sdk to treat the Arduino output line by line, it's always in a X bytes basis.
In order to parse the Arduino output string correctly, what should i do? Would it be a good idea to add leading and tailing 0 to my double data to make the original string to be sent in a fixed length?
(i.e. "03.45x45.50x02.30" to make it 17 bytes and try to read 17 bytes of data using redpark sdk?)
The Redpark SDK only grabs the incoming serial data stream, but doesn't (despite having a few helper routines) interpret it as packets. You'll need to code that yourself. As suggested by agentatlarge in the comments to your question, read the data into a buffer using readBytesAvailable:numBytes until you get a new line character (ASCII 13), at which point you have your string to parse and can start over.
Alternatively, skip the initial string: read the incoming data until you get an "x" (at which time you add a string to an NSMutableArray) or a new line character (at which point you process the array and start a new one.
Be aware that, using the default settings (configurable in redparkSerial.h) data will be fed to you in chunks limited to 100ms (rxForwardingTimeout) or 16 bytes (rxForwardCount), whichever comes sooner. So your system will need to be able to handle multiple reads until it is certain that it has received all the data in a packet (printed line), evidenced by the arrival of the new line character.
I want to send files(text or binary) through winsock,I have a buffer with 32768 byte size, In the other side the buffer size is same,But when the packet size <32768 then i don't know how determine the end of packet in buffer,Also with binary file it seems mark the end of packet with a unique character is not possible,Any solution there?
thx
With fixed-size "packets," we would usually that every packet except the last will be completely full of valid data. Only the last one will be "partial," and if the recipient knows how many bytes to expect (because, using Davita's suggestion, the sender told it the file size in advance), then that's no problem. The recipient can simply ignore the remainder of the last packet.
But your further description makes it sound like there may be multiple partially full packets associated with a single file transmission. There is a similarly easy solution to that: Prefix each packet with the number of valid bytes.
You later mention TCustomWinSocket.ReceiveText, and you wonder how it knows how much text to read, and then you quote the answer, which is that it calls ReceiveBuf(Pointer(nul)^, -1)) to set the length of the result buffer before filling it. Perhaps you just didn't understand what that code is doing. It's easier to understand if you look at that same code in another context, the ReceiveLength method. It makes that same call to ReceiveBuf, indicating that when you pass -1 to ReceiveBuf, it returns the number of bytes it received.
In order for that to work for your purposes, you cannot send fixed-size packets. If you always send 32KB packets, and just pad the end with zeroes, then ReceiveLength will always return 32768, and you'll have to combine Davita's and my solutions of sending file and packet lengths along with the payload. But if you ensure that every byte in your packet is always valid, then the recipient can know how much to save based on the size of the packet.
One way or another, you need to make sure the sender provides the recipient with the information it needs to do its job. If the sender sends garbage without giving the recipient a way to distinguish garbage from valid data, then you're stuck.
Well, you can always send file size before you start file transfer, so you'll know when to stop writing to file.