How to respond to BLE GATT write request with "invalid attribute value"? - bluetooth-lowenergy

I have a BLE characteristic that shall represent a switch, hence a boolean value. My intention is to give it a fixed size of "1 byte", and when read, 0 means false, 1 means true. I want this characteristic to be readable and writable.
Since the value can be written, I want to validate that only one of those two values is written to the characteristic. Any other values are invalid.
The Bluetooth Core Specification v5.3 specifies in Volume 3, Part F, chapter 3.4.5.1 "ATT_WRITE_REQ" (page 1443):
If the attribute value has a fixed length and the requested attribute value
parameter length is greater than the length of the attribute value then the
server shall respond with an ATT_ERROR_RSP PDU with the Error Code
parameter set to Invalid Attribute Value Length (0x0D).
This code 0x0D is also mentioned on page 1423 in a table of ATT error codes. So when the client attempts to write more than 1 byte to the characterstic, I reject the write request with that error code 0x0D, and the correct error message appears in nRF Connect for example.
What I cannot find is if there is any recommended way to respond something that conveys an "invalid value" or "value out of range" error kind; in my case, that would be the response to any 1-byte-values other than 0x00 or 0x01, like 0x0A for example.
I see that table 3.4 on pages 1422f contains error codes for the ATT_ERROR_RSP PDU, 0x13 "Value Not Allowed" being one of them. 0x13 is however not listed as valid error code in response to an ATT_WRITE_REQ (table 3.44, page 1458).
The concept of "invalid argument" appears so fundamental to me that I don't trust my understanding it is not covered by the standard codes already.
But the only somewhat matching pre-defined and valid error code would be 0x06 "Request Not Supported", but that one is so widely used for all kinds of requests that I don't think it's meant to be used here.
Is it really up to me to pick a custom error code from the "Application Error" range? If not, which pre-defined error code should I use?

Background
Note that the error codes that are defined and discussed in the ATT chapter are mainly ATT protocol related error codes. The ATT protocol's task is to make sure that the request opcode is supported, the handle is valid, the permissions are acceptable, a sent value conforms to the maximum length requirements etc. The ATT protocol does not inspect or validate the contents of the individual bytes. That is the task of a "higher level specification", i.e. in practice GATT or a GATT service. You should therefore definitely not use ATT protocol specific error codes such as "Request Not Supported" since that refers to that an ATT operation is not implemented.
Keep in mind that the Bluetooth specification is written and maintained by a huge amount of companies and organizations who can propose not so always well thought out changes that after a (quick) review can get incorporated into the standard. Also since different Bluetooth SIG GATT services are made by different people, these people might have different opinions on which error codes should be used due to the lack of good ones properly defined by the core standard.
Let's go back to Bluetooth v4.0, when BLE was introduced. Here we can read that the only valid error codes for Write Requests are "Application Error" error codes (0x80-0xff) beyond some ATT protocol specific error codes. The ATT chapter does not specify the meaning for specific Application Error codes but instead says they are defined in a "higher layer specification".
In the GATT chapter of the 4.0 specification, we can read:
If the Characteristic Value that is written is the wrong size, or has an invalid value as defined by the profile, then the value shall not be written and an Error Response shall be sent with the Error Code set to Application Error by the server.
Opening up various GATT service specifications from Bluetooth SIG, custom application error codes are defined in a table with the corresponding meaning for this service and how the specific error code is used. One example is the Alert Notification Service, where one code is defined as "command not allowed". Another example is the HTTP Proxy Service which defines the application errors "Invalid Request" when the URI, HTTP Header or body is incorrect, and "Network Not Available" when no network connection is available. For the Physical Activity Monitor Service there is one error code "Invalid Type" that is used when the Type value is in the RFU range. Otherwise, the early defined services back in 2011 often ignore the case when an invalid value is written and do not specify how that should be handled. Take the Link Loss service for example where the alert level can be one of three different levels. It specifies how the device should act upon a disconnection for (only) the three different levels. It does not mention that a value out of range should be rejected when written and it does not specify what should happen upon disconnection if the written value was out of range.
To solve the mess a few "Common Profile and Service Error Codes" were added in Bluetooth 4.1 and listed in the Core Specification Supplement. Two of particular interest are the following:
2.1 OUT OF RANGE (0xFF)
The Out of Range error code is used when an attribute value is out of range as defined by a profile or service specification.
2.4 WRITE REQUEST REJECTED (0xFC)
The Write Request Rejected error code is used when a requested write operation cannot be fulfilled for reasons other than permissions. Note: This differs from the “Write Not Permitted” error response in Vol 3, Part F, Section 3.4.1.1 (ATT), which is intended when the write operation cannot be fulfilled due to permissions.
Lately defined services, such as the Emergency Configuration Service, has a big section in its introduction that when a client writes a value that is RFU, the server should generally "reject" the write, which I assume means use the error code above. The server can also, when specified, ignore individual RFU bits or whole RFU values, in case that would be more relevant.
In the ATT chapter of Bluetooth 4.1, the Application Error range has now been decreased from 0x80-0xff to 0x80-0x9f. The range 0xa0-0xdf is now RFU and 0xe0-0xff is allocated for "Common Profile and Service Error Codes". Apart from being breaking changes, they did two mistakes:
They forgot to include "Common Profile and Service Error Codes" in the list of allowed Error Response codes for relevant corresponding request methods "Attribute Request and Response Summary".
They forgot to change the text in the GATT chapter about how to handle a written value that is the wrong size or is invalid as defined by the profile. It still says (only) that an "Application Error" shall be sent. It should mention the possibility of "Common Profile and Service Error Codes" as well.
Since neither of the ATT nor GATT standards mention these new error codes as being valid to use for any of the Write methods, they are technically never allowed to be used...
The first mistake was fixed first in version 5.3. The second mistake has still not been fixed as of the latest version (5.3).
In Bluetooth 5.1, a Client Supported Features characteristic was added to the Generic Attribute Profile Service. This contains a bitfield that can be written by the client. If a client has ever written 1 to a bit, it may not later write a 0 to the same bit. Since the team defining this missed that the error code "Write Request Rejected" exists, or didn't think it was good enough, they invented a new error code "Value Not Allowed" which, according to my interpretation, means that the value is in range but in this situation not allowed. Here I think they made a mistake adding this as an error code as part of the ATT standard, rather than as a "Common Profile and Service Error Code". Again, they made the same mistake as before, i.e. forgot to update the table of valid error codes for the different ATT request methods as well as updating the Write section in the GATT chapter that this error code may be used when a value is not allowed.
This new Value Not Allowed error code is used in the Microphone Control Service. It has a Mute characteristic (readable, writable, notifiable) which can contain Not Muted, Muted, Disabled or RFU. A client may only write Not Muted or Muted, otherwise the server shall return "Write Not Allowed". Only the server can hence set the value to "Disabled".
So due to the lack of a clearly defined "invalid value" error defined in the first place in Bluetooth 4.0, the various specifications are not consistent how to handle the case when a written value is out of range or RFU. Some services ignore values that are RFU, some use the "Write Not Allowed" error code, some use the "Write Request Rejected" error code, some use service-defined application error codes and you also have the "Out Of Range" error code.
Conclusion
For your case, I would probably go with the "Out Of Range" 0xff error code when 1 byte is written, but the byte is out of range, since it best describes the error and is probably the most helpful one, rather than a custom application error code or a generic not allowed/rejected error code. Clients complying to Bluetooth 4.1 or newer will see this 0xff as "Out Of Range", while clients complying to Bluetooth 4.0 will see this 0xff as an Application Error code.

Related

BizTalk - Orchestration - Wcf.Action Must be a message part property of message part

I'll answer this myself, just adding here for documentation if anyone else encounters it.
We are using dynamic WCF-SQL port. I had it working in one test orchestration, but when I copied code to the real orchestration, it gave the error:
Wcf.Action Must be a message part property of message part ...
and similar for each of the lines below (in a Message Assignment shape in a BizTalk orchestration).
The issue was just to remove the
.Messagepart
Example:
SQLRequestMessage(WCF.Action) = etc...
The built-in WCF related promoted fields are on the message, not the parts of the message.
My test orchestration didn't use multipart message types, but in the real orchestration that I'm modified, our standard is to use them.
Once I saw the issue, it was obvious, but was knocking my head to figure it out for a while.

Is it possible that both TA1 and 999 missing in BizTalk when inbounding a bad formatted X12 file?

This is the 1st time I meet this.
Normally when we received an inbound X12 file. A 999 will always be generated (by configuration in BizTalk) and in case of interchange level error occurs, a TA1 will be created.
But today I got a X12 file with some formatting errors, the error popup in BizTalk is :
Delimiters are not unique, field and component seperator are the same.
The sequence number of the suspended message is 1.
I am expecting to have a 999 or TA1 generated to reject the inbound file. but none of these 2 files created.
My question:
What file shall I expect to created for this kind of error? 999 or
TA1?
Is this a bug or normal behavior for BizTalk?
If this is normal, what is the best mechanism to catch this error and
response back to trading partner.
You should definitely not expect a 999 (which would be transaction set specific), because this error prevents BizTalk from parsing the transaction set at all - it doesn't have a reliable way to determine what kind of transaction it is.
A TA1 could be appropriate, but this seems like a grey area - might be worth contacting Microsoft support about. The documentation indicates that an invalid ISA should result in a negative TA1, but the error codes for TA1 don't list this particular scenario as one that's support (or at all).
A possible work around would be capturing this kind of message, generating a TA1 for it, and routing it back to the TP. However, having non-unique delimiters may make it impossible to determine the TP from the message itself, even though you might be able to determine it from context (but maybe not if multiple trading partners use the same ports/locations). My guess is that's why BizTalk isn't handling it properly out of the box. To be honest, unless this happens fairly frequently it'd probably be easier/more realible to deal with it on an exception basis with human intervention.
As far as capturing the message, I'm thinking you'd need a custom pipeline component - perhaps even subclassing the EdiDisassembler so you can catch this particular exception and deal with it.

SCSI sense data formats and MODE SENSE control page

The SCSI reference manual defines two types of sense data formats - fixed and variable descriptor-based ones (chapter 2.4). The "Control Mode Page (0Ah)" (4.3.8), which is supposed to be returned as a response to the MODE SENSE SCSI command, contains a D_SENSE bit, which is defined as:
D_SENSE (DESCRIPTOR FORMAT SENSE DATA) bit
0 A descriptor format sense data (D_SENSE) bit set to zero specifies that the device server shall return the fixed format
sense data when returning sense data in the same I_T_L_Q nexus transaction as a CHECK CONDITION status.
1 A D_SENSE bit set to one specifies that the device server shall return descriptor format sense data when returning
sense data in the same I_T_L_Q nexus transaction as a CHECK CONDITION status, except as defined in 2.4.1.
My question is about this bit interpretation on the SCSI target side - is the target server obligated to return sense data in the descriptor format if this bit is 1? Or it's just a possibility to return this data in any format it wants?
The first byte of the sense data can be used to determine its format, so the SCSI initiator doesn't actually need the D_SENSE bit value to decide how to decode the received sense data.
I'm asking this question cause I'm working on some piece of software which is supposed to simulate a SCSI target, so I need to digest multiple SCSI documents to make it right.
If the SCSI target implements the ability to set this bit it must be able to return either of the sense formats. The SCSI target may choose to only provide this bit for reading and not writing and then it dictates what format it returns.
Please also notice that to be properly SCSI compliant you also need to provide the mode page in a "mask mode" that shows which bits of a mode page are settable.

Setting EDIFACT delimiters in party agreement

I am currently implementing an EDI solution in BizTalk Server 2010.
This is the scenario:
BizTalk is responsible for the correct message routing between a X.400 mailbox and the customer's ERP software. It is also used to put information about the exchanged message into a SharePoint site using the SharePoint webservices.
I am using Role Links and the BizTalk party management to apply the correct settings (send ports, password in UNB6 segment, etc.).
Now I have the following question:
When I try to fetch an outgoing INVOIC message from the customer's ERP system, extract the relevant information in an orchestration and write it into the SharePoint site, the receive port using the EDI receive pipeline gets suspended with the following error message:
An output message of the component "EDI disassembler" in receive pipeline
"**********.Pipelines.FileNamePromotionEDIReceivePipeline, **********.Pipelines,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=****************" is suspended
due to the following error:
Error: 1 (Miscellaneous error)
33: Invalid occurence outside message, package or group.
The sequence number of the suspended message is 1.
This happens because the message uses a CR and LF as suffix after each segment delimiter. Now I could add the ASCII-hex-codes for CR and LF to the "EfactDelimiters" setting of the pipeline, but the problem is that there are other messages without the CR and LF, which then could not be received using the same pipeline. By the way, when I fetch one of those messages without CR and LF using the pipeline also without CR and LF set as delimiters, the receive port also gets suspended, this time with an error message resulting from the usage of dots instead of commas as decimal separator (although I have enabled the option "UseDotAsDecimalSeparator" in the pipeline). Again, only changing the EfactDelimiters helps.
I thought that the "Character set and separators" page in the party agreement was supposed to make exactly that possible: To set the delimiters individually for each business party. But the changes I make in these settings seem to have no effect whatsoever. I set the "UNA6 Suffix" to "CR LF" and the "Decimal Notation (UNA3)" to ".(Decimal)", restart the host instance... same problem.
Can anyone help?
I never used biztalk, but I know my EDIFACT, and as far as I know, those messages containing CR/LF are syntactically wrong. The UNA6 Suffix seems to be an addition by Microsoft, as I can find no trace of it in the official documents on EDIFACT at UNECE.
Normally, the chars you want to use as special chars in an EDIFACT message are set by the special (optinal) UNA segment, which always comes first. When you write, you set the separators / delimiters, I don't really know, what you mean by that, as it could refer either to setting the options for the created message (what delimiters are used in the message), setting the delimiters used for parsing by the receiving program, or it could refer to the chars that are printed in the UNA segment.
Know, in the UNA segment, there is no way that I know of, to indicate the use of any UNA6 suffix (as stated quite explicitly in the documents, the UNA segment has to be exactly 9 characters of length, see 8.3 Interchange formatting rules). That leads me to the conclusion, that you set the options for the created messages. I would not advise to use a UNA6 suffix, if you can avoid it. It might be nice for humans to read the message, but it does not belong there and is not useful for the machine to read.
If the receiving program has no option to allow optional occurrence of CR/LF, and you can not avoid a mix of those to kind of messages, I see no other way for you other than somehow insert a small program that gets rid of the CR/LF.
The most important principle is of course, to make the sending and the receiving program talk in the same syntax, otherwise it can't work. The same thing goes for the problem with the decimal separator. As of Syntax rules, 10.1, either the comma or the dot is allowed, which is a quite loose definition. If you want to be on the save side, send an UNA segment, specifying which one you use, and then only use that one.
I'm not really sure, how much this helps you with the specific problem, as it might be a thing that's only a question on how to configure biztalk, but I thing some background information should be useful.

Correlation on MessageBox direct bound ports

I have an orchestration called MyUsefulOrch, hosted in an application MySharedApp.
MyUsefulOrch has an inbound messagebox-direct-bound port to receive requests, and after doing some useful work, an outbound messagebox-direct-bound port to send a message to the caller.
Now, I have another orchestration called MyCallerOrch which wants to benefit from the useful processing provided by MyUsefulOrch. However, MyCallerOrch is hosted in a different application, MyCallingApp.
I do not want to have any references to the assembly which contains MyUsefulOrch from MyCallerOrch.
My problem now is making sure I can send a message to MyUsefulOrch from MyCallerOrch and receive a response from it.
Ahah! Correlation should do the trick! But how do I go about getting correlation to work in this scenario?
For example:
Would I put a correlation id in a property schema and stuff a guid into the message context under this property from MyCallerOrch just before sending it to the messagebox?
How do I ensure that MyCallerOrch receives only the responses it needs to receive from MyUsefulOrch?
Do I need to put the correlation id value into the message body of the messages which are sent between the two orchestrations?
I would greatly appreciate any help, ideally as descriptive as possible, about how to acheive this.
Many thanks in advance.
If you use a two-way, request/response send port in the caller orchestration to send messages to the useful orchestration, then you can use correlation to route the relevant messages back to the userful orch from the caller.
The trick is that you will need to modify the useful orch (to make it more useful, of course).
If you do not/cannot control whether or not callers to the userful orch are expecting a response back, then you would need to make the inbound (request) port a one-way port. The orchestration would then complete by sending to a one-way outbound (response) port.
To ensure that messages received from two-way/request-response callers are routed back properly, the construct shape of the outbound message inside your useful orch will need to set the following message properties to true using a message assignment shape:
BTS.RouteDirectToTP
BTS.IsRequestResponse
Before setting those two properties, though, also make sure to do something like msgOut(*) f= msgIn(*); in the same message assignment shape to ensure that other properties get copied over. If the inbound and outbound messages are not the same, then you have to manually set each of the required properties, one at a time.
Those properties, of course, in addition to the two above, are what help ensure that the result of the useful orch is properly routed to the caller. They should be inside your correlation set and are:
BTS.CorrelationToken
BTS.EpmRRCorrelationToken
BTS.IsRequestResponse
BTS.ReqRespTransmitPipelineID
BTS.RouteDirectToTP
I'm getting a bit ahead of myself, however, as you assign the correlation set to the outbound send shape only if BTS.EpmRRCorrelationToken exists msgIn. This is critical. I have used a decision shape in an orchcestration, with the decision based upon that exact phrase. If the result is true, then send the previously constructed message out and assign the correlation set from above as the Initializing correlation set. This will cause BizTalk to route the message back to the caller as its expected response.
If the result of the decision was false then the caller of the useful orchestration was one-way. You will still likely want to send out a result (and just have someone else subscribe to it). You can even use the same send port as for two-way responses, just do not assign the correlation set.
You will want to thoroughly test this, of course. It does work for me in the one scenario in which I have used it, but that doesn't absolve others from doing their due diligence.
I think you are pretty much on the right track
Since the 2 applications are going to send messages to eachother, if you use strongly typed schemas, both apps will need to know about the schemas.
In this case recommend that you separate the common schemas off into a separate assembly, and reference this from both your orchestration apps.
(Schemas registered on the Server must have unique XMLNS#ROOTs, even across multiple applications)
However, if you really can't stand even a shared schema assembly reference, you might need to resort to untyped messages.
Richard Seroter has an example here
His article also explains a technique for auto stamping a correlation GUID on the context properties.
Edit : Good point. It is possible to promote custom context properties on the message without a Pipeline - see the tricks here and here - this would suffice to send the context property to MyUsefulOrch and similarly, the Custom context could be promoted on the return message from within MyUsefulOrch (since MyUsefulOrch doesn't need any correlation). However I can't think how, on the return to MyCallingOrch that the custom context property can be used to continue the "following correlation", unless you add a new correlating property into the return message.

Resources