use of org.apache.plc4x.java.api.exceptions.PlcProtocolException in project plc4x by apache.
the class Payload2SerialProtocol method decode.
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> out) throws Exception {
LOGGER.trace("(-->IN): {}, {}, {}", channelHandlerContext, byteBuf, out);
if (byteBuf.readableBytes() < MagicCookie.NUM_BYTES + TransmitterAddress.NUM_BYTES + ReceiverAddress.NUM_BYTES + FragmentNumber.NUM_BYTES) {
return;
}
MagicCookie magicCookie = MagicCookie.of(byteBuf);
TransmitterAddress transmitterAddress = TransmitterAddress.of(byteBuf);
ReceiverAddress receiverAddress = ReceiverAddress.of(byteBuf);
FragmentNumber fragmentNumber = FragmentNumber.of(byteBuf);
int expectedFrameNumber = fragmentCounter.get() - 1;
if (expectedFrameNumber < 0) {
expectedFrameNumber = 255;
}
if (fragmentNumber.getAsByte() != expectedFrameNumber) {
LOGGER.warn("Unexpected fragment {} received. Expected {}", fragmentNumber, expectedFrameNumber);
}
UserDataLength userDataLength = UserDataLength.of(byteBuf);
UserData userData;
byte userDataLengthAsByte = userDataLength.getAsByte();
if (byteBuf.readableBytes() < userDataLengthAsByte) {
return;
}
if (userDataLengthAsByte > 0) {
byte[] userDataByteArray = new byte[userDataLengthAsByte];
byteBuf.readBytes(userDataByteArray);
userData = UserData.of(userDataByteArray);
} else {
userData = UserData.EMPTY;
}
CRC crc = CRC.of(byteBuf);
// we don't need to retransmit
ScheduledFuture<?> scheduledFuture = currentRetryer.get();
if (scheduledFuture != null) {
scheduledFuture.cancel(false);
}
Runnable postAction = null;
switch(magicCookie.getAsInt()) {
case AmsSerialFrame.ID:
AmsSerialFrame amsSerialFrame = AmsSerialFrame.of(magicCookie, transmitterAddress, receiverAddress, fragmentNumber, userDataLength, userData, crc);
LOGGER.debug("Ams Serial Frame received {}", amsSerialFrame);
postAction = () -> {
// TODO: check if this is the right way to ack a package.
ChannelFuture channelFuture = channelHandlerContext.writeAndFlush(AmsSerialAcknowledgeFrame.of(transmitterAddress, receiverAddress, fragmentNumber).getByteBuf());
// waiting for the ack-frame to be transmitted before we forward the package
try {
channelFuture.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new PlcRuntimeException(e);
}
out.add(userData.getByteBuf());
};
break;
case AmsSerialAcknowledgeFrame.ID:
AmsSerialAcknowledgeFrame amsSerialAcknowledgeFrame = AmsSerialAcknowledgeFrame.of(magicCookie, transmitterAddress, receiverAddress, fragmentNumber, userDataLength, crc);
LOGGER.debug("Ams Serial ACK Frame received {}", amsSerialAcknowledgeFrame);
ReferenceCountUtil.release(byteBuf);
break;
case AmsSerialResetFrame.ID:
// TODO: how to react to a reset
AmsSerialResetFrame amsSerialResetFrame = AmsSerialResetFrame.of(magicCookie, transmitterAddress, receiverAddress, fragmentNumber, userDataLength, crc);
LOGGER.debug("Ams Serial Reset Frame received {}", amsSerialResetFrame);
ReferenceCountUtil.release(byteBuf);
break;
default:
throw new PlcProtocolException("Unknown type: " + magicCookie);
}
CRC calculatedCrc = CRC.of(DigestUtil.calculateCrc16(magicCookie, transmitterAddress, receiverAddress, fragmentNumber, userDataLength, userData));
if (!crc.equals(calculatedCrc)) {
throw new PlcProtocolException("CRC checksum wrong. Got " + crc + " expected " + calculatedCrc);
}
if (postAction != null) {
postAction.run();
}
if (byteBuf.readableBytes() > 0) {
throw new IllegalStateException("Unread bytes left: " + byteBuf.readableBytes());
}
}
use of org.apache.plc4x.java.api.exceptions.PlcProtocolException in project plc4x by apache.
the class Plc4x2AdsProtocol method encodeWriteRequest.
private void encodeWriteRequest(PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> msg, List<Object> out) throws PlcException {
InternalPlcWriteRequest writeRequest = (InternalPlcWriteRequest) msg.getRequest();
if (writeRequest.getFields().size() != 1) {
throw new PlcProtocolException("Only one item supported");
}
PlcField field = writeRequest.getFields().get(0);
if (field instanceof SymbolicAdsField) {
DirectAdsField mappedField = fieldMapping.get(field);
LOGGER.debug("Replacing {} with {}", field, mappedField);
field = mappedField;
}
if (!(field instanceof DirectAdsField)) {
throw new PlcProtocolException("PlcField not of type DirectAdsField: " + field.getClass());
}
DirectAdsField directAdsField = (DirectAdsField) field;
Invoke invokeId = Invoke.of(correlationBuilder.incrementAndGet());
IndexGroup indexGroup = IndexGroup.of(directAdsField.getIndexGroup());
IndexOffset indexOffset = IndexOffset.of(directAdsField.getIndexOffset());
Object[] plcValues;
PlcValue plcValue = writeRequest.getPlcValues().get(0);
if (plcValue instanceof PlcList) {
plcValues = ((PlcList) plcValue).getList().toArray(new Object[0]);
} else {
plcValues = new Object[] { plcValue.getObject() };
}
byte[] bytes = encodeData(directAdsField.getAdsDataType(), plcValues);
int bytesToBeWritten = bytes.length;
int maxTheoreticalSize = directAdsField.getAdsDataType().getTargetByteSize() * directAdsField.getNumberOfElements();
if (bytesToBeWritten > maxTheoreticalSize) {
LOGGER.debug("Requested AdsDatatype {} is exceeded by number of bytes {}. Limit {}.", directAdsField.getAdsDataType(), bytesToBeWritten, maxTheoreticalSize);
throw new PlcProtocolPayloadTooBigException("ADS", maxTheoreticalSize, bytesToBeWritten, plcValues);
}
Data data = Data.of(bytes);
AmsPacket amsPacket = AdsWriteRequest.of(targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort, invokeId, indexGroup, indexOffset, data);
LOGGER.debug("encoded write request {}", amsPacket);
out.add(amsPacket);
requests.put(invokeId.getAsLong(), msg);
}
use of org.apache.plc4x.java.api.exceptions.PlcProtocolException in project plc4x by apache.
the class Plc4x2AdsProtocol method encodeProprietaryRequest.
private void encodeProprietaryRequest(PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> msg, List<Object> out) throws PlcProtocolException {
PlcProprietaryRequest plcProprietaryRequest = (PlcProprietaryRequest) msg.getRequest();
if (!(plcProprietaryRequest.getProprietaryRequest() instanceof AmsPacket)) {
throw new PlcProtocolException("Unsupported proprietary type for this driver " + plcProprietaryRequest.getProprietaryRequest().getClass());
}
AmsPacket amsPacket = (AmsPacket) plcProprietaryRequest.getProprietaryRequest();
LOGGER.debug("encoded proprietary request {}", amsPacket);
out.add(amsPacket);
requests.put(amsPacket.getAmsHeader().getInvokeId().getAsLong(), msg);
}
use of org.apache.plc4x.java.api.exceptions.PlcProtocolException in project plc4x by apache.
the class Plc4x2AdsProtocol method decode.
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, AmsPacket amsPacket, List<Object> out) throws Exception {
LOGGER.trace("(-->IN): {}, {}, {}", channelHandlerContext, amsPacket, out);
if (amsPacket instanceof AdsDeviceNotificationRequest) {
LOGGER.debug("Received notification {}", amsPacket);
handleAdsDeviceNotificationRequest((AdsDeviceNotificationRequest) amsPacket);
return;
}
PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> plcRequestContainer = requests.remove(amsPacket.getAmsHeader().getInvokeId().getAsLong());
if (plcRequestContainer == null) {
LOGGER.info("Unmapped packet received {}", amsPacket);
return;
}
PlcRequest request = plcRequestContainer.getRequest();
final InternalPlcResponse response;
// Handle the response to a read request.
if (request instanceof PlcReadRequest) {
if (amsPacket instanceof AdsReadResponse) {
response = decodeReadResponse((AdsReadResponse) amsPacket, plcRequestContainer);
} else {
throw new PlcProtocolException("Wrong type correlated " + amsPacket);
}
} else if (request instanceof PlcWriteRequest) {
if (amsPacket instanceof AdsWriteResponse) {
response = decodeWriteResponse((AdsWriteResponse) amsPacket, plcRequestContainer);
} else {
throw new PlcProtocolException("Wrong type correlated " + amsPacket);
}
} else if (request instanceof PlcProprietaryRequest) {
response = decodeProprietaryResponse(amsPacket, plcRequestContainer);
} else {
response = null;
}
LOGGER.debug("Plc4x response {}", response);
// Confirm the response being handled.
if (response != null) {
plcRequestContainer.getResponseFuture().complete(response);
}
}
use of org.apache.plc4x.java.api.exceptions.PlcProtocolException in project plc4x by apache.
the class LittleEndianEncoder method encodeData.
public static byte[] encodeData(AdsDataType adsDataType, Object... values) throws PlcProtocolException {
if (values.length == 0) {
return new byte[] {};
}
Class<?> valueType = values[0].getClass();
Stream<byte[]> result;
if (valueType == Boolean.class) {
result = encodeBoolean(adsDataType, Arrays.stream(values).map(Boolean.class::cast));
} else if (valueType == Byte.class) {
result = encodeByte(adsDataType, Arrays.stream(values).map(Byte.class::cast));
} else if (valueType == Short.class) {
result = encodeShort(adsDataType, Arrays.stream(values).map(Short.class::cast));
} else if (valueType == Integer.class) {
result = encodeInteger(adsDataType, Arrays.stream(values).map(Integer.class::cast));
} else if (valueType == Long.class) {
result = encodeLong(adsDataType, Arrays.stream(values).map(Long.class::cast));
} else if (valueType == BigInteger.class) {
result = encodeBigInteger(adsDataType, Arrays.stream(values).map(BigInteger.class::cast));
} else if (valueType == LocalTime.class) {
result = encodeLocalTime(adsDataType, Arrays.stream(values).map(LocalTime.class::cast));
} else if (valueType == LocalDate.class) {
result = encodeLocalDate(adsDataType, Arrays.stream(values).map(LocalDate.class::cast));
} else if (valueType == LocalDateTime.class) {
result = encodeLocalDateTime(adsDataType, Arrays.stream(values).map(LocalDateTime.class::cast));
} else if (valueType == Float.class) {
result = encodeFloat(adsDataType, Arrays.stream(values).map(Float.class::cast));
} else if (valueType == Double.class) {
result = encodeDouble(adsDataType, Arrays.stream(values).map(Double.class::cast));
} else if (valueType == String.class) {
result = encodeString(adsDataType, Arrays.stream(values).map(String.class::cast));
} else if (valueType == byte[].class) {
result = encodeByteArray(adsDataType, Arrays.stream(values).map(byte[].class::cast));
} else if (valueType == Byte[].class) {
result = encodeBigByteArray(adsDataType, Arrays.stream(values).map(Byte[].class::cast));
} else {
throw new PlcUnsupportedDataTypeException(valueType);
}
// TODO: maybe we can replace this by a smarter flatmap
try {
return result.collect(ByteArrayOutputStream::new, (bos, byteValue) -> {
try {
bos.write(byteValue);
} catch (IOException e) {
throw new PlcRuntimeException(e);
}
}, (a, b) -> {
}).toByteArray();
} catch (PlcRuntimeException e) {
throw new PlcProtocolException("Error encoding data", e);
}
}
Aggregations