private PlcResponse decodeReadResponse(S7Message responseMessage, PlcReadRequest plcReadRequest) throws PlcProtocolException {
        Map<String, PlcResponseItem<PlcValue>> values = new HashMap<>();
        short errorClass;
        short errorCode;

        S7ParameterUserDataItemCPUFunctions parameteritem = null;
        if (responseMessage instanceof S7MessageResponseData) {
            S7MessageResponseData messageResponseData = (S7MessageResponseData) responseMessage;
            errorClass = messageResponseData.getErrorClass();
            errorCode = messageResponseData.getErrorCode();
        } else if (responseMessage instanceof S7MessageResponse) {
            S7MessageResponse messageResponse = (S7MessageResponse) responseMessage;
            errorClass = messageResponse.getErrorClass();
            errorCode = messageResponse.getErrorCode();
        } else if (responseMessage instanceof S7MessageUserData) {
            S7MessageUserData messageResponse = (S7MessageUserData) responseMessage;
            S7ParameterUserData parameters = (S7ParameterUserData) messageResponse.getParameter();
            parameteritem = (S7ParameterUserDataItemCPUFunctions) parameters.getItems().get(0);
            errorClass = 0;
            errorCode = parameteritem.getErrorCode().shortValue();
        } else {
            throw new PlcProtocolException("Unsupported message type " + responseMessage.getClass().getName());
        }
        // If the result contains any form of non-null error code, handle this instead.
        if ((errorClass != 0) || (errorCode != 0)) {
            // This is usually the case if PUT/GET wasn't enabled on the PLC
            if ((errorClass == 129) && (errorCode == 4)) {
                logger.warn("Got an error response from the PLC. This particular response code usually indicates " +
                    "that PUT/GET is not enabled on the PLC.");
                for (String tagName : plcReadRequest.getTagNames()) {
                    PlcResponseItem<PlcValue> result = new DefaultPlcResponseItem<>(PlcResponseCode.ACCESS_DENIED, new PlcNull());
                    values.put(tagName, result);
                }
                return new DefaultPlcReadResponse(plcReadRequest, values);
            } else if ((errorClass == 0x85) && (errorCode == 0)) {
                logger.warn("Got an error response from the PLC. This particular response code usually indicates " +
                    "that we sent a too large packet or would be receiving a too large one. " +
                    "Please report this, as this is most probably a bug.");
                for (String tagName : plcReadRequest.getTagNames()) {
                    PlcResponseItem<PlcValue> result = new DefaultPlcResponseItem<>(PlcResponseCode.ACCESS_DENIED, new PlcNull());
                    values.put(tagName, result);
                }
                return new DefaultPlcReadResponse(plcReadRequest, values);
            } else {
                logger.warn("Got an unknown error response from the PLC. Error Class: {}, Error Code {}. " +
                        "We probably need to implement explicit handling for this, so please file a bug-report " +
                        "on https://github.com/apache/plc4x/issues and ideally attach a WireShark dump " +
                        "containing a capture of the communication.",
                    errorClass, errorCode);
                for (String tagName : plcReadRequest.getTagNames()) {
                    PlcResponseItem<PlcValue> result = new DefaultPlcResponseItem<>(PlcResponseCode.INTERNAL_ERROR, new PlcNull());
                    values.put(tagName, result);
                }
                return new DefaultPlcReadResponse(plcReadRequest, values);
            }
        }

        if (responseMessage instanceof S7MessageUserData) {
            S7PayloadUserData payload = (S7PayloadUserData) responseMessage.getPayload();
            if (plcReadRequest.getNumberOfTags() != payload.getItems().size()) {
                throw new PlcProtocolException(
                    "The number of requested items doesn't match the number of returned items");
            }

            List<S7PayloadUserDataItem> payloadItems = payload.getItems();

            PlcResponseCode responseCode = PlcResponseCode.INTERNAL_ERROR;
            PlcValue plcValue = null;
            int index = 0;
            for (String tagName : plcReadRequest.getTagNames()) {

                if (plcReadRequest.getTag(tagName) instanceof S7SzlTag) {

                    S7PayloadUserDataItemCpuFunctionReadSzlResponse payloadItem = (S7PayloadUserDataItemCpuFunctionReadSzlResponse) payloadItems.get(index);
                    responseCode = decodeResponseCode(payloadItem.getReturnCode());

                    if (responseCode == PlcResponseCode.OK) {
                        try {
                            List<PlcValue> plcValues  = new LinkedList<>();
                            byte[] data = payloadItem.getItems();


                            for (byte b : data) {
                                plcValues.add(new PlcSINT(b));
                            }

                            if (parameteritem.getLastDataUnit() == 1) {
                                final short sequenceNumber = parameteritem.getSequenceNumber();
                                boolean flag  = false;
                                ContextHandler handler = null;
                                
                                S7MessageUserData msg = null; 
                                
                                CompletableFuture<S7MessageUserData>  nextFuture = null;
                                                                
                                    int lastDataUnit = 1;
//                                    CompletableFuture<S7MessageUserData> nextFuture;
                                    S7ParameterUserData nextParameter;
                                    S7PayloadUserData nextPayload;
                                    S7PayloadUserDataItemCpuFunctionReadSzlResponse nextPayloadItem;
                                    //TODO: Aqui el codigo se congela, se debe definir una estrategia
                                    //      para que ejecuten las tareas de Netty
                                    //      https://netty.io/wiki/thread-model.html

                                    while (lastDataUnit == 1) {
                                        //TODO: Just wait for one answer!. Pending for other packages for rearm.
                                                                                   
                                        if (flag == false) {
                                            flag = true;
                                            nextFuture = reassembledMessage(sequenceNumber, plcValues);
                                            try {
                                                msg  = nextFuture.get();
                                                flag = false;                                                    
                                            } catch (Exception ex){
                                                logger.error(ex.getMessage());                                                        
                                            }
                                        };
 
                                        if (msg != null) {
                                            nextParameter = (S7ParameterUserData) msg.getParameter();
                                            var nextParameterItem = (S7ParameterUserDataItemCPUFunctions) nextParameter.getItems().get(0);
                                            lastDataUnit = nextParameterItem.getLastDataUnit();
                                            nextPayload = (S7PayloadUserData) msg.getPayload();
                                            nextPayloadItem = (S7PayloadUserDataItemCpuFunctionReadSzlResponse) nextPayload.getItems().get(0);
                                            for (byte b : nextPayloadItem.getItems()) {
                                                plcValues.add(new PlcSINT(b));
                                            }
                                            plcValue = new PlcList(plcValues);
                                            msg = null;
                                            flag = false;
                                        } else {
                                           return  new DefaultPlcReadResponse(plcReadRequest, null);
                                        }

                                    }
  
                            } else {
                                plcValue = new PlcList(plcValues);
                            }
                            
                        } catch (Exception e) {
                            throw new PlcProtocolException("Error decoding PlcValue", e);
                        }

                    }

                }
                if (plcReadRequest.getTag(tagName) instanceof S7AckTag) {
                    S7PayloadUserDataItemCpuFunctionAlarmAckResponse payloadItem =
                        (S7PayloadUserDataItemCpuFunctionAlarmAckResponse) payloadItems.get(index);
                    responseCode = decodeResponseCode(payloadItem.getReturnCode());
                    List<Short> data = payloadItem.getMessageObjects();
                    List<PlcValue> plcValues = new LinkedList<>();
                    for (short b : data) {
                        plcValues.add(new PlcSINT((byte) b));
                    }
                    plcValue = new PlcList(plcValues);
                }
                if (plcReadRequest.getTag(tagName) instanceof S7ClkTag) {
                    DateAndTime dt;
                    if (payloadItems.get(index) instanceof S7PayloadUserDataItemClkResponse) {
                        final S7PayloadUserDataItemClkResponse payloadItem =
                            (S7PayloadUserDataItemClkResponse) payloadItems.get(index);
                        responseCode = decodeResponseCode(payloadItem.getReturnCode());
                        dt = payloadItem.getTimeStamp();
                    } else if (payloadItems.get(index) instanceof S7PayloadUserDataItemClkFResponse) {
                        final S7PayloadUserDataItemClkFResponse payloadItem =
                            (S7PayloadUserDataItemClkFResponse) payloadItems.get(index);
                        responseCode = decodeResponseCode(payloadItem.getReturnCode());
                        dt = payloadItem.getTimeStamp();
                    } else {
                        throw new PlcRuntimeException("unknown date-time type.");
                    }

                    List<PlcValue> plcValues = new LinkedList<>();
                    plcValues.add(PlcDATE_AND_LTIME.of(LocalDateTime.of(
                        dt.getYear() + 2000,
                        dt.getMonth(),
                        dt.getDay(),
                        dt.getHour(),
                        dt.getMinutes(),
                        dt.getSeconds(),
                        dt.getMsec() * 1000000)));
                    plcValue = new PlcList(plcValues);
                }

                PlcResponseItem<PlcValue> result = new DefaultPlcResponseItem<>(responseCode, plcValue);
                values.put(tagName, result);
                index++;
            }

            return new DefaultPlcReadResponse(plcReadRequest, values);
        }

        // In all other cases all went well.
        S7PayloadReadVarResponse payload = (S7PayloadReadVarResponse) responseMessage.getPayload();

        // If the numbers of items don't match, we're in big trouble as the only
        // way to know how to interpret the responses is by aligning them with the
        // items from the request as this information is not returned by the PLC.
        if (plcReadRequest.getNumberOfTags() != payload.getItems().size()) {
            throw new PlcProtocolException(
                "The number of requested items doesn't match the number of returned items");
        }

        List<S7VarPayloadDataItem> payloadItems = payload.getItems();
        int index = 0;
        PlcResponseCode responseCode;
        PlcValue plcValue;
        for (String tagName : plcReadRequest.getTagNames()) {
            S7Tag tag = (S7Tag) plcReadRequest.getTag(tagName);
            S7VarPayloadDataItem payloadItem = payloadItems.get(index);

            responseCode = decodeResponseCode(payloadItem.getReturnCode());
            plcValue = null;

            if (responseCode == PlcResponseCode.OK) {
                try {
                    plcValue = parsePlcValue(tag, payloadItem.getData());
                } catch (Exception e) {
                    throw new PlcProtocolException("Error decoding PlcValue", e);
                }
            }

            PlcResponseItem<PlcValue> result = new DefaultPlcResponseItem<>(responseCode, plcValue);
            values.put(tagName, result);
            index++;
        }

        return new DefaultPlcReadResponse(plcReadRequest, values);
    }
DECODE:
This method is called when there is no handler for the message. 
By default it must correspond to asynchronous events, which if so, 
must be transferred to the event queue.
The event's own information is encapsulated in the parameters and payload
field. From this it is abstracted to the corresponding event model.
01. S7ModeEvent:
02. S7UserEvent:
03. S7SysEvent:
04. S7AlarmEvent
05. S7CyclicEvent:
06. S7CyclicEvent:
TODO: Use mspec to generate types that allow better interpretation of
the code using "instanceof".
plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java