From c4115fdea1872b964aa470d4379d7d310d037be0 Mon Sep 17 00:00:00 2001 From: Christofer Dutz Date: Fri, 2 Feb 2024 12:41:01 +0100 Subject: [PATCH] refactor: Finished support for the last missing data types for S7 1500 models. --- .../java/JavaLanguageTemplateHelper.java | 8 +- .../templates/java/data-io-template.java.ftlh | 7 + plc4c/api/include/plc4c/data.h | 4 + .../s7/include/transport_size.h | 3 +- plc4c/generated-sources/s7/src/data_item.c | 177 ++++++++++++++++++ .../generated-sources/s7/src/transport_size.c | 85 +++------ plc4c/spi/include/plc4c/spi/types_private.h | 1 + plc4c/spi/src/data.c | 10 + .../protocols/s7/readwrite/model/DataItem.go | 103 ++++++++++ .../s7/readwrite/model/TransportSize.go | 76 ++------ .../plc4x/java/api/types/PlcValueType.java | 3 +- .../plc4x/java/ads/readwrite/DataItem.java | 8 +- .../java/plc4x/readwrite/Plc4xValue.java | 8 +- .../plc4x/java/s7/readwrite/DataItem.java | 104 ++++++++++ .../java/s7/readwrite/TransportSize.java | 23 +-- .../readwrite/protocol/S7ProtocolLogic.java | 2 +- .../plc4x/java/s7/readwrite/tag/S7Tag.java | 14 +- .../java/s7/readwrite/utils/StaticHelper.java | 1 - .../s7/readwrite/ManualS71500DriverTest.java | 9 +- .../java/spi/values/PlcDATE_AND_LTIME.java | 141 ++++++++++++++ .../src/main/resources/protocols/s7/s7.mspec | 36 ++-- 21 files changed, 641 insertions(+), 182 deletions(-) create mode 100644 plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcDATE_AND_LTIME.java diff --git a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java index 06d11e7cda8..9a573ac4aaf 100644 --- a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java +++ b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java @@ -649,8 +649,14 @@ public String getDataIoPropertyValue(PropertyField propertyField) { } else { return "BigInteger.valueOf(_value.getTime().getLong(ChronoField.NANO_OF_DAY))"; } + case "nannosecondsOfSecond": + if(simpleTypeReference.getSizeInBits() <= 63) { + return "_value.getTime().getLong(ChronoField.NANO_OF_SECOND)"; + } else { + return "BigInteger.valueOf(_value.getTime().getLong(ChronoField.NANO_OF_SECOND))"; + } case "nanosecondsSinceEpoch": - return "BigInteger.valueOf(_value.getDateTime().toEpochSecond(ZoneOffset.of(ZoneId.systemDefault().getId()))).multiply(BigInteger.valueOf(1000000000)).add(BigInteger.valueOf(_value.getDateTime().getNano()))"; + return "BigInteger.valueOf(_value.getDateTime().toEpochSecond(OffsetDateTime.now().getOffset())).multiply(BigInteger.valueOf(1000000000)).add(BigInteger.valueOf(_value.getDateTime().getNano()))"; } if("value".equals(propertyField.getName())) { } else { diff --git a/code-generation/language-java/src/main/resources/templates/java/data-io-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/data-io-template.java.ftlh index 2121f094eca..05d5f8bf282 100644 --- a/code-generation/language-java/src/main/resources/templates/java/data-io-template.java.ftlh +++ b/code-generation/language-java/src/main/resources/templates/java/data-io-template.java.ftlh @@ -318,6 +318,13 @@ public class ${type.name} { return PlcDATE_AND_TIME.ofSecondsSinceEpoch(secondsSinceEpoch); <#break> + <#case "DATE_AND_LTIME"> + <#if helper.hasFieldsWithNames(case.fields, "nanosecondsSinceEpoch")> + return PlcDATE_AND_LTIME.ofNanosecondsSinceEpoch(nanosecondsSinceEpoch); + <#elseif helper.hasFieldsWithNames(case.fields, "year", "month", "day", "hour", "minutes", "seconds", "nannosecondsOfSecond")> + return PlcDATE_AND_LTIME.ofSegments(year, (month == 0) ? 1 : month, (day == 0) ? 1 : day, hour, minutes, seconds, nannosecondsOfSecond); + + <#break> <#case "LDATE_AND_TIME"> <#if helper.hasFieldsWithNames(case.fields, "nanosecondsSinceEpoch")> return PlcLDATE_AND_TIME.ofNanosecondsSinceEpoch(nanosecondsSinceEpoch); diff --git a/plc4c/api/include/plc4c/data.h b/plc4c/api/include/plc4c/data.h index 39214db1b34..0dc2fe480f4 100644 --- a/plc4c/api/include/plc4c/data.h +++ b/plc4c/api/include/plc4c/data.h @@ -139,6 +139,10 @@ plc4c_data *plc4c_data_create_date_and_time_array(uint32_t *tad, int nItems); plc4c_data *plc4c_data_create_ldate_and_time_data(uint64_t nanosecondsSinceEpoch); plc4c_data *plc4c_data_create_ldate_and_time_array(uint64_t *nanosecondsSinceEpoch, int nItems); +plc4c_data *plc4c_data_create_date_and_ltime_data(uint64_t nanosecondsSinceEpoch); +plc4c_data *plc4c_data_create_date_and_ltime_array(uint64_t *nanosecondsSinceEpoch, int nItems); + + /** * Creates a plc4c_data with char* * @param size the size of the string diff --git a/plc4c/generated-sources/s7/include/transport_size.h b/plc4c/generated-sources/s7/include/transport_size.h index 9522336dc32..31778cbcf35 100644 --- a/plc4c/generated-sources/s7/include/transport_size.h +++ b/plc4c/generated-sources/s7/include/transport_size.h @@ -60,9 +60,8 @@ enum plc4c_s7_read_write_transport_size { plc4c_s7_read_write_transport_size_LTOD = 0x1B, plc4c_s7_read_write_transport_size_DATE_AND_TIME = 0x1C, plc4c_s7_read_write_transport_size_DT = 0x1D, - plc4c_s7_read_write_transport_size_LDATE_AND_TIME = 0x1E, + plc4c_s7_read_write_transport_size_DATE_AND_LTIME = 0x1E, plc4c_s7_read_write_transport_size_LDT = 0x1F, - plc4c_s7_read_write_transport_size_DATE_AND_LTIME = 0x20, plc4c_s7_read_write_transport_size_DTL = 0x21 }; typedef enum plc4c_s7_read_write_transport_size plc4c_s7_read_write_transport_size; diff --git a/plc4c/generated-sources/s7/src/data_item.c b/plc4c/generated-sources/s7/src/data_item.c index d9eec39a71e..3bc09b1b1ff 100644 --- a/plc4c/generated-sources/s7/src/data_item.c +++ b/plc4c/generated-sources/s7/src/data_item.c @@ -384,6 +384,98 @@ plc4c_return_code plc4c_s7_read_write_data_item_parse(plc4x_spi_context ctx, plc *data_item = plc4c_data_create_date_and_time_data(dayOfWeek); + } else if(strcmp(dataProtocolId, "IEC61131_DATE_AND_LTIME") == 0) { /* DATE_AND_LTIME */ + + // Simple Field (nanosecondsSinceEpoch) + uint64_t nanosecondsSinceEpoch = 0; + _res = plc4c_spi_read_unsigned_long(readBuffer, 64, (uint64_t*) &nanosecondsSinceEpoch); + if(_res != OK) { + return _res; + } + + *data_item = plc4c_data_create_date_and_ltime_data(nanosecondsSinceEpoch); + + } else if(strcmp(dataProtocolId, "IEC61131_DTL") == 0) { /* DATE_AND_LTIME */ + + // Simple Field (year) + uint16_t year = 0; + _res = plc4c_spi_read_unsigned_short(readBuffer, 16, (uint16_t*) &year); + if(_res != OK) { + return _res; + } + + *data_item = plc4c_data_create_date_and_ltime_data(year); + + + // Simple Field (month) + uint8_t month = 0; + _res = plc4c_spi_read_unsigned_byte(readBuffer, 8, (uint8_t*) &month); + if(_res != OK) { + return _res; + } + + *data_item = plc4c_data_create_date_and_ltime_data(month); + + + // Simple Field (day) + uint8_t day = 0; + _res = plc4c_spi_read_unsigned_byte(readBuffer, 8, (uint8_t*) &day); + if(_res != OK) { + return _res; + } + + *data_item = plc4c_data_create_date_and_ltime_data(day); + + + // Simple Field (dayOfWeek) + uint8_t dayOfWeek = 0; + _res = plc4c_spi_read_unsigned_byte(readBuffer, 8, (uint8_t*) &dayOfWeek); + if(_res != OK) { + return _res; + } + + *data_item = plc4c_data_create_date_and_ltime_data(dayOfWeek); + + + // Simple Field (hour) + uint8_t hour = 0; + _res = plc4c_spi_read_unsigned_byte(readBuffer, 8, (uint8_t*) &hour); + if(_res != OK) { + return _res; + } + + *data_item = plc4c_data_create_date_and_ltime_data(hour); + + + // Simple Field (minutes) + uint8_t minutes = 0; + _res = plc4c_spi_read_unsigned_byte(readBuffer, 8, (uint8_t*) &minutes); + if(_res != OK) { + return _res; + } + + *data_item = plc4c_data_create_date_and_ltime_data(minutes); + + + // Simple Field (seconds) + uint8_t seconds = 0; + _res = plc4c_spi_read_unsigned_byte(readBuffer, 8, (uint8_t*) &seconds); + if(_res != OK) { + return _res; + } + + *data_item = plc4c_data_create_date_and_ltime_data(seconds); + + + // Simple Field (nannosecondsOfSecond) + uint32_t nannosecondsOfSecond = 0; + _res = plc4c_spi_read_unsigned_int(readBuffer, 32, (uint32_t*) &nannosecondsOfSecond); + if(_res != OK) { + return _res; + } + + *data_item = plc4c_data_create_date_and_ltime_data(nannosecondsOfSecond); + } return OK; @@ -597,6 +689,62 @@ plc4c_return_code plc4c_s7_read_write_data_item_serialize(plc4x_spi_context ctx, if(_res != OK) { return _res; } + } else if(strcmp(dataProtocolId, "IEC61131_DATE_AND_LTIME") == 0) { /* DATE_AND_LTIME */ + + // Simple field (nanosecondsSinceEpoch) + _res = plc4c_spi_write_unsigned_long(writeBuffer, 64, (*data_item)->data.date_and_ltime_value); + if(_res != OK) { + return _res; + } + } else if(strcmp(dataProtocolId, "IEC61131_DTL") == 0) { /* DATE_AND_LTIME */ + + // Simple field (year) + _res = plc4c_spi_write_unsigned_short(writeBuffer, 16, (*data_item)->data.date_and_ltime_value); + if(_res != OK) { + return _res; + } + + // Simple field (month) + _res = plc4c_spi_write_unsigned_byte(writeBuffer, 8, (*data_item)->data.date_and_ltime_value); + if(_res != OK) { + return _res; + } + + // Simple field (day) + _res = plc4c_spi_write_unsigned_byte(writeBuffer, 8, (*data_item)->data.date_and_ltime_value); + if(_res != OK) { + return _res; + } + + // Simple field (dayOfWeek) + _res = plc4c_spi_write_unsigned_byte(writeBuffer, 8, (*data_item)->data.date_and_ltime_value); + if(_res != OK) { + return _res; + } + + // Simple field (hour) + _res = plc4c_spi_write_unsigned_byte(writeBuffer, 8, (*data_item)->data.date_and_ltime_value); + if(_res != OK) { + return _res; + } + + // Simple field (minutes) + _res = plc4c_spi_write_unsigned_byte(writeBuffer, 8, (*data_item)->data.date_and_ltime_value); + if(_res != OK) { + return _res; + } + + // Simple field (seconds) + _res = plc4c_spi_write_unsigned_byte(writeBuffer, 8, (*data_item)->data.date_and_ltime_value); + if(_res != OK) { + return _res; + } + + // Simple field (nannosecondsOfSecond) + _res = plc4c_spi_write_unsigned_int(writeBuffer, 32, (*data_item)->data.date_and_ltime_value); + if(_res != OK) { + return _res; + } } return OK; } @@ -735,6 +883,35 @@ uint16_t plc4c_s7_read_write_data_item_length_in_bits(plc4x_spi_context ctx, plc // Simple field (dayOfWeek) lengthInBits += 4; + } else if(strcmp(dataProtocolId, "IEC61131_DATE_AND_LTIME") == 0) { /* DATE_AND_LTIME */ + + // Simple field (nanosecondsSinceEpoch) + lengthInBits += 64; + } else if(strcmp(dataProtocolId, "IEC61131_DTL") == 0) { /* DATE_AND_LTIME */ + + // Simple field (year) + lengthInBits += 16; + + // Simple field (month) + lengthInBits += 8; + + // Simple field (day) + lengthInBits += 8; + + // Simple field (dayOfWeek) + lengthInBits += 8; + + // Simple field (hour) + lengthInBits += 8; + + // Simple field (minutes) + lengthInBits += 8; + + // Simple field (seconds) + lengthInBits += 8; + + // Simple field (nannosecondsOfSecond) + lengthInBits += 32; } return lengthInBits; } diff --git a/plc4c/generated-sources/s7/src/transport_size.c b/plc4c/generated-sources/s7/src/transport_size.c index 49621fb23a8..1829066f7d6 100644 --- a/plc4c/generated-sources/s7/src/transport_size.c +++ b/plc4c/generated-sources/s7/src/transport_size.c @@ -149,15 +149,12 @@ plc4c_s7_read_write_transport_size plc4c_s7_read_write_transport_size_value_of(c if(strcmp(value_string, "DT") == 0) { return plc4c_s7_read_write_transport_size_DT; } - if(strcmp(value_string, "LDATE_AND_TIME") == 0) { - return plc4c_s7_read_write_transport_size_LDATE_AND_TIME; + if(strcmp(value_string, "DATE_AND_LTIME") == 0) { + return plc4c_s7_read_write_transport_size_DATE_AND_LTIME; } if(strcmp(value_string, "LDT") == 0) { return plc4c_s7_read_write_transport_size_LDT; } - if(strcmp(value_string, "DATE_AND_LTIME") == 0) { - return plc4c_s7_read_write_transport_size_DATE_AND_LTIME; - } if(strcmp(value_string, "DTL") == 0) { return plc4c_s7_read_write_transport_size_DTL; } @@ -165,7 +162,7 @@ plc4c_s7_read_write_transport_size plc4c_s7_read_write_transport_size_value_of(c } int plc4c_s7_read_write_transport_size_num_values() { - return 33; + return 32; } plc4c_s7_read_write_transport_size plc4c_s7_read_write_transport_size_value_for_index(int index) { @@ -258,15 +255,12 @@ plc4c_s7_read_write_transport_size plc4c_s7_read_write_transport_size_value_for_ return plc4c_s7_read_write_transport_size_DT; } case 29: { - return plc4c_s7_read_write_transport_size_LDATE_AND_TIME; + return plc4c_s7_read_write_transport_size_DATE_AND_LTIME; } case 30: { return plc4c_s7_read_write_transport_size_LDT; } case 31: { - return plc4c_s7_read_write_transport_size_DATE_AND_LTIME; - } - case 32: { return plc4c_s7_read_write_transport_size_DTL; } default: { @@ -364,17 +358,14 @@ bool plc4c_s7_read_write_transport_size_get_supported__s7_300(plc4c_s7_read_writ case plc4c_s7_read_write_transport_size_DT: { /* '0x1D' */ return true; } - case plc4c_s7_read_write_transport_size_LDATE_AND_TIME: { /* '0x1E' */ + case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x1E' */ return false; } case plc4c_s7_read_write_transport_size_LDT: { /* '0x1F' */ return false; } - case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x20' */ - return false; - } case plc4c_s7_read_write_transport_size_DTL: { /* '0x21' */ - return true; + return false; } default: { return 0; @@ -479,15 +470,12 @@ bool plc4c_s7_read_write_transport_size_get_supported__logo(plc4c_s7_read_write_ case plc4c_s7_read_write_transport_size_DT: { /* '0x1D' */ return false; } - case plc4c_s7_read_write_transport_size_LDATE_AND_TIME: { /* '0x1E' */ + case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x1E' */ return false; } case plc4c_s7_read_write_transport_size_LDT: { /* '0x1F' */ return false; } - case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x20' */ - return false; - } case plc4c_s7_read_write_transport_size_DTL: { /* '0x21' */ return false; } @@ -594,15 +582,12 @@ uint8_t plc4c_s7_read_write_transport_size_get_code(plc4c_s7_read_write_transpor case plc4c_s7_read_write_transport_size_DT: { /* '0x1D' */ return 0; } - case plc4c_s7_read_write_transport_size_LDATE_AND_TIME: { /* '0x1E' */ + case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x1E' */ return 0; } case plc4c_s7_read_write_transport_size_LDT: { /* '0x1F' */ return 0; } - case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x20' */ - return 0; - } case plc4c_s7_read_write_transport_size_DTL: { /* '0x21' */ return 0; } @@ -742,15 +727,12 @@ uint8_t plc4c_s7_read_write_transport_size_get_size_in_bytes(plc4c_s7_read_write case plc4c_s7_read_write_transport_size_DT: { /* '0x1D' */ return 8; } - case plc4c_s7_read_write_transport_size_LDATE_AND_TIME: { /* '0x1E' */ + case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x1E' */ return 8; } case plc4c_s7_read_write_transport_size_LDT: { /* '0x1F' */ return 8; } - case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x20' */ - return 8; - } case plc4c_s7_read_write_transport_size_DTL: { /* '0x21' */ return 12; } @@ -872,17 +854,14 @@ bool plc4c_s7_read_write_transport_size_get_supported__s7_400(plc4c_s7_read_writ case plc4c_s7_read_write_transport_size_DT: { /* '0x1D' */ return true; } - case plc4c_s7_read_write_transport_size_LDATE_AND_TIME: { /* '0x1E' */ + case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x1E' */ return false; } case plc4c_s7_read_write_transport_size_LDT: { /* '0x1F' */ return false; } - case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x20' */ - return false; - } case plc4c_s7_read_write_transport_size_DTL: { /* '0x21' */ - return true; + return false; } default: { return 0; @@ -987,17 +966,14 @@ bool plc4c_s7_read_write_transport_size_get_supported__s7_1200(plc4c_s7_read_wri case plc4c_s7_read_write_transport_size_DT: { /* '0x1D' */ return false; } - case plc4c_s7_read_write_transport_size_LDATE_AND_TIME: { /* '0x1E' */ + case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x1E' */ return false; } case plc4c_s7_read_write_transport_size_LDT: { /* '0x1F' */ return false; } - case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x20' */ - return true; - } case plc4c_s7_read_write_transport_size_DTL: { /* '0x21' */ - return false; + return true; } default: { return 0; @@ -1102,15 +1078,12 @@ uint8_t plc4c_s7_read_write_transport_size_get_short_name(plc4c_s7_read_write_tr case plc4c_s7_read_write_transport_size_DT: { /* '0x1D' */ return 'X'; } - case plc4c_s7_read_write_transport_size_LDATE_AND_TIME: { /* '0x1E' */ + case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x1E' */ return 'X'; } case plc4c_s7_read_write_transport_size_LDT: { /* '0x1F' */ return 'X'; } - case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x20' */ - return 'X'; - } case plc4c_s7_read_write_transport_size_DTL: { /* '0x21' */ return 'X'; } @@ -1229,15 +1202,12 @@ bool plc4c_s7_read_write_transport_size_get_supported__s7_1500(plc4c_s7_read_wri case plc4c_s7_read_write_transport_size_DT: { /* '0x1D' */ return true; } - case plc4c_s7_read_write_transport_size_LDATE_AND_TIME: { /* '0x1E' */ + case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x1E' */ return true; } case plc4c_s7_read_write_transport_size_LDT: { /* '0x1F' */ return true; } - case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x20' */ - return true; - } case plc4c_s7_read_write_transport_size_DTL: { /* '0x21' */ return true; } @@ -1344,15 +1314,12 @@ plc4c_s7_read_write_data_transport_size plc4c_s7_read_write_transport_size_get_d case plc4c_s7_read_write_transport_size_DT: { /* '0x1D' */ return plc4c_s7_read_write_data_transport_size_BYTE_WORD_DWORD; } - case plc4c_s7_read_write_transport_size_LDATE_AND_TIME: { /* '0x1E' */ + case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x1E' */ return plc4c_s7_read_write_data_transport_size_BYTE_WORD_DWORD; } case plc4c_s7_read_write_transport_size_LDT: { /* '0x1F' */ return plc4c_s7_read_write_data_transport_size_BYTE_WORD_DWORD; } - case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x20' */ - return plc4c_s7_read_write_data_transport_size_BYTE_WORD_DWORD; - } case plc4c_s7_read_write_transport_size_DTL: { /* '0x21' */ return plc4c_s7_read_write_data_transport_size_BYTE_WORD_DWORD; } @@ -1474,17 +1441,14 @@ char* plc4c_s7_read_write_transport_size_get_data_protocol_id(plc4c_s7_read_writ case plc4c_s7_read_write_transport_size_DT: { /* '0x1D' */ return "IEC61131_DATE_AND_TIME"; } - case plc4c_s7_read_write_transport_size_LDATE_AND_TIME: { /* '0x1E' */ - return "IEC61131_LDATE_AND_TIME"; + case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x1E' */ + return "IEC61131_DATE_AND_LTIME"; } case plc4c_s7_read_write_transport_size_LDT: { /* '0x1F' */ - return "IEC61131_LDATE_AND_TIME"; - } - case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x20' */ return "IEC61131_DATE_AND_LTIME"; } case plc4c_s7_read_write_transport_size_DTL: { /* '0x21' */ - return "IEC61131_DATE_AND_LTIME"; + return "IEC61131_DTL"; } default: { return 0; @@ -1514,15 +1478,15 @@ plc4c_s7_read_write_transport_size plc4c_s7_read_write_transport_size_get_first_ if (strcmp(value, "IEC61131_DINT") == 0) { return plc4c_s7_read_write_transport_size_DINT; } + if (strcmp(value, "IEC61131_DTL") == 0) { + return plc4c_s7_read_write_transport_size_DTL; + } if (strcmp(value, "IEC61131_DWORD") == 0) { return plc4c_s7_read_write_transport_size_DWORD; } if (strcmp(value, "IEC61131_INT") == 0) { return plc4c_s7_read_write_transport_size_INT; } - if (strcmp(value, "IEC61131_LDATE_AND_TIME") == 0) { - return plc4c_s7_read_write_transport_size_LDATE_AND_TIME; - } if (strcmp(value, "IEC61131_LINT") == 0) { return plc4c_s7_read_write_transport_size_LINT; } @@ -1668,15 +1632,12 @@ plc4c_s7_read_write_transport_size plc4c_s7_read_write_transport_size_get_base_t case plc4c_s7_read_write_transport_size_DT: { /* '0x1D' */ return -1; } - case plc4c_s7_read_write_transport_size_LDATE_AND_TIME: { /* '0x1E' */ + case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x1E' */ return -1; } case plc4c_s7_read_write_transport_size_LDT: { /* '0x1F' */ return -1; } - case plc4c_s7_read_write_transport_size_DATE_AND_LTIME: { /* '0x20' */ - return -1; - } case plc4c_s7_read_write_transport_size_DTL: { /* '0x21' */ return -1; } diff --git a/plc4c/spi/include/plc4c/spi/types_private.h b/plc4c/spi/include/plc4c/spi/types_private.h index b3ec2bde74b..660301ca359 100644 --- a/plc4c/spi/include/plc4c/spi/types_private.h +++ b/plc4c/spi/include/plc4c/spi/types_private.h @@ -255,6 +255,7 @@ struct plc4c_data_t { uint64_t ltime_of_day_value; uint32_t date_and_time_value; uint64_t ldate_and_time_value; + uint64_t date_and_ltime_value; char char_value; wchar_t wchar_value; diff --git a/plc4c/spi/src/data.c b/plc4c/spi/src/data.c index d04b6cfb671..893a4c9b706 100644 --- a/plc4c/spi/src/data.c +++ b/plc4c/spi/src/data.c @@ -336,6 +336,16 @@ plc4c_data *plc4c_data_create_ldate_and_time_array(uint64_t *nanosecondsSinceEpo return NULL; } +plc4c_data *plc4c_data_create_date_and_ltime_data(uint64_t nanosecondsSinceEpoch) { + // TODO: Implement + return NULL; +} + +plc4c_data *plc4c_data_create_date_and_ltime_array(uint64_t *nanosecondsSinceEpoch, int nItems) { + // TODO: Implement + return NULL; +} + plc4c_data *plc4c_data_create_string_data(unsigned int size, char *s) { plc4c_data *data = malloc(sizeof(plc4c_data)); data->data_type = PLC4C_STRING; diff --git a/plc4go/protocols/s7/readwrite/model/DataItem.go b/plc4go/protocols/s7/readwrite/model/DataItem.go index 2687e71ed21..90a2c6d48dd 100644 --- a/plc4go/protocols/s7/readwrite/model/DataItem.go +++ b/plc4go/protocols/s7/readwrite/model/DataItem.go @@ -293,6 +293,64 @@ func DataItemParseWithBuffer(ctx context.Context, readBuffer utils.ReadBuffer, d return nil, errors.Wrap(_dayOfWeekErr, "Error parsing 'dayOfWeek' field") } readBuffer.CloseContext("DataItem") + case dataProtocolId == "IEC61131_DATE_AND_LTIME": // DATE_AND_LTIME + // Simple Field (nanosecondsSinceEpoch) + _, _nanosecondsSinceEpochErr := readBuffer.ReadUint64("nanosecondsSinceEpoch", 64) + if _nanosecondsSinceEpochErr != nil { + return nil, errors.Wrap(_nanosecondsSinceEpochErr, "Error parsing 'nanosecondsSinceEpoch' field") + } + readBuffer.CloseContext("DataItem") + return values.NewPlcDATE_AND_LTIME(value), nil + case dataProtocolId == "IEC61131_DTL": // DATE_AND_LTIME + // Simple Field (year) + _, _yearErr := readBuffer.ReadUint16("year", 16) + if _yearErr != nil { + return nil, errors.Wrap(_yearErr, "Error parsing 'year' field") + } + + // Simple Field (month) + _, _monthErr := readBuffer.ReadUint8("month", 8) + if _monthErr != nil { + return nil, errors.Wrap(_monthErr, "Error parsing 'month' field") + } + + // Simple Field (day) + _, _dayErr := readBuffer.ReadUint8("day", 8) + if _dayErr != nil { + return nil, errors.Wrap(_dayErr, "Error parsing 'day' field") + } + + // Simple Field (dayOfWeek) + _, _dayOfWeekErr := readBuffer.ReadUint8("dayOfWeek", 8) + if _dayOfWeekErr != nil { + return nil, errors.Wrap(_dayOfWeekErr, "Error parsing 'dayOfWeek' field") + } + + // Simple Field (hour) + _, _hourErr := readBuffer.ReadUint8("hour", 8) + if _hourErr != nil { + return nil, errors.Wrap(_hourErr, "Error parsing 'hour' field") + } + + // Simple Field (minutes) + _, _minutesErr := readBuffer.ReadUint8("minutes", 8) + if _minutesErr != nil { + return nil, errors.Wrap(_minutesErr, "Error parsing 'minutes' field") + } + + // Simple Field (seconds) + _, _secondsErr := readBuffer.ReadUint8("seconds", 8) + if _secondsErr != nil { + return nil, errors.Wrap(_secondsErr, "Error parsing 'seconds' field") + } + + // Simple Field (nannosecondsOfSecond) + _, _nannosecondsOfSecondErr := readBuffer.ReadUint32("nannosecondsOfSecond", 32) + if _nannosecondsOfSecondErr != nil { + return nil, errors.Wrap(_nannosecondsOfSecondErr, "Error parsing 'nannosecondsOfSecond' field") + } + readBuffer.CloseContext("DataItem") + return values.NewPlcDATE_AND_LTIME(value), nil } // TODO: add more info which type it is actually return nil, errors.New("unsupported type") @@ -496,6 +554,51 @@ func DataItemSerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.Wri if _err := writeBuffer.WriteUint8("dayOfWeek", 4, uint8(value.(values.PlcDATE_AND_TIME).GetDayOfWeek())); _err != nil { return errors.Wrap(_err, "Error serializing 'dayOfWeek' field") } + case dataProtocolId == "IEC61131_DATE_AND_LTIME": // DATE_AND_LTIME + // Simple Field (nanosecondsSinceEpoch) + if _err := writeBuffer.WriteUint64("nanosecondsSinceEpoch", 64, uint64(value.GetUint64())); _err != nil { + return errors.Wrap(_err, "Error serializing 'nanosecondsSinceEpoch' field") + } + case dataProtocolId == "IEC61131_DTL": // DATE_AND_LTIME + // Simple Field (year) + if _err := writeBuffer.WriteUint16("year", 16, uint16(value.GetUint16())); _err != nil { + return errors.Wrap(_err, "Error serializing 'year' field") + } + + // Simple Field (month) + if _err := writeBuffer.WriteUint8("month", 8, uint8(value.GetUint8())); _err != nil { + return errors.Wrap(_err, "Error serializing 'month' field") + } + + // Simple Field (day) + if _err := writeBuffer.WriteUint8("day", 8, uint8(value.GetUint8())); _err != nil { + return errors.Wrap(_err, "Error serializing 'day' field") + } + + // Simple Field (dayOfWeek) + if _err := writeBuffer.WriteUint8("dayOfWeek", 8, uint8(value.GetUint8())); _err != nil { + return errors.Wrap(_err, "Error serializing 'dayOfWeek' field") + } + + // Simple Field (hour) + if _err := writeBuffer.WriteUint8("hour", 8, uint8(value.GetUint8())); _err != nil { + return errors.Wrap(_err, "Error serializing 'hour' field") + } + + // Simple Field (minutes) + if _err := writeBuffer.WriteUint8("minutes", 8, uint8(value.GetUint8())); _err != nil { + return errors.Wrap(_err, "Error serializing 'minutes' field") + } + + // Simple Field (seconds) + if _err := writeBuffer.WriteUint8("seconds", 8, uint8(value.GetUint8())); _err != nil { + return errors.Wrap(_err, "Error serializing 'seconds' field") + } + + // Simple Field (nannosecondsOfSecond) + if _err := writeBuffer.WriteUint32("nannosecondsOfSecond", 32, uint32(value.GetUint32())); _err != nil { + return errors.Wrap(_err, "Error serializing 'nannosecondsOfSecond' field") + } default: // TODO: add more info which type it is actually return errors.New("unsupported type") diff --git a/plc4go/protocols/s7/readwrite/model/TransportSize.go b/plc4go/protocols/s7/readwrite/model/TransportSize.go index 9dc69b265a3..8c1af5292ee 100644 --- a/plc4go/protocols/s7/readwrite/model/TransportSize.go +++ b/plc4go/protocols/s7/readwrite/model/TransportSize.go @@ -81,9 +81,8 @@ const ( TransportSize_LTOD TransportSize = 0x1B TransportSize_DATE_AND_TIME TransportSize = 0x1C TransportSize_DT TransportSize = 0x1D - TransportSize_LDATE_AND_TIME TransportSize = 0x1E + TransportSize_DATE_AND_LTIME TransportSize = 0x1E TransportSize_LDT TransportSize = 0x1F - TransportSize_DATE_AND_LTIME TransportSize = 0x20 TransportSize_DTL TransportSize = 0x21 ) @@ -121,9 +120,8 @@ func init() { TransportSize_LTOD, TransportSize_DATE_AND_TIME, TransportSize_DT, - TransportSize_LDATE_AND_TIME, - TransportSize_LDT, TransportSize_DATE_AND_LTIME, + TransportSize_LDT, TransportSize_DTL, } } @@ -254,13 +252,9 @@ func (e TransportSize) Supported_S7_300() bool { { /* '0x1F' */ return false } - case 0x20: - { /* '0x20' */ - return false - } case 0x21: { /* '0x21' */ - return true + return false } default: { @@ -404,10 +398,6 @@ func (e TransportSize) Supported_LOGO() bool { { /* '0x1F' */ return false } - case 0x20: - { /* '0x20' */ - return false - } case 0x21: { /* '0x21' */ return false @@ -554,10 +544,6 @@ func (e TransportSize) Code() uint8 { { /* '0x1F' */ return 0x00 } - case 0x20: - { /* '0x20' */ - return 0x00 - } case 0x21: { /* '0x21' */ return 0x00 @@ -704,10 +690,6 @@ func (e TransportSize) SizeInBytes() uint8 { { /* '0x1F' */ return 8 } - case 0x20: - { /* '0x20' */ - return 8 - } case 0x21: { /* '0x21' */ return 12 @@ -854,13 +836,9 @@ func (e TransportSize) Supported_S7_400() bool { { /* '0x1F' */ return false } - case 0x20: - { /* '0x20' */ - return false - } case 0x21: { /* '0x21' */ - return true + return false } default: { @@ -1004,13 +982,9 @@ func (e TransportSize) Supported_S7_1200() bool { { /* '0x1F' */ return false } - case 0x20: - { /* '0x20' */ - return true - } case 0x21: { /* '0x21' */ - return false + return true } default: { @@ -1154,10 +1128,6 @@ func (e TransportSize) ShortName() uint8 { { /* '0x1F' */ return 'X' } - case 0x20: - { /* '0x20' */ - return 'X' - } case 0x21: { /* '0x21' */ return 'X' @@ -1304,10 +1274,6 @@ func (e TransportSize) Supported_S7_1500() bool { { /* '0x1F' */ return true } - case 0x20: - { /* '0x20' */ - return true - } case 0x21: { /* '0x21' */ return true @@ -1454,10 +1420,6 @@ func (e TransportSize) DataTransportSize() DataTransportSize { { /* '0x1F' */ return DataTransportSize_BYTE_WORD_DWORD } - case 0x20: - { /* '0x20' */ - return DataTransportSize_BYTE_WORD_DWORD - } case 0x21: { /* '0x21' */ return DataTransportSize_BYTE_WORD_DWORD @@ -1598,19 +1560,15 @@ func (e TransportSize) DataProtocolId() string { } case 0x1E: { /* '0x1E' */ - return "IEC61131_LDATE_AND_TIME" + return "IEC61131_DATE_AND_LTIME" } case 0x1F: { /* '0x1F' */ - return "IEC61131_LDATE_AND_TIME" - } - case 0x20: - { /* '0x20' */ return "IEC61131_DATE_AND_LTIME" } case 0x21: { /* '0x21' */ - return "IEC61131_DATE_AND_LTIME" + return "IEC61131_DTL" } default: { @@ -1754,10 +1712,6 @@ func (e TransportSize) BaseType() TransportSize { { /* '0x1F' */ return 0 } - case 0x20: - { /* '0x20' */ - return 0 - } case 0x21: { /* '0x21' */ return 0 @@ -1838,11 +1792,9 @@ func TransportSizeByValue(value uint8) (enum TransportSize, ok bool) { case 0x1D: return TransportSize_DT, true case 0x1E: - return TransportSize_LDATE_AND_TIME, true + return TransportSize_DATE_AND_LTIME, true case 0x1F: return TransportSize_LDT, true - case 0x20: - return TransportSize_DATE_AND_LTIME, true case 0x21: return TransportSize_DTL, true } @@ -1909,12 +1861,10 @@ func TransportSizeByName(value string) (enum TransportSize, ok bool) { return TransportSize_DATE_AND_TIME, true case "DT": return TransportSize_DT, true - case "LDATE_AND_TIME": - return TransportSize_LDATE_AND_TIME, true - case "LDT": - return TransportSize_LDT, true case "DATE_AND_LTIME": return TransportSize_DATE_AND_LTIME, true + case "LDT": + return TransportSize_LDT, true case "DTL": return TransportSize_DTL, true } @@ -2042,12 +1992,10 @@ func (e TransportSize) PLC4XEnumName() string { return "DATE_AND_TIME" case TransportSize_DT: return "DT" - case TransportSize_LDATE_AND_TIME: - return "LDATE_AND_TIME" - case TransportSize_LDT: - return "LDT" case TransportSize_DATE_AND_LTIME: return "DATE_AND_LTIME" + case TransportSize_LDT: + return "LDT" case TransportSize_DTL: return "DTL" } diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/types/PlcValueType.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/types/PlcValueType.java index 18b3eca4a55..fd2f89360d0 100644 --- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/types/PlcValueType.java +++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/types/PlcValueType.java @@ -57,7 +57,8 @@ public enum PlcValueType { TIME_OF_DAY((short) 0x55, LocalTime.class), LTIME_OF_DAY((short) 0x56, LocalTime.class), DATE_AND_TIME((short) 0x57, LocalDateTime.class), - LDATE_AND_TIME((short) 0x58, LocalDateTime.class), + DATE_AND_LTIME((short) 0x58, LocalDateTime.class), + LDATE_AND_TIME((short) 0x59, LocalDateTime.class), Struct((short) 0x61, HashMap.class), List((short) 0x62, ArrayList.class), RAW_BYTE_ARRAY((short) 0x71, Byte.class); diff --git a/plc4j/drivers/ads/src/main/generated/org/apache/plc4x/java/ads/readwrite/DataItem.java b/plc4j/drivers/ads/src/main/generated/org/apache/plc4x/java/ads/readwrite/DataItem.java index 95b5ea32499..4699f1e21f6 100644 --- a/plc4j/drivers/ads/src/main/generated/org/apache/plc4x/java/ads/readwrite/DataItem.java +++ b/plc4j/drivers/ads/src/main/generated/org/apache/plc4x/java/ads/readwrite/DataItem.java @@ -385,9 +385,7 @@ public static void staticSerialize( "nanosecondsSinceEpoch", (BigInteger) BigInteger.valueOf( - _value - .getDateTime() - .toEpochSecond(ZoneOffset.of(ZoneId.systemDefault().getId()))) + _value.getDateTime().toEpochSecond(OffsetDateTime.now().getOffset())) .multiply(BigInteger.valueOf(1000000000)) .add(BigInteger.valueOf(_value.getDateTime().getNano())), writeUnsignedBigInteger(writeBuffer, 64)); @@ -416,9 +414,7 @@ public static void staticSerialize( "nanosecondsSinceEpoch", (BigInteger) BigInteger.valueOf( - _value - .getDateTime() - .toEpochSecond(ZoneOffset.of(ZoneId.systemDefault().getId()))) + _value.getDateTime().toEpochSecond(OffsetDateTime.now().getOffset())) .multiply(BigInteger.valueOf(1000000000)) .add(BigInteger.valueOf(_value.getDateTime().getNano())), writeUnsignedBigInteger(writeBuffer, 64)); diff --git a/plc4j/drivers/plc4x/src/main/generated/org/apache/plc4x/java/plc4x/readwrite/Plc4xValue.java b/plc4j/drivers/plc4x/src/main/generated/org/apache/plc4x/java/plc4x/readwrite/Plc4xValue.java index 226ad000dd8..c5ac66da0b5 100644 --- a/plc4j/drivers/plc4x/src/main/generated/org/apache/plc4x/java/plc4x/readwrite/Plc4xValue.java +++ b/plc4j/drivers/plc4x/src/main/generated/org/apache/plc4x/java/plc4x/readwrite/Plc4xValue.java @@ -320,9 +320,7 @@ public static void staticSerialize( "nanosecondsSinceEpoch", (BigInteger) BigInteger.valueOf( - _value - .getDateTime() - .toEpochSecond(ZoneOffset.of(ZoneId.systemDefault().getId()))) + _value.getDateTime().toEpochSecond(OffsetDateTime.now().getOffset())) .multiply(BigInteger.valueOf(1000000000)) .add(BigInteger.valueOf(_value.getDateTime().getNano())), writeUnsignedBigInteger(writeBuffer, 64)); @@ -351,9 +349,7 @@ public static void staticSerialize( "nanosecondsSinceEpoch", (BigInteger) BigInteger.valueOf( - _value - .getDateTime() - .toEpochSecond(ZoneOffset.of(ZoneId.systemDefault().getId()))) + _value.getDateTime().toEpochSecond(OffsetDateTime.now().getOffset())) .multiply(BigInteger.valueOf(1000000000)) .add(BigInteger.valueOf(_value.getDateTime().getNano())), writeUnsignedBigInteger(writeBuffer, 64)); diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/DataItem.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/DataItem.java index 284ea356a7d..04d2eac486f 100644 --- a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/DataItem.java +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/DataItem.java @@ -212,6 +212,36 @@ public static PlcValue staticParse( minutes, seconds, millisecondsOfSecond); + } else if (EvaluationHelper.equals( + dataProtocolId, (String) "IEC61131_DATE_AND_LTIME")) { // DATE_AND_LTIME + BigInteger nanosecondsSinceEpoch = + readSimpleField("nanosecondsSinceEpoch", readUnsignedBigInteger(readBuffer, 64)); + return PlcDATE_AND_LTIME.ofNanosecondsSinceEpoch(nanosecondsSinceEpoch); + } else if (EvaluationHelper.equals(dataProtocolId, (String) "IEC61131_DTL")) { // DATE_AND_LTIME + int year = readSimpleField("year", readUnsignedInt(readBuffer, 16)); + + short month = readSimpleField("month", readUnsignedShort(readBuffer, 8)); + + short day = readSimpleField("day", readUnsignedShort(readBuffer, 8)); + + short dayOfWeek = readSimpleField("dayOfWeek", readUnsignedShort(readBuffer, 8)); + + short hour = readSimpleField("hour", readUnsignedShort(readBuffer, 8)); + + short minutes = readSimpleField("minutes", readUnsignedShort(readBuffer, 8)); + + short seconds = readSimpleField("seconds", readUnsignedShort(readBuffer, 8)); + + long nannosecondsOfSecond = + readSimpleField("nannosecondsOfSecond", readUnsignedLong(readBuffer, 32)); + return PlcDATE_AND_LTIME.ofSegments( + year, + (month == 0) ? 1 : month, + (day == 0) ? 1 : day, + hour, + minutes, + seconds, + nannosecondsOfSecond); } return null; } @@ -331,6 +361,34 @@ public static int getLengthInBits( // Simple field (dayOfWeek) lengthInBits += 4; + } else if (EvaluationHelper.equals( + dataProtocolId, (String) "IEC61131_DATE_AND_LTIME")) { // DATE_AND_LTIME + // Simple field (nanosecondsSinceEpoch) + lengthInBits += 64; + } else if (EvaluationHelper.equals(dataProtocolId, (String) "IEC61131_DTL")) { // DATE_AND_LTIME + // Simple field (year) + lengthInBits += 16; + + // Simple field (month) + lengthInBits += 8; + + // Simple field (day) + lengthInBits += 8; + + // Simple field (dayOfWeek) + lengthInBits += 8; + + // Simple field (hour) + lengthInBits += 8; + + // Simple field (minutes) + lengthInBits += 8; + + // Simple field (seconds) + lengthInBits += 8; + + // Simple field (nannosecondsOfSecond) + lengthInBits += 32; } return lengthInBits; @@ -538,6 +596,52 @@ public static void staticSerialize( (byte) _value.getDate().getDayOfWeek().getValue(), writeUnsignedByte(writeBuffer, 4), WithOption.WithEncoding("BCD")); + } else if (EvaluationHelper.equals( + dataProtocolId, (String) "IEC61131_DATE_AND_LTIME")) { // DATE_AND_LTIME + // Simple Field (nanosecondsSinceEpoch) + writeSimpleField( + "nanosecondsSinceEpoch", + (BigInteger) + BigInteger.valueOf( + _value.getDateTime().toEpochSecond(OffsetDateTime.now().getOffset())) + .multiply(BigInteger.valueOf(1000000000)) + .add(BigInteger.valueOf(_value.getDateTime().getNano())), + writeUnsignedBigInteger(writeBuffer, 64)); + } else if (EvaluationHelper.equals(dataProtocolId, (String) "IEC61131_DTL")) { // DATE_AND_LTIME + // Simple Field (year) + writeSimpleField("year", (int) _value.getDate().getYear(), writeUnsignedInt(writeBuffer, 16)); + + // Simple Field (month) + writeSimpleField( + "month", (short) _value.getDate().getMonthValue(), writeUnsignedShort(writeBuffer, 8)); + + // Simple Field (day) + writeSimpleField( + "day", (short) _value.getDate().getDayOfMonth(), writeUnsignedShort(writeBuffer, 8)); + + // Simple Field (dayOfWeek) + writeSimpleField( + "dayOfWeek", + (short) _value.getDate().getDayOfWeek().getValue(), + writeUnsignedShort(writeBuffer, 8)); + + // Simple Field (hour) + writeSimpleField( + "hour", (short) _value.getTime().getHour(), writeUnsignedShort(writeBuffer, 8)); + + // Simple Field (minutes) + writeSimpleField( + "minutes", (short) _value.getTime().getMinute(), writeUnsignedShort(writeBuffer, 8)); + + // Simple Field (seconds) + writeSimpleField( + "seconds", (short) _value.getTime().getSecond(), writeUnsignedShort(writeBuffer, 8)); + + // Simple Field (nannosecondsOfSecond) + writeSimpleField( + "nannosecondsOfSecond", + (long) _value.getTime().getLong(ChronoField.NANO_OF_SECOND), + writeUnsignedLong(writeBuffer, 32)); } } } diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/TransportSize.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/TransportSize.java index cb2f198611d..61f68f789c9 100644 --- a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/TransportSize.java +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/TransportSize.java @@ -403,7 +403,7 @@ public enum TransportSize { DataTransportSize.BYTE_WORD_DWORD, (String) "IEC61131_DATE_AND_TIME", null), - LDATE_AND_TIME( + DATE_AND_LTIME( (short) 0x1E, (boolean) false, (boolean) false, @@ -414,7 +414,7 @@ public enum TransportSize { (short) 'X', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, - (String) "IEC61131_LDATE_AND_TIME", + (String) "IEC61131_DATE_AND_LTIME", null), LDT( (short) 0x1F, @@ -427,33 +427,20 @@ public enum TransportSize { (short) 'X', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, - (String) "IEC61131_LDATE_AND_TIME", - null), - DATE_AND_LTIME( - (short) 0x20, - (boolean) false, - (boolean) false, - (short) 0x00, - (short) 8, - (boolean) false, - (boolean) true, - (short) 'X', - (boolean) true, - DataTransportSize.BYTE_WORD_DWORD, (String) "IEC61131_DATE_AND_LTIME", null), DTL( (short) 0x21, - (boolean) true, + (boolean) false, (boolean) false, (short) 0x00, (short) 12, - (boolean) true, (boolean) false, + (boolean) true, (short) 'X', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, - (String) "IEC61131_DATE_AND_LTIME", + (String) "IEC61131_DTL", null); private static final Map map; diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java index a9d6cad926e..26bee485354 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java @@ -1758,7 +1758,7 @@ private PlcResponse decodeReadResponse(S7Message responseMessage, PlcReadRequest } List plcValues = new LinkedList<>(); - plcValues.add(PlcLDATE_AND_TIME.of(LocalDateTime.of( + plcValues.add(PlcDATE_AND_LTIME.of(LocalDateTime.of( dt.getYear() + 2000, dt.getMonth(), dt.getDay(), diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7Tag.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7Tag.java index c026119fc44..20baed67994 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7Tag.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7Tag.java @@ -89,9 +89,17 @@ public String getAddressString() { @Override public PlcValueType getPlcValueType() { - //S5TIME is a specific type of Simatic S5/S7. - String name = dataType.name().equals("S5TIME")?"TIME":dataType.name(); - return PlcValueType.valueOf(name); + // Translate non-standard tag names. + switch (dataType.name()) { + case "S5TIME": + return PlcValueType.TIME; + case "LDT": + return PlcValueType.DATE_AND_LTIME; + case "DTL": + return PlcValueType.DATE_AND_LTIME; + default: + return PlcValueType.valueOf(dataType.name()); + } } @Override diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java index 2c06743c038..76c65b5e8ff 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java @@ -2581,7 +2581,6 @@ public static Long parseS5Time(ReadBuffer io) { public static void serializeS5Time(final WriteBuffer io, PlcValue value) { final PlcTIME time = (PlcTIME) value; Short shortValue = durationToS5Time(time.getDuration()); - System.out.println(">>>TIPO: " + value.getClass().getName() + " : " + shortValue); try { io.writeUnsignedInt(16,shortValue); } catch (SerializationException e) { diff --git a/plc4j/drivers/s7/src/test/java/org/apache/plc4x/java/s7/readwrite/ManualS71500DriverTest.java b/plc4j/drivers/s7/src/test/java/org/apache/plc4x/java/s7/readwrite/ManualS71500DriverTest.java index 89705e1f91f..9b72c0b6b37 100644 --- a/plc4j/drivers/s7/src/test/java/org/apache/plc4x/java/s7/readwrite/ManualS71500DriverTest.java +++ b/plc4j/drivers/s7/src/test/java/org/apache/plc4x/java/s7/readwrite/ManualS71500DriverTest.java @@ -21,10 +21,7 @@ import org.apache.plc4x.java.spi.values.*; import org.apache.plc4x.test.manual.ManualTest; -import java.time.Duration; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; +import java.time.*; public class ManualS71500DriverTest extends ManualTest { @@ -62,8 +59,8 @@ public static void main(String[] args) throws Exception { test.addTestCase("%DB1:1612:TIME_OF_DAY", new PlcTIME_OF_DAY(LocalTime.parse("15:36:30.123"))); test.addTestCase("%DB1:1616:LTIME_OF_DAY", new PlcLTIME_OF_DAY(LocalTime.parse("15:36:30"))); test.addTestCase("%DB1:1624:DATE_AND_TIME", new PlcDATE_AND_TIME(LocalDateTime.parse("1996-05-06T15:36:30"))); - //test.addTestCase("%DB1:1632:LDATE_AND_TIME", new PlcLDATE_AND_TIME(LocalDateTime.parse("1978-03-28T15:36:30"))); - //test.addTestCase("%DB1:1632:DATE_AND_LTIME", new PlcDATE_AND_LTIME(LocalDateTime.parse("1978-03-28T15:36:30"))); + test.addTestCase("%DB1:1632:DATE_AND_LTIME", new PlcDATE_AND_LTIME(LocalDateTime.parse("1978-03-28T15:36:30"))); + test.addTestCase("%DB1:1642:DTL", new PlcDATE_AND_LTIME(LocalDateTime.parse("1978-03-28T15:36:30").withNano(34002044))); long start = System.currentTimeMillis(); test.run(); long end = System.currentTimeMillis(); diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcDATE_AND_LTIME.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcDATE_AND_LTIME.java new file mode 100644 index 00000000000..270d9e5112b --- /dev/null +++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcDATE_AND_LTIME.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.plc4x.java.spi.values; + +import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; +import org.apache.plc4x.java.api.types.PlcValueType; +import org.apache.plc4x.java.spi.codegen.WithOption; +import org.apache.plc4x.java.spi.generation.SerializationException; +import org.apache.plc4x.java.spi.generation.WriteBuffer; + +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.time.*; + +public class PlcDATE_AND_LTIME extends PlcSimpleValue { + + public static PlcDATE_AND_LTIME of(Object value) { + if (value instanceof LocalDateTime) { + return new PlcDATE_AND_LTIME((LocalDateTime) value); + } else if (value instanceof Long) { + return new PlcDATE_AND_LTIME(LocalDateTime.ofInstant( + Instant.ofEpochSecond((long) value), ZoneOffset.UTC)); + } else if (value instanceof BigInteger) { + return new PlcDATE_AND_LTIME(LocalDateTime.ofInstant( + Instant.ofEpochSecond(((BigInteger) value).longValue()), ZoneOffset.UTC)); + } + throw new PlcRuntimeException("Invalid value type"); + } + + public static PlcDATE_AND_LTIME ofNanosecondsSinceEpoch(BigInteger nanosecondsSinceEpoch) { + BigInteger epochSecond = nanosecondsSinceEpoch.divide(BigInteger.valueOf(1000000000L)); + BigInteger nanoOfSecond = nanosecondsSinceEpoch.mod(BigInteger.valueOf(1000000000L)); + return new PlcDATE_AND_LTIME(LocalDateTime.ofEpochSecond(epochSecond.longValue(), nanoOfSecond.intValue(), + ZoneOffset.UTC)); + } + + public PlcDATE_AND_LTIME(LocalDateTime value) { + super(value, true); + } + + public PlcDATE_AND_LTIME(BigInteger nanosecondsSinceEpoch) { + super(LocalDateTime.ofEpochSecond(nanosecondsSinceEpoch.divide(BigInteger.valueOf(1000000000L)).longValue(), + nanosecondsSinceEpoch.mod(BigInteger.valueOf(1000000000L)).intValue(), + ZoneOffset.UTC), true); + } + + public static PlcDATE_AND_LTIME ofSegments(int year, int month, int day, int hour, int minutes, int seconds, long nannosecondsOfSecond) { + return new PlcDATE_AND_LTIME(LocalDateTime.of(year, month, day, hour, minutes, seconds, (int) nannosecondsOfSecond)); + } + + @Override + public PlcValueType getPlcValueType() { + return PlcValueType.DATE_AND_LTIME; + } + + public BigInteger getNanosecondsSinceEpoch() { + Instant instant = getDateTime().toInstant(ZoneOffset.UTC); + return BigInteger.valueOf(instant.getEpochSecond()).multiply(BigInteger.valueOf(1000_000_000)).add(BigInteger.valueOf(instant.getNano())); + } + + @Override + public boolean isLong() { + return true; + } + + @Override + public long getLong() { + Instant instant = value.atZone(ZoneOffset.UTC).toInstant(); + return instant.getEpochSecond(); + } + + @Override + public boolean isString() { + return true; + } + + @Override + public String getString() { + return value.toString(); + } + + @Override + public boolean isTime() { + return true; + } + + @Override + public LocalTime getTime() { + return value.toLocalTime(); + } + + @Override + public boolean isDate() { + return true; + } + + @Override + public LocalDate getDate() { + return value.toLocalDate(); + } + + @Override + public boolean isDateTime() { + return true; + } + + @Override + public LocalDateTime getDateTime() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @Override + public void serialize(WriteBuffer writeBuffer) throws SerializationException { + String valueString = value.toString(); + writeBuffer.writeString(getClass().getSimpleName(), + valueString.getBytes(StandardCharsets.UTF_8).length*8, + valueString, WithOption.WithEncoding(StandardCharsets.UTF_8.name())); + } + +} diff --git a/protocols/s7/src/main/resources/protocols/s7/s7.mspec b/protocols/s7/src/main/resources/protocols/s7/s7.mspec index dc8d3f14da7..5e7ef2888b0 100644 --- a/protocols/s7/src/main/resources/protocols/s7/s7.mspec +++ b/protocols/s7/src/main/resources/protocols/s7/s7.mspec @@ -817,13 +817,28 @@ // Half a byte with one 4-bit value representing 1 - 7 [simple uint 4 dayOfWeek encoding='"BCD"'] ] - // - Date & Time: Interpreted as "number of nanoseconds since 1990-01-01" - //['"IEC61131_LDATE_AND_TIME"' LDATE_AND_TIME - // [implicit uint 16 nanosecondsSinceSiemensEpoch 'nanosecondsSinceEpoch ...'] - // [virtual uint 16 nanosecondsSinceEpoch 'nanosecondsSinceSiemensEpoch ...'] - //] - //['"IEC61131_LDT"' DATE_AND_LTIME - //] + // - Date & Time: Interpreted as "number of nanoseconds since 1970-01-01" + ['"IEC61131_DATE_AND_LTIME"' DATE_AND_LTIME + [simple uint 64 nanosecondsSinceEpoch] + ] + ['"IEC61131_DTL"' DATE_AND_LTIME + // One byte with 2 4-bit BCD encoded values representing 90-99 = 1990-1999 and 00-89 = 2000-2089 + [simple uint 16 year ] + // One byte values representing 01(Jan) - 12(Dec) + [simple uint 8 month ] + // One byte representing 01 - 31 + [simple uint 8 day ] + // One byte representing 01 (Sunday) - 07 (Saturday) + [simple uint 8 dayOfWeek ] + // One byte representing 00 - 23 + [simple uint 8 hour ] + // One byte representing 00 - 59 + [simple uint 8 minutes ] + // One byte representing 00 - 59 + [simple uint 8 seconds ] + // Four byte with 3 4-bit values representing 0 - 999 + [simple uint 32 nannosecondsOfSecond ] + ] ] ] @@ -906,10 +921,9 @@ ['0x1B' LTOD ['0x00' , 'X' , '8' , 'null' , 'BYTE_WORD_DWORD' , 'IEC61131_LTIME_OF_DAY' , 'false' , 'false' , 'false' , 'true' , 'true' ]] ['0x1C' DATE_AND_TIME ['0x00' , 'X' , '8' , 'null' , 'BYTE_WORD_DWORD' , 'IEC61131_DATE_AND_TIME' , 'true' , 'true' , 'false' , 'true' , 'false' ]] ['0x1D' DT ['0x00' , 'X' , '8' , 'null' , 'BYTE_WORD_DWORD' , 'IEC61131_DATE_AND_TIME' , 'true' , 'true' , 'false' , 'true' , 'false' ]] - ['0x1E' LDATE_AND_TIME ['0x00' , 'X' , '8' , 'null' , 'BYTE_WORD_DWORD' , 'IEC61131_LDATE_AND_TIME' , 'false' , 'false' , 'false' , 'true' , 'false' ]] - ['0x1F' LDT ['0x00' , 'X' , '8' , 'null' , 'BYTE_WORD_DWORD' , 'IEC61131_LDATE_AND_TIME' , 'false' , 'false' , 'false' , 'true' , 'false' ]] - ['0x20' DATE_AND_LTIME ['0x00' , 'X' , '8' , 'null' , 'BYTE_WORD_DWORD' , 'IEC61131_DATE_AND_LTIME' , 'false' , 'false' , 'true' , 'true' , 'false' ]] - ['0x21' DTL ['0x00' , 'X' , '12' , 'null' , 'BYTE_WORD_DWORD' , 'IEC61131_DATE_AND_LTIME' , 'true' , 'true' , 'false' , 'true' , 'false' ]] + ['0x1E' DATE_AND_LTIME ['0x00' , 'X' , '8' , 'null' , 'BYTE_WORD_DWORD' , 'IEC61131_DATE_AND_LTIME' , 'false' , 'false' , 'false' , 'true' , 'false' ]] + ['0x1F' LDT ['0x00' , 'X' , '8' , 'null' , 'BYTE_WORD_DWORD' , 'IEC61131_DATE_AND_LTIME' , 'false' , 'false' , 'false' , 'true' , 'false' ]] + ['0x21' DTL ['0x00' , 'X' , '12' , 'null' , 'BYTE_WORD_DWORD' , 'IEC61131_DTL' , 'false' , 'false' , 'true' , 'true' , 'false' ]] ] [enum uint 8 MemoryArea(string 24 shortName)