u9n / dlms-cosem

A Python library for DLMS/COSEM
Other
80 stars 41 forks source link

Handling service specific block transfer - GET #9

Closed Krolken closed 3 years ago

Krolken commented 3 years ago

We need to support service specific block transfer, at least for the GET service. The service specific block transfer is different from the GeneralBlockTransfer.

The service specific GET block transfer is still contained done using GET-requests and GET-responses. But when the result is larger than negotiated PDU-size the meter will need to send data in blocks. It does this by sending a GET-response with the type GetType.WITH_BLOCK.

Upon receiving this the client should request the next block with a GET request to the same instance and attribute but setting the type to GetRequestType.NEXT

The last block sent from the meter will be a GET-response with block where the last-block attribute is true.

To be able to support this feature we should do some changes:

  1. Instead of sending a GetRequest with request_type=GetRequestType.NEXT we should send a GetRequestNext apdu. By using new classes for the different types of request and responses we can easier track the the state of the connection and we can easier control the encoding and decoding of the bytes for each specific APDU. We should however introduce a new factoryclass that can generate the correct class when given the data of a GetRequest.
  2. We need to delay interpretation of the byte sent in the request. Now with a GetRequest.NORMAL we can just parse the data since it is all there. But when we introduce the block transfer we need to wait for all the blocks to arrive before we can try to parse the data. The simplest thing would be to just supply the bytes and let the client parse data when it feels eveything is done.

New classes for the GetRequest factory:

New classes for the GetResponseFactory:

Error handling:

The service specific block transfers are arguably worse in reliability than the GeneralBlockTransfer. We cannot request lost blocks. If we receive a block out of order we need to abort the whole transmission.

  1. If the meter cannot produce the next block for some reasone it will respond with a GetResponseLastBlockWithError but indicate an error instead of data. This ends the transmission.
  2. If the meter receives a GetRequestNext with a block number that is not the last block the meter sent, the meter will interpret this as an abortion and will abort the transmission by sending a GetResponseLastBlockWithError with an error DataAccessResult.LONG_GET_ABORTED.
  3. The client might send a GetRequestNext when no block transfer has been initiated. The meter will then respond with a GetResponseLastBlockWithError with the error DataAccessResult.NO_LONG_GET_IN_PROGRESS.
  4. If the client receives a block from the meter that is not the next block in the sequence the client shall abort the transmission and not send a GetRequestNext.
  5. If for any reason in the cases 1-3 the meter is not able to produce a GetResponseLastBlockWithError it can instead send a GetResponseNormalWithError