commit 47a0c377abfff05ec4686dc1a2cd5c125b8f3624 Author: Ondřej Hruška Date: Thu Sep 8 22:37:49 2022 +0200 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..91b8835 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +/Cargo.lock +.idea/ diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..f1adf42 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "nep-parser" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +thiserror = "1" +byteorder = "1" +once_cell = "1.14" +log = "0.4" +lazy_static = "1.4" + +[dev-dependencies] +simple-logging = "2" +hex = "0.4" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..a68a414 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,928 @@ +#[macro_use] +extern crate thiserror; +#[macro_use] +extern crate log; + +use std::collections::HashMap; +use std::io::{BufRead, Cursor, Read}; +use byteorder::{BigEndian, ByteOrder, ReadBytesExt}; +use once_cell::sync::Lazy; + +#[derive(Debug, Error)] +pub enum NepError { + #[error("Encrypted message parsing not supported!")] + Encrypted, + #[error(transparent)] + Io(#[from] std::io::Error), +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum NepType { + // "ASCIIZ retezec, zakonceny 0" + STRING = 0, + // "pole byte, ruzne delky" + OCTETS = 1, + // "32 bitove cislo bez znamenka" + UNUMBER = 2, + // "32 bitove cislo se znamenkem" + NUMBER = 3, + // "IP adresa, 4 byte MSB prvni" + IP = 4, + // "IEEE794 floating point format" + FLOAT = 5, + // "?" + OID = 6, + // "nema datovou cast, pro dotazy na stav promenne" + NULL = 7, + // Unknown + INVALID, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum NepValue { + String(String), + Octets(Vec), + Unumber(u32), + Number(i32), + IP([u8; 4]), + Float(f32), + Oid(u16), + Null, + Invalid, +} + +impl From for NepType { + fn from(b: u8) -> Self { + match b { + 0 => Self::STRING, + 1 => Self::OCTETS, + 2 => Self::UNUMBER, + 3 => Self::NUMBER, + 4 => Self::IP, + 5 => Self::FLOAT, + 6 => Self::OID, + 7 => Self::NULL, // wrong but will be good enough + _ => Self::INVALID, + } + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct NepEntry { + pub oid: NepOid, + /// Entry index, NEP uses 1-based indices, 0 indicates no index was specified + pub index: u16, + pub value: NepValue, +} + +pub struct NepOidSpec { + oid: NepOid, + hasindex: bool, + readonly: bool, + neptype: NepType, + name: &'static str, +} + +#[allow(non_camel_case_types)] +#[derive(Debug, Clone, Copy, PartialEq, Hash)] +pub enum NepOid { + NAME = 1, + TYPE = 2, + SUBTYPE = 3, + MANUF = 4, + HWVER = 5, + HWREV = 6, + SWVER = 7, + SWREV = 8, + LOCATION = 9, + CONTACT = 10, + COMMAND = 11, + UPTIME = 12, + SYSTIME = 13, + RESET = 14, + CONFIG = 15, + MANUF_ID = 16, + NEXT_TIMESTAMP = 17, + NEXT_DELTATIME = 18, + ENCRYPTED_BLOCK = 19, + GPS_LATITUDE = 20, + GPS_LONGITUDE = 21, + GPS_ALTITUDE = 22, + BULKCOUNT = 55, + SEND_ALARMS = 56, + NEXT_OID = 57, + AUTORESET_TIMEOUT = 58, + ALARM_CNT = 59, + TRAP_CODE = 60, + SEQ_NUMBER = 61, + SIGNATURE = 62, + MSGTYPE = 63, + CURR_ADDR = 64, + CURR_LEN = 65, + MEMORY = 66, + IOPORTS = 67, + TASKNAME = 70, + TASK_STATE = 71, + TASK_PRIO = 72, + METHANE_THRESHOLD = 81, + METHANE = 82, + ALARM_ON_CODE = 83, + ALARM_OFF_CODE = 84, + TVOC_THRESHOLD = 85, + TVOC = 86, + CO2_THRESHOLD = 87, + CO2 = 88, + CALIBRATION = 89, + HUMIDITY = 90, + HUMIDITY_LOW = 91, + HUMIDITY_HIGH = 92, + AVALUE_Q = 94, + AVALUE_KL = 95, + AVALUE_KH = 96, + AVALUE = 97, + IVALUE_TYPE = 98, + IVALUE_LEVEL = 99, + IVALUE = 100, + IVALUE_MULT = 101, + IVALUE_DIV = 102, + TEMPERATURE_LOW = 103, + TEMPERATURE_HIGH = 104, + TEMPERATURE = 105, + VOLTAGE = 106, + OVALUE = 107, + OVALUE_OFF_TOUT = 108, + SISA_TIMEOUTS = 109, + SLRF_CHANNEL = 110, + SLRF_HOPCOUNT = 111, + SLRF_TIMESLOTS = 112, + SLRF_TIMESLOT = 113, + SLRF_GROUP = 114, + SLRF_MADDRESS = 115, + SLRF_REPEATER = 116, + SLRF_MASTER = 117, + SLRF_ADDRESS = 118, + SLRF_PACKET = 119, + SLRF_RSSI = 120, + SLRF_PROMISCUOUS = 121, + SLRF_CD = 122, + SLRF_TEST = 123, + SLRF_TEST_TIMEOUT = 124, + SLRF_TX_PWR = 125, + SLRF_AADDRESS = 126, + SLRF_WOR = 127, + SLRF_PREAMBLE_LEN = 128, + SLRF_RFA_ACTIVE = 129, + IFC_NAME = 130, + IFC_ADMIN = 131, + IFC_OPER = 132, + IFC_SPEED = 133, + IFC_PARAM = 134, + IFC_TX_ON = 135, + IFC_TX_OFF = 136, + IFC_INTERBYTE_TOUT = 137, + SLRF_DRV_ERROR = 142, + SLRF_WOR_WAKEUP = 143, + SLRF_OUT_ERRORS = 144, + SLRF_IN_ERRORS = 145, + SLRF_OUT_PKTS = 146, + SLRF_IN_PKTS = 147, + SLRF_RFFTC = 148, + SLRF_CRYPT_KEY = 149, + RFT_ADDRESS = 150, + RFT_VALUE = 151, + RF_UDP_DST_PORT = 152, + RF_UDP_SRC_PORT = 153, + RF_DST_IP_ADDR = 154, + UDP_HEARTBEAT = 155, + IPRT_ADDR = 156, + IPRT_MASK = 157, + IPRT_GW = 158, + IPRT_IFC_NAME = 159, + IP_IFC_NAME = 160, + IP_ADDRESS = 161, + IP_MASK = 162, + IP_ADMIN = 163, + IP_OPER = 164, + IP_MTU = 165, + IP_MAC_ADDRESS = 166, + IP_IFC_TYPE = 167, + IFC_START_TIME = 168, + IFC_STTOP_TIME = 169, + SIGFOX_ID = 180, + SIGFOX_PAC = 181, + STORAGE_INTERVAL = 196, + STORAGE_FLOAT = 197, + STORAGE_INT = 198, + STORAGE_TIMESTAMP = 199, + COLL_RF_ADDR = 200, + COLL_RF_RSSI = 201, + COLL_MBUS_ADDR = 205, + COLL_MBUS_ID = 206, + COLL_MBUS_FMT = 207, + COLL_MBUS_MEDIUM = 208, + COLL_MBUS_C1_RFI = 209, + COLL_MBUS_C1_VI = 210, + COLL_MBUS_C2_RFI = 211, + COLL_MBUS_C2_VI = 212, + WMBUS_MODE = 213, + WMBUS_SENDING = 214, + WMBUS_PACKET = 215, + WMBUS_RSSI = 216, + WMBUS_FREQ_RANGE = 217, + WMBUS_CHANNEL = 218, + WMBUS_DATARATE = 219, + WMBUS_FRAME_FORMAT = 220, + WMBUS_RFFTC = 221, + WMBUS_IN_PKTS = 222, + WMBUS_OUT_PKTS = 223, + WMBUS_IN_ERRORS = 224, + WMBUS_OUT_ERRORS = 225, + WMBUS_DRV_ERROR = 226, + WMBUS_POWER = 227, + WMBUS_SENDMODE = 228, + WMBUS_CAPATUN = 229, + MBUS_PRIMARY = 300, + MBUS_SECONDARY = 301, + MBUS_MANUF = 302, + MBUS_VERSION = 303, + MBUS_MEDIUM = 304, + MBUS_ENCRYPT_KEY = 305, + MBUS_ENCRYPT_TYPE = 306, + MBUS_PERIOD = 307, + MBUS_MANUF_NO = 308, + MBUSV_DEV_INDEX = 320, + MBUSV_DIF = 321, + MBUSV_VIF = 322, + MBUSV_OPTO_ID = 326, + MBUSV_OPTO_DECIMAL = 327, + LEAKMEASURETIME = 360, + LEAKCHECKTIME = 361, + LEAKZEROTIME = 362, + BURSTCHECKTIME = 363, + BURSTFLOW = 364, + PROTO_DEVICE = 400, + PROTO_TYPE = 401, + PROTO_SPEED = 402, + PROTO_PARAM = 403, + PROTO_PERIOD = 404, + PROTO_TRANSACTION_TIMEOUT = 405, + PROTO_TRANSACTION_DELAY = 406, + PROTO_ENCRYPTION_KEY = 407, + PROTO_REPEAT = 408, + PROTO_MBUS_PRISEC = 415, + PROTO_MBUS_PRI = 416, + PROTO_MBUS_SEC_ID = 417, + PROTO_OPTO_ADDR = 420, + PROTO_OPTO_MODE = 421, + PROTO_MODBUS_ADDR = 425, + PROTO_MODBUS_MODE = 426, + PROTO_VAR_INDEX = 430, + PROTO_VAR_DIF_VIF = 431, + PROTO_VAR_OPTO = 432, + PROTO_VAR_MODBUS_REGISTER = 433, + PROTO_VAR_MODBUS_FUNC = 434, + PROTO_VAR_MODBUS_TYPE = 435, + PROTO_OUT_OID = 436, + PROTO_OUT_IDX = 437, + PROTO_OUT_DIFVIF = 438, + PROTO_DEC = 439, + ALARM_INDEX = 452, + ALARM_TYPE = 453, + ALARM_BIT = 454, + SEND_MASK = 459, + MODEM_IMEI = 460, + MODEM_CCID = 461, + MODEM_LAST_RSSI = 462, + Modem_APN = 463, + MODEM_PIN = 464, + MODEM_SENDPKT = 465, + MODEM_RECVPKT = 466, + MODEM_IMSI = 467, + MODEM_SESTIMEOUT = 468, + MODEM_FLAGS = 469, + MODEM_TEST_IP = 470, + RADAR_TYPE = 500, + RADAR_IDENT = 501, + RADAR_TIMESTAMP = 502, + RADAR_RSSI = 503, + RADAR_STATUS = 504, + GW_UDP_DST_PORT = 552, + GW_UDP_SRC_PORT = 553, + GW_DST_IP_ADDR = 554, + GW_UDP_HEARTBEAT = 555, + GW_IP_TIMEOUT = 556, + GW_MSG_SENT = 557, + CONFIGVERSION = 600, + CONFIGTYPE = 601, + CONFIGVAL = 602, + EZS1_UPTIME = 1000, + EZS1_MUPC = 1001, + EZS1_MLSF = 1002, + EZS1_MSfAT = 1003, + EZS1_MSFPF = 1004, + EZS1_MGFLG = 1005, + EZS1_MSFLG = 1006, + EZS1_MTFLG = 1007, + EZS1_MSMSI = 1008, + EZS1_MDKEP = 1009, + EZS1_MDKET = 1010, + EZS1_MIDK = 1011, + EZS1_MLVDK = 1012, + EZS1_MSA = 1013, + EZS1_MST = 1014, + EZS1_MEVP = 1015, + EZS1_MPPIC = 1016, + EZS1_MSFTO = 1017, + EZS1_MSFF = 1018, + EZS1_MSFL = 1019, + EZS1_MLDK = 1020, + EZS1_PIN = 1030, + EZS1_ALARMTIME = 1031, + EZS1_SIGLOW = 1032, + EZS1_SIGHIGH = 1033, + EZS1_ALRMAX = 1050, + EZS1_ALRCONF = 1051, + EZS1_ALRMSG = 1052, + EZS1_NGSMAX = 1055, + EZS1_NGSCONF = 1056, + NGS_MSG = 1057, + EZS1_PCOMAX = 1060, + EZS1_PCOCONF = 1061, + EZS1_PCOMSG = 1062, + EZS1_DKMAX = 1070, + EZS1_DKCONF = 1071, + EZS1_DKCODE = 1072, + EZS1_TLFMAX = 1080, + EZS1_TLFCONG = 1081, + EZS1_TLFNUM = 1082, + EZS1_PRGOUTMAX = 1090, + EZS1_PRGOUTCONF = 1091, + EZS1_PRGOUTTOUT = 1092, + EZS1_PRGOUTVAL = 1093, + EZS1_PRGOUTTREST = 1094, + EZS1_ZONEMAX = 1100, + EZS1_ZONECONF = 1101, + EZS1_ZONENAME = 1102, + EZS1_ZONETOUT = 1103, + EZS1_ZONEBYTES = 1104, + EZS1_ZONEMTOUT = 1105, + EZS1_ANLPMAX = 1110, + EZS1_ANLPCONF = 1111, + EZS1_ANLPZONE = 1112, + EZS1_ANLPTOUT = 1113, + EZS1_ANLPSHORT = 1114, + EZS1_ANLPOPEN = 1115, + EZS1_Z1 = 1116, + EZS1_Z2 = 1117, + EZS1_Z1_Z2 = 1118, + EZS1_ANLPMBYTES = 1119, + EZS1_ANLPMTOUT = 1120, + EZS1_CONTMAX = 1140, + EZS1_CONTCONF = 1141, + EZS1_CONTZONE = 1142, + EZS1_CONTTOUT = 1143, + EZS1_CONTMBYTE = 1144, + EZS1_CONTMTOUT = 1145, + DIGIN = 8000, + ANALOGIN = 8001, + PWMOUT = 8002, + TMRPERIOD = 8003, + TMRDUTY = 8004, + STATUS = 8007, + TMRIN = 8008, + CURRENT_PGM = 8021, + PGM_TIME = 8022, + PGM_LIST = 8023, + CAN_SPEED = 8024, + BIN_OUTPUTS = 8030, + REZISTORS = 8031, +} + +pub fn oid_spec(oid: NepOid) -> Option<&'static NepOidSpec> { + OID_TABLE.get(&(oid as u16)) +} + +lazy_static::lazy_static! { + static ref OID_TABLE: HashMap = HashMap::from([ + (1, NepOidSpec { oid: NepOid::NAME, hasindex: false, readonly: true, neptype: NepType::STRING, name: "NAME" }), + (2, NepOidSpec { oid: NepOid::TYPE, hasindex: false, readonly: true, neptype: NepType::UNUMBER, name: "TYPE" }), + (3, NepOidSpec { oid: NepOid::SUBTYPE, hasindex: false, readonly: true, neptype: NepType::UNUMBER, name: "SUBTYPE" }), + (4, NepOidSpec { oid: NepOid::MANUF, hasindex: false, readonly: true, neptype: NepType::OCTETS, name: "MANUF" }), + (5, NepOidSpec { oid: NepOid::HWVER, hasindex: false, readonly: true, neptype: NepType::UNUMBER, name: "HWVER" }), + (6, NepOidSpec { oid: NepOid::HWREV, hasindex: false, readonly: true, neptype: NepType::UNUMBER, name: "HWREV" }), + (7, NepOidSpec { oid: NepOid::SWVER, hasindex: false, readonly: true, neptype: NepType::UNUMBER, name: "SWVER" }), + (8, NepOidSpec { oid: NepOid::SWREV, hasindex: false, readonly: true, neptype: NepType::UNUMBER, name: "SWREV" }), + (9, NepOidSpec { oid: NepOid::LOCATION, hasindex: false, readonly: false, neptype: NepType::STRING, name: "LOCATION" }), + (10, NepOidSpec { oid: NepOid::CONTACT, hasindex: false, readonly: false, neptype: NepType::STRING, name: "CONTACT" }), + (11, NepOidSpec { oid: NepOid::COMMAND, hasindex: false, readonly: false, neptype: NepType::STRING, name: "COMMAND" }), + (12, NepOidSpec { oid: NepOid::UPTIME, hasindex: false, readonly: true, neptype: NepType::UNUMBER, name: "UPTIME" }), + (13, NepOidSpec { oid: NepOid::SYSTIME, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "SYSTIME" }), + (14, NepOidSpec { oid: NepOid::RESET, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "RESET" }), + (15, NepOidSpec { oid: NepOid::CONFIG, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "CONFIG" }), + (16, NepOidSpec { oid: NepOid::MANUF_ID, hasindex: false, readonly: false, neptype: NepType::STRING, name: "MANUF_ID" }), + (17, NepOidSpec { oid: NepOid::NEXT_TIMESTAMP, hasindex: false, readonly: true, neptype: NepType::UNUMBER, name: "NEXT_TIMESTAMP" }), + (18, NepOidSpec { oid: NepOid::NEXT_DELTATIME, hasindex: false, readonly: true, neptype: NepType::NUMBER, name: "NEXT_DELTATIME" }), + (19, NepOidSpec { oid: NepOid::ENCRYPTED_BLOCK, hasindex: true, readonly: false, neptype: NepType::OCTETS, name: "ENCRYPTED_BLOCK" }), + (20, NepOidSpec { oid: NepOid::GPS_LATITUDE, hasindex: false, readonly: true, neptype: NepType::FLOAT, name: "GPS_LATITUDE" }), + (21, NepOidSpec { oid: NepOid::GPS_LONGITUDE, hasindex: false, readonly: true, neptype: NepType::FLOAT, name: "GPS_LONGITUDE" }), + (22, NepOidSpec { oid: NepOid::GPS_ALTITUDE, hasindex: false, readonly: true, neptype: NepType::FLOAT, name: "GPS_ALTITUDE" }), + (55, NepOidSpec { oid: NepOid::BULKCOUNT, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "BULKCOUNT" }), + (56, NepOidSpec { oid: NepOid::SEND_ALARMS, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "SEND_ALARMS" }), + (57, NepOidSpec { oid: NepOid::NEXT_OID, hasindex: false, readonly: true, neptype: NepType::OID, name: "NEXT_OID" }), + (58, NepOidSpec { oid: NepOid::AUTORESET_TIMEOUT, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "AUTORESET_TIMEOUT" }), + (59, NepOidSpec { oid: NepOid::ALARM_CNT, hasindex: false, readonly: true, neptype: NepType::UNUMBER, name: "ALARM_CNT" }), + (60, NepOidSpec { oid: NepOid::TRAP_CODE, hasindex: false, readonly: true, neptype: NepType::UNUMBER, name: "TRAP_CODE" }), + (61, NepOidSpec { oid: NepOid::SEQ_NUMBER, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "SEQ_NUMBER" }), + (62, NepOidSpec { oid: NepOid::SIGNATURE, hasindex: false, readonly: false, neptype: NepType::OCTETS, name: "SIGNATURE" }), + (63, NepOidSpec { oid: NepOid::MSGTYPE, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "MSGTYPE" }), + (64, NepOidSpec { oid: NepOid::CURR_ADDR, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "CURR_ADDR" }), + (65, NepOidSpec { oid: NepOid::CURR_LEN, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "CURR_LEN" }), + (66, NepOidSpec { oid: NepOid::MEMORY, hasindex: false, readonly: false, neptype: NepType::OCTETS, name: "MEMORY" }), + (67, NepOidSpec { oid: NepOid::IOPORTS, hasindex: false, readonly: false, neptype: NepType::OCTETS, name: "IOPORTS" }), + (70, NepOidSpec { oid: NepOid::TASKNAME, hasindex: true, readonly: true, neptype: NepType::STRING, name: "TASKNAME" }), + (71, NepOidSpec { oid: NepOid::TASK_STATE, hasindex: true, readonly: true, neptype: NepType::NUMBER, name: "TASK_STATE" }), + (72, NepOidSpec { oid: NepOid::TASK_PRIO, hasindex: true, readonly: true, neptype: NepType::NUMBER, name: "TASK_PRIO" }), + (81, NepOidSpec { oid: NepOid::METHANE_THRESHOLD, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "METHANE_THRESHOLD" }), + (82, NepOidSpec { oid: NepOid::METHANE, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "METHANE" }), + (83, NepOidSpec { oid: NepOid::ALARM_ON_CODE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "ALARM_ON_CODE" }), + (84, NepOidSpec { oid: NepOid::ALARM_OFF_CODE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "ALARM_OFF_CODE" }), + (85, NepOidSpec { oid: NepOid::TVOC_THRESHOLD, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "TVOC_THRESHOLD" }), + (86, NepOidSpec { oid: NepOid::TVOC, hasindex: true, readonly: true, neptype: NepType::NUMBER, name: "TVOC" }), + (87, NepOidSpec { oid: NepOid::CO2_THRESHOLD, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "CO2_THRESHOLD" }), + (88, NepOidSpec { oid: NepOid::CO2, hasindex: true, readonly: true, neptype: NepType::NUMBER, name: "CO2" }), + (89, NepOidSpec { oid: NepOid::CALIBRATION, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "CALIBRATION" }), + (90, NepOidSpec { oid: NepOid::HUMIDITY, hasindex: true, readonly: true, neptype: NepType::NUMBER, name: "HUMIDITY" }), + (91, NepOidSpec { oid: NepOid::HUMIDITY_LOW, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "HUMIDITY_LOW" }), + (92, NepOidSpec { oid: NepOid::HUMIDITY_HIGH, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "HUMIDITY_HIGH" }), + (94, NepOidSpec { oid: NepOid::AVALUE_Q, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "AVALUE_Q" }), + (95, NepOidSpec { oid: NepOid::AVALUE_KL, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "AVALUE_KL" }), + (96, NepOidSpec { oid: NepOid::AVALUE_KH, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "AVALUE_KH" }), + (97, NepOidSpec { oid: NepOid::AVALUE, hasindex: true, readonly: true, neptype: NepType::NUMBER, name: "AVALUE" }), + (98, NepOidSpec { oid: NepOid::IVALUE_TYPE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "IVALUE_TYPE" }), + (99, NepOidSpec { oid: NepOid::IVALUE_LEVEL, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "IVALUE_LEVEL" }), + (100, NepOidSpec { oid: NepOid::IVALUE, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "IVALUE" }), + (101, NepOidSpec { oid: NepOid::IVALUE_MULT, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "IVALUE_MULT" }), + (102, NepOidSpec { oid: NepOid::IVALUE_DIV, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "IVALUE_DIV" }), + (103, NepOidSpec { oid: NepOid::TEMPERATURE_LOW, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "TEMPERATURE_LOW" }), + (104, NepOidSpec { oid: NepOid::TEMPERATURE_HIGH, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "TEMPERATURE_HIGH" }), + (105, NepOidSpec { oid: NepOid::TEMPERATURE, hasindex: true, readonly: true, neptype: NepType::NUMBER, name: "TEMPERATURE" }), + (106, NepOidSpec { oid: NepOid::VOLTAGE, hasindex: true, readonly: true, neptype: NepType::NUMBER, name: "VOLTAGE" }), + (107, NepOidSpec { oid: NepOid::OVALUE, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "OVALUE" }), + (108, NepOidSpec { oid: NepOid::OVALUE_OFF_TOUT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "OVALUE_OFF_TOUT" }), + (109, NepOidSpec { oid: NepOid::SISA_TIMEOUTS, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "SISA_TIMEOUTS" }), + (110, NepOidSpec { oid: NepOid::SLRF_CHANNEL, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "SLRF_CHANNEL" }), + (111, NepOidSpec { oid: NepOid::SLRF_HOPCOUNT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "SLRF_HOPCOUNT" }), + (112, NepOidSpec { oid: NepOid::SLRF_TIMESLOTS, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "SLRF_TIMESLOTS" }), + (113, NepOidSpec { oid: NepOid::SLRF_TIMESLOT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "SLRF_TIMESLOT" }), + (114, NepOidSpec { oid: NepOid::SLRF_GROUP, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "SLRF_GROUP" }), + (115, NepOidSpec { oid: NepOid::SLRF_MADDRESS, hasindex: true, readonly: false, neptype: NepType::OCTETS, name: "SLRF_MADDRESS" }), + (116, NepOidSpec { oid: NepOid::SLRF_REPEATER, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "SLRF_REPEATER" }), + (117, NepOidSpec { oid: NepOid::SLRF_MASTER, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "SLRF_MASTER" }), + (118, NepOidSpec { oid: NepOid::SLRF_ADDRESS, hasindex: true, readonly: true, neptype: NepType::OCTETS, name: "SLRF_ADDRESS" }), + (119, NepOidSpec { oid: NepOid::SLRF_PACKET, hasindex: true, readonly: false, neptype: NepType::OCTETS, name: "SLRF_PACKET" }), + (120, NepOidSpec { oid: NepOid::SLRF_RSSI, hasindex: true, readonly: true, neptype: NepType::NUMBER, name: "SLRF_RSSI" }), + (121, NepOidSpec { oid: NepOid::SLRF_PROMISCUOUS, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "SLRF_PROMISCUOUS" }), + (122, NepOidSpec { oid: NepOid::SLRF_CD, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "SLRF_CD" }), + (123, NepOidSpec { oid: NepOid::SLRF_TEST, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "SLRF_TEST" }), + (124, NepOidSpec { oid: NepOid::SLRF_TEST_TIMEOUT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "SLRF_TEST_TIMEOUT" }), + (125, NepOidSpec { oid: NepOid::SLRF_TX_PWR, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "SLRF_TX_PWR" }), + (126, NepOidSpec { oid: NepOid::SLRF_AADDRESS, hasindex: true, readonly: false, neptype: NepType::OCTETS, name: "SLRF_AADDRESS" }), + (127, NepOidSpec { oid: NepOid::SLRF_WOR, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "SLRF_WOR" }), + (128, NepOidSpec { oid: NepOid::SLRF_PREAMBLE_LEN, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "SLRF_PREAMBLE_LEN" }), + (129, NepOidSpec { oid: NepOid::SLRF_RFA_ACTIVE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "SLRF_RFA_ACTIVE" }), + (130, NepOidSpec { oid: NepOid::IFC_NAME, hasindex: true, readonly: true, neptype: NepType::STRING, name: "IFC_NAME" }), + (131, NepOidSpec { oid: NepOid::IFC_ADMIN, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "IFC_ADMIN" }), + (132, NepOidSpec { oid: NepOid::IFC_OPER, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "IFC_OPER" }), + (133, NepOidSpec { oid: NepOid::IFC_SPEED, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "IFC_SPEED" }), + (134, NepOidSpec { oid: NepOid::IFC_PARAM, hasindex: true, readonly: false, neptype: NepType::STRING, name: "IFC_PARAM" }), + (135, NepOidSpec { oid: NepOid::IFC_TX_ON, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "IFC_TX_ON" }), + (136, NepOidSpec { oid: NepOid::IFC_TX_OFF, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "IFC_TX_OFF" }), + (137, NepOidSpec { oid: NepOid::IFC_INTERBYTE_TOUT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "IFC_INTERBYTE_TOUT" }), + (142, NepOidSpec { oid: NepOid::SLRF_DRV_ERROR, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "SLRF_DRV_ERROR" }), + (143, NepOidSpec { oid: NepOid::SLRF_WOR_WAKEUP, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "SLRF_WOR_WAKEUP" }), + (144, NepOidSpec { oid: NepOid::SLRF_OUT_ERRORS, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "SLRF_OUT_ERRORS" }), + (145, NepOidSpec { oid: NepOid::SLRF_IN_ERRORS, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "SLRF_IN_ERRORS" }), + (146, NepOidSpec { oid: NepOid::SLRF_OUT_PKTS, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "SLRF_OUT_PKTS" }), + (147, NepOidSpec { oid: NepOid::SLRF_IN_PKTS, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "SLRF_IN_PKTS" }), + (148, NepOidSpec { oid: NepOid::SLRF_RFFTC, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "SLRF_RFFTC" }), + (149, NepOidSpec { oid: NepOid::SLRF_CRYPT_KEY, hasindex: true, readonly: false, neptype: NepType::STRING, name: "SLRF_CRYPT_KEY" }), + (150, NepOidSpec { oid: NepOid::RFT_ADDRESS, hasindex: true, readonly: false, neptype: NepType::OCTETS, name: "RFT_ADDRESS" }), + (151, NepOidSpec { oid: NepOid::RFT_VALUE, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "RFT_VALUE" }), + (152, NepOidSpec { oid: NepOid::RF_UDP_DST_PORT, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "RF_UDP_DST_PORT" }), + (153, NepOidSpec { oid: NepOid::RF_UDP_SRC_PORT, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "RF_UDP_SRC_PORT" }), + (154, NepOidSpec { oid: NepOid::RF_DST_IP_ADDR, hasindex: false, readonly: false, neptype: NepType::IP, name: "RF_DST_IP_ADDR" }), + (155, NepOidSpec { oid: NepOid::UDP_HEARTBEAT, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "UDP_HEARTBEAT" }), + (156, NepOidSpec { oid: NepOid::IPRT_ADDR, hasindex: true, readonly: false, neptype: NepType::IP, name: "IPRT_ADDR" }), + (157, NepOidSpec { oid: NepOid::IPRT_MASK, hasindex: true, readonly: false, neptype: NepType::IP, name: "IPRT_MASK" }), + (158, NepOidSpec { oid: NepOid::IPRT_GW, hasindex: true, readonly: false, neptype: NepType::IP, name: "IPRT_GW" }), + (159, NepOidSpec { oid: NepOid::IPRT_IFC_NAME, hasindex: true, readonly: false, neptype: NepType::STRING, name: "IPRT_IFC_NAME" }), + (160, NepOidSpec { oid: NepOid::IP_IFC_NAME, hasindex: true, readonly: false, neptype: NepType::STRING, name: "IP_IFC_NAME" }), + (161, NepOidSpec { oid: NepOid::IP_ADDRESS, hasindex: true, readonly: false, neptype: NepType::IP, name: "IP_ADDRESS" }), + (162, NepOidSpec { oid: NepOid::IP_MASK, hasindex: true, readonly: false, neptype: NepType::IP, name: "IP_MASK" }), + (163, NepOidSpec { oid: NepOid::IP_ADMIN, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "IP_ADMIN" }), + (164, NepOidSpec { oid: NepOid::IP_OPER, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "IP_OPER" }), + (165, NepOidSpec { oid: NepOid::IP_MTU, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "IP_MTU" }), + (166, NepOidSpec { oid: NepOid::IP_MAC_ADDRESS, hasindex: true, readonly: true, neptype: NepType::OCTETS, name: "IP_MAC_ADDRESS" }), + (167, NepOidSpec { oid: NepOid::IP_IFC_TYPE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "IP_IFC_TYPE" }), + (168, NepOidSpec { oid: NepOid::IFC_START_TIME, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "IFC_START_TIME" }), + (169, NepOidSpec { oid: NepOid::IFC_STTOP_TIME, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "IFC_STTOP_TIME" }), + (180, NepOidSpec { oid: NepOid::SIGFOX_ID, hasindex: true, readonly: true, neptype: NepType::STRING, name: "SIGFOX_ID" }), + (181, NepOidSpec { oid: NepOid::SIGFOX_PAC, hasindex: true, readonly: true, neptype: NepType::STRING, name: "SIGFOX_PAC" }), + (196, NepOidSpec { oid: NepOid::STORAGE_INTERVAL, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "STORAGE_INTERVAL" }), + (197, NepOidSpec { oid: NepOid::STORAGE_FLOAT, hasindex: true, readonly: false, neptype: NepType::FLOAT, name: "STORAGE_FLOAT" }), + (198, NepOidSpec { oid: NepOid::STORAGE_INT, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "STORAGE_INT" }), + (199, NepOidSpec { oid: NepOid::STORAGE_TIMESTAMP, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "STORAGE_TIMESTAMP" }), + (200, NepOidSpec { oid: NepOid::COLL_RF_ADDR, hasindex: true, readonly: false, neptype: NepType::OCTETS, name: "COLL_RF_ADDR" }), + (201, NepOidSpec { oid: NepOid::COLL_RF_RSSI, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "COLL_RF_RSSI" }), + (205, NepOidSpec { oid: NepOid::COLL_MBUS_ADDR, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "COLL_MBUS_ADDR" }), + (206, NepOidSpec { oid: NepOid::COLL_MBUS_ID, hasindex: true, readonly: false, neptype: NepType::OCTETS, name: "COLL_MBUS_ID" }), + (207, NepOidSpec { oid: NepOid::COLL_MBUS_FMT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "COLL_MBUS_FMT" }), + (208, NepOidSpec { oid: NepOid::COLL_MBUS_MEDIUM, hasindex: true, readonly: false, neptype: NepType::OCTETS, name: "COLL_MBUS_MEDIUM" }), + (209, NepOidSpec { oid: NepOid::COLL_MBUS_C1_RFI, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "COLL_MBUS_C1_RFI" }), + (210, NepOidSpec { oid: NepOid::COLL_MBUS_C1_VI, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "COLL_MBUS_C1_VI" }), + (211, NepOidSpec { oid: NepOid::COLL_MBUS_C2_RFI, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "COLL_MBUS_C2_RFI" }), + (212, NepOidSpec { oid: NepOid::COLL_MBUS_C2_VI, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "COLL_MBUS_C2_VI" }), + (213, NepOidSpec { oid: NepOid::WMBUS_MODE, hasindex: true, readonly: false, neptype: NepType::STRING, name: "WMBUS_MODE" }), + (214, NepOidSpec { oid: NepOid::WMBUS_SENDING, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "WMBUS_SENDING" }), + (215, NepOidSpec { oid: NepOid::WMBUS_PACKET, hasindex: true, readonly: false, neptype: NepType::OCTETS, name: "WMBUS_PACKET" }), + (216, NepOidSpec { oid: NepOid::WMBUS_RSSI, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "WMBUS_RSSI" }), + (217, NepOidSpec { oid: NepOid::WMBUS_FREQ_RANGE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "WMBUS_FREQ_RANGE" }), + (218, NepOidSpec { oid: NepOid::WMBUS_CHANNEL, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "WMBUS_CHANNEL" }), + (219, NepOidSpec { oid: NepOid::WMBUS_DATARATE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "WMBUS_DATARATE" }), + (220, NepOidSpec { oid: NepOid::WMBUS_FRAME_FORMAT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "WMBUS_FRAME_FORMAT" }), + (221, NepOidSpec { oid: NepOid::WMBUS_RFFTC, hasindex: true, readonly: true, neptype: NepType::NUMBER, name: "WMBUS_RFFTC" }), + (222, NepOidSpec { oid: NepOid::WMBUS_IN_PKTS, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "WMBUS_IN_PKTS" }), + (223, NepOidSpec { oid: NepOid::WMBUS_OUT_PKTS, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "WMBUS_OUT_PKTS" }), + (224, NepOidSpec { oid: NepOid::WMBUS_IN_ERRORS, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "WMBUS_IN_ERRORS" }), + (225, NepOidSpec { oid: NepOid::WMBUS_OUT_ERRORS, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "WMBUS_OUT_ERRORS" }), + (226, NepOidSpec { oid: NepOid::WMBUS_DRV_ERROR, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "WMBUS_DRV_ERROR" }), + (227, NepOidSpec { oid: NepOid::WMBUS_POWER, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "WMBUS_POWER" }), + (228, NepOidSpec { oid: NepOid::WMBUS_SENDMODE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "WMBUS_SENDMODE" }), + (229, NepOidSpec { oid: NepOid::WMBUS_CAPATUN, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "WMBUS_CAPATUN" }), + (300, NepOidSpec { oid: NepOid::MBUS_PRIMARY, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "MBUS_PRIMARY" }), + (301, NepOidSpec { oid: NepOid::MBUS_SECONDARY, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "MBUS_SECONDARY" }), + (302, NepOidSpec { oid: NepOid::MBUS_MANUF, hasindex: true, readonly: false, neptype: NepType::STRING, name: "MBUS_MANUF" }), + (303, NepOidSpec { oid: NepOid::MBUS_VERSION, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "MBUS_VERSION" }), + (304, NepOidSpec { oid: NepOid::MBUS_MEDIUM, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "MBUS_MEDIUM" }), + (305, NepOidSpec { oid: NepOid::MBUS_ENCRYPT_KEY, hasindex: true, readonly: false, neptype: NepType::OCTETS, name: "MBUS_ENCRYPT_KEY" }), + (306, NepOidSpec { oid: NepOid::MBUS_ENCRYPT_TYPE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "MBUS_ENCRYPT_TYPE" }), + (307, NepOidSpec { oid: NepOid::MBUS_PERIOD, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "MBUS_PERIOD" }), + (308, NepOidSpec { oid: NepOid::MBUS_MANUF_NO, hasindex: true, readonly: false, neptype: NepType::STRING, name: "MBUS_MANUF_NO" }), + (320, NepOidSpec { oid: NepOid::MBUSV_DEV_INDEX, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "MBUSV_DEV_INDEX" }), + (321, NepOidSpec { oid: NepOid::MBUSV_DIF, hasindex: true, readonly: false, neptype: NepType::OCTETS, name: "MBUSV_DIF" }), + (322, NepOidSpec { oid: NepOid::MBUSV_VIF, hasindex: true, readonly: false, neptype: NepType::OCTETS, name: "MBUSV_VIF" }), + (326, NepOidSpec { oid: NepOid::MBUSV_OPTO_ID, hasindex: true, readonly: false, neptype: NepType::STRING, name: "MBUSV_OPTO_ID" }), + (327, NepOidSpec { oid: NepOid::MBUSV_OPTO_DECIMAL, hasindex: true, readonly: false, neptype: NepType::NUMBER, name: "MBUSV_OPTO_DECIMAL" }), + (360, NepOidSpec { oid: NepOid::LEAKMEASURETIME, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "LEAKMEASURETIME" }), + (361, NepOidSpec { oid: NepOid::LEAKCHECKTIME, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "LEAKCHECKTIME" }), + (362, NepOidSpec { oid: NepOid::LEAKZEROTIME, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "LEAKZEROTIME" }), + (363, NepOidSpec { oid: NepOid::BURSTCHECKTIME, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "BURSTCHECKTIME" }), + (364, NepOidSpec { oid: NepOid::BURSTFLOW, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "BURSTFLOW" }), + (400, NepOidSpec { oid: NepOid::PROTO_DEVICE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_DEVICE" }), + (401, NepOidSpec { oid: NepOid::PROTO_TYPE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_TYPE" }), + (402, NepOidSpec { oid: NepOid::PROTO_SPEED, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_SPEED" }), + (403, NepOidSpec { oid: NepOid::PROTO_PARAM, hasindex: true, readonly: false, neptype: NepType::STRING, name: "PROTO_PARAM" }), + (404, NepOidSpec { oid: NepOid::PROTO_PERIOD, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_PERIOD" }), + (405, NepOidSpec { oid: NepOid::PROTO_TRANSACTION_TIMEOUT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_TRANSACTION_TIMEOUT" }), + (406, NepOidSpec { oid: NepOid::PROTO_TRANSACTION_DELAY, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_TRANSACTION_DELAY" }), + (407, NepOidSpec { oid: NepOid::PROTO_ENCRYPTION_KEY, hasindex: true, readonly: false, neptype: NepType::OCTETS, name: "PROTO_ENCRYPTION_KEY" }), + (408, NepOidSpec { oid: NepOid::PROTO_REPEAT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_REPEAT" }), + (415, NepOidSpec { oid: NepOid::PROTO_MBUS_PRISEC, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_MBUS_PRISEC" }), + (416, NepOidSpec { oid: NepOid::PROTO_MBUS_PRI, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_MBUS_PRI" }), + (417, NepOidSpec { oid: NepOid::PROTO_MBUS_SEC_ID, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_MBUS_SEC_ID" }), + (420, NepOidSpec { oid: NepOid::PROTO_OPTO_ADDR, hasindex: true, readonly: false, neptype: NepType::STRING, name: "PROTO_OPTO_ADDR" }), + (421, NepOidSpec { oid: NepOid::PROTO_OPTO_MODE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_OPTO_MODE" }), + (425, NepOidSpec { oid: NepOid::PROTO_MODBUS_ADDR, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_MODBUS_ADDR" }), + (426, NepOidSpec { oid: NepOid::PROTO_MODBUS_MODE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_MODBUS_MODE" }), + (430, NepOidSpec { oid: NepOid::PROTO_VAR_INDEX, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_VAR_INDEX" }), + (431, NepOidSpec { oid: NepOid::PROTO_VAR_DIF_VIF, hasindex: true, readonly: false, neptype: NepType::OCTETS, name: "PROTO_VAR_DIF_VIF" }), + (432, NepOidSpec { oid: NepOid::PROTO_VAR_OPTO, hasindex: true, readonly: false, neptype: NepType::STRING, name: "PROTO_VAR_OPTO" }), + (433, NepOidSpec { oid: NepOid::PROTO_VAR_MODBUS_REGISTER, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_VAR_MODBUS_REGISTER" }), + (434, NepOidSpec { oid: NepOid::PROTO_VAR_MODBUS_FUNC, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_VAR_MODBUS_FUNC" }), + (435, NepOidSpec { oid: NepOid::PROTO_VAR_MODBUS_TYPE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_VAR_MODBUS_TYPE" }), + (436, NepOidSpec { oid: NepOid::PROTO_OUT_OID, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_OUT_OID" }), + (437, NepOidSpec { oid: NepOid::PROTO_OUT_IDX, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_OUT_IDX" }), + (438, NepOidSpec { oid: NepOid::PROTO_OUT_DIFVIF, hasindex: true, readonly: false, neptype: NepType::OCTETS, name: "PROTO_OUT_DIFVIF" }), + (439, NepOidSpec { oid: NepOid::PROTO_DEC, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PROTO_DEC" }), + (452, NepOidSpec { oid: NepOid::ALARM_INDEX, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "ALARM_INDEX" }), + (453, NepOidSpec { oid: NepOid::ALARM_TYPE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "ALARM_TYPE" }), + (454, NepOidSpec { oid: NepOid::ALARM_BIT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "ALARM_BIT" }), + (459, NepOidSpec { oid: NepOid::SEND_MASK, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "SEND_MASK" }), + (460, NepOidSpec { oid: NepOid::MODEM_IMEI, hasindex: true, readonly: true, neptype: NepType::STRING, name: "MODEM_IMEI" }), + (461, NepOidSpec { oid: NepOid::MODEM_CCID, hasindex: true, readonly: true, neptype: NepType::STRING, name: "MODEM_CCID" }), + (462, NepOidSpec { oid: NepOid::MODEM_LAST_RSSI, hasindex: true, readonly: true, neptype: NepType::NUMBER, name: "MODEM_LAST_RSSI" }), + (463, NepOidSpec { oid: NepOid::Modem_APN, hasindex: true, readonly: false, neptype: NepType::STRING, name: "Modem_APN" }), + (464, NepOidSpec { oid: NepOid::MODEM_PIN, hasindex: true, readonly: false, neptype: NepType::STRING, name: "MODEM_PIN" }), + (465, NepOidSpec { oid: NepOid::MODEM_SENDPKT, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "MODEM_SENDPKT" }), + (466, NepOidSpec { oid: NepOid::MODEM_RECVPKT, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "MODEM_RECVPKT" }), + (467, NepOidSpec { oid: NepOid::MODEM_IMSI, hasindex: true, readonly: true, neptype: NepType::STRING, name: "MODEM_IMSI" }), + (468, NepOidSpec { oid: NepOid::MODEM_SESTIMEOUT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "MODEM_SESTIMEOUT" }), + (469, NepOidSpec { oid: NepOid::MODEM_FLAGS, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "MODEM_FLAGS" }), + (470, NepOidSpec { oid: NepOid::MODEM_TEST_IP, hasindex: true, readonly: false, neptype: NepType::IP, name: "MODEM_TEST_IP" }), + (500, NepOidSpec { oid: NepOid::RADAR_TYPE, hasindex: true, readonly: true, neptype: NepType::NUMBER, name: "RADAR_TYPE" }), + (501, NepOidSpec { oid: NepOid::RADAR_IDENT, hasindex: true, readonly: true, neptype: NepType::STRING, name: "RADAR_IDENT" }), + (502, NepOidSpec { oid: NepOid::RADAR_TIMESTAMP, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "RADAR_TIMESTAMP" }), + (503, NepOidSpec { oid: NepOid::RADAR_RSSI, hasindex: true, readonly: true, neptype: NepType::NUMBER, name: "RADAR_RSSI" }), + (504, NepOidSpec { oid: NepOid::RADAR_STATUS, hasindex: true, readonly: true, neptype: NepType::NUMBER, name: "RADAR_STATUS" }), + (552, NepOidSpec { oid: NepOid::GW_UDP_DST_PORT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "GW_UDP_DST_PORT" }), + (553, NepOidSpec { oid: NepOid::GW_UDP_SRC_PORT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "GW_UDP_SRC_PORT" }), + (554, NepOidSpec { oid: NepOid::GW_DST_IP_ADDR, hasindex: true, readonly: false, neptype: NepType::IP, name: "GW_DST_IP_ADDR" }), + (555, NepOidSpec { oid: NepOid::GW_UDP_HEARTBEAT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "GW_UDP_HEARTBEAT" }), + (556, NepOidSpec { oid: NepOid::GW_IP_TIMEOUT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "GW_IP_TIMEOUT" }), + (557, NepOidSpec { oid: NepOid::GW_MSG_SENT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "GW_MSG_SENT" }), + (600, NepOidSpec { oid: NepOid::CONFIGVERSION, hasindex: true, readonly: true, neptype: NepType::NUMBER, name: "CONFIGVERSION" }), + (601, NepOidSpec { oid: NepOid::CONFIGTYPE, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "CONFIGTYPE" }), + (602, NepOidSpec { oid: NepOid::CONFIGVAL, hasindex: true, readonly: true, neptype: NepType::STRING, name: "CONFIGVAL" }), + (1000, NepOidSpec { oid: NepOid::EZS1_UPTIME, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_UPTIME" }), + (1001, NepOidSpec { oid: NepOid::EZS1_MUPC, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MUPC" }), + (1002, NepOidSpec { oid: NepOid::EZS1_MLSF, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MLSF" }), + (1003, NepOidSpec { oid: NepOid::EZS1_MSfAT, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MSfAT" }), + (1004, NepOidSpec { oid: NepOid::EZS1_MSFPF, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MSFPF" }), + (1005, NepOidSpec { oid: NepOid::EZS1_MGFLG, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MGFLG" }), + (1006, NepOidSpec { oid: NepOid::EZS1_MSFLG, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MSFLG" }), + (1007, NepOidSpec { oid: NepOid::EZS1_MTFLG, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MTFLG" }), + (1008, NepOidSpec { oid: NepOid::EZS1_MSMSI, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MSMSI" }), + (1009, NepOidSpec { oid: NepOid::EZS1_MDKEP, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MDKEP" }), + (1010, NepOidSpec { oid: NepOid::EZS1_MDKET, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MDKET" }), + (1011, NepOidSpec { oid: NepOid::EZS1_MIDK, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MIDK" }), + (1012, NepOidSpec { oid: NepOid::EZS1_MLVDK, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MLVDK" }), + (1013, NepOidSpec { oid: NepOid::EZS1_MSA, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MSA" }), + (1014, NepOidSpec { oid: NepOid::EZS1_MST, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MST" }), + (1015, NepOidSpec { oid: NepOid::EZS1_MEVP, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MEVP" }), + (1016, NepOidSpec { oid: NepOid::EZS1_MPPIC, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MPPIC" }), + (1017, NepOidSpec { oid: NepOid::EZS1_MSFTO, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MSFTO" }), + (1018, NepOidSpec { oid: NepOid::EZS1_MSFF, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MSFF" }), + (1019, NepOidSpec { oid: NepOid::EZS1_MSFL, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_MSFL" }), + (1020, NepOidSpec { oid: NepOid::EZS1_MLDK, hasindex: false, readonly: false, neptype: NepType::STRING, name: "EZS1_MLDK" }), + (1030, NepOidSpec { oid: NepOid::EZS1_PIN, hasindex: false, readonly: false, neptype: NepType::STRING, name: "EZS1_PIN" }), + (1031, NepOidSpec { oid: NepOid::EZS1_ALARMTIME, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_ALARMTIME" }), + (1032, NepOidSpec { oid: NepOid::EZS1_SIGLOW, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_SIGLOW" }), + (1033, NepOidSpec { oid: NepOid::EZS1_SIGHIGH, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_SIGHIGH" }), + (1050, NepOidSpec { oid: NepOid::EZS1_ALRMAX, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_ALRMAX" }), + (1051, NepOidSpec { oid: NepOid::EZS1_ALRCONF, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_ALRCONF" }), + (1052, NepOidSpec { oid: NepOid::EZS1_ALRMSG, hasindex: true, readonly: false, neptype: NepType::STRING, name: "EZS1_ALRMSG" }), + (1055, NepOidSpec { oid: NepOid::EZS1_NGSMAX, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_NGSMAX" }), + (1056, NepOidSpec { oid: NepOid::EZS1_NGSCONF, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_NGSCONF" }), + (1057, NepOidSpec { oid: NepOid::NGS_MSG, hasindex: true, readonly: false, neptype: NepType::STRING, name: "NGS_MSG" }), + (1060, NepOidSpec { oid: NepOid::EZS1_PCOMAX, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_PCOMAX" }), + (1061, NepOidSpec { oid: NepOid::EZS1_PCOCONF, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_PCOCONF" }), + (1062, NepOidSpec { oid: NepOid::EZS1_PCOMSG, hasindex: true, readonly: false, neptype: NepType::STRING, name: "EZS1_PCOMSG" }), + (1070, NepOidSpec { oid: NepOid::EZS1_DKMAX, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_DKMAX" }), + (1071, NepOidSpec { oid: NepOid::EZS1_DKCONF, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_DKCONF" }), + (1072, NepOidSpec { oid: NepOid::EZS1_DKCODE, hasindex: true, readonly: false, neptype: NepType::STRING, name: "EZS1_DKCODE" }), + (1080, NepOidSpec { oid: NepOid::EZS1_TLFMAX, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_TLFMAX" }), + (1081, NepOidSpec { oid: NepOid::EZS1_TLFCONG, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_TLFCONG" }), + (1082, NepOidSpec { oid: NepOid::EZS1_TLFNUM, hasindex: true, readonly: false, neptype: NepType::STRING, name: "EZS1_TLFNUM" }), + (1090, NepOidSpec { oid: NepOid::EZS1_PRGOUTMAX, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_PRGOUTMAX" }), + (1091, NepOidSpec { oid: NepOid::EZS1_PRGOUTCONF, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_PRGOUTCONF" }), + (1092, NepOidSpec { oid: NepOid::EZS1_PRGOUTTOUT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_PRGOUTTOUT" }), + (1093, NepOidSpec { oid: NepOid::EZS1_PRGOUTVAL, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_PRGOUTVAL" }), + (1094, NepOidSpec { oid: NepOid::EZS1_PRGOUTTREST, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_PRGOUTTREST" }), + (1100, NepOidSpec { oid: NepOid::EZS1_ZONEMAX, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_ZONEMAX" }), + (1101, NepOidSpec { oid: NepOid::EZS1_ZONECONF, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_ZONECONF" }), + (1102, NepOidSpec { oid: NepOid::EZS1_ZONENAME, hasindex: true, readonly: false, neptype: NepType::STRING, name: "EZS1_ZONENAME" }), + (1103, NepOidSpec { oid: NepOid::EZS1_ZONETOUT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_ZONETOUT" }), + (1104, NepOidSpec { oid: NepOid::EZS1_ZONEBYTES, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_ZONEBYTES" }), + (1105, NepOidSpec { oid: NepOid::EZS1_ZONEMTOUT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_ZONEMTOUT" }), + (1110, NepOidSpec { oid: NepOid::EZS1_ANLPMAX, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_ANLPMAX" }), + (1111, NepOidSpec { oid: NepOid::EZS1_ANLPCONF, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_ANLPCONF" }), + (1112, NepOidSpec { oid: NepOid::EZS1_ANLPZONE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_ANLPZONE" }), + (1113, NepOidSpec { oid: NepOid::EZS1_ANLPTOUT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_ANLPTOUT" }), + (1114, NepOidSpec { oid: NepOid::EZS1_ANLPSHORT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_ANLPSHORT" }), + (1115, NepOidSpec { oid: NepOid::EZS1_ANLPOPEN, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_ANLPOPEN" }), + (1116, NepOidSpec { oid: NepOid::EZS1_Z1, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_Z1" }), + (1117, NepOidSpec { oid: NepOid::EZS1_Z2, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_Z2" }), + (1118, NepOidSpec { oid: NepOid::EZS1_Z1_Z2, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_Z1_Z2" }), + (1119, NepOidSpec { oid: NepOid::EZS1_ANLPMBYTES, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_ANLPMBYTES" }), + (1120, NepOidSpec { oid: NepOid::EZS1_ANLPMTOUT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_ANLPMTOUT" }), + (1140, NepOidSpec { oid: NepOid::EZS1_CONTMAX, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_CONTMAX" }), + (1141, NepOidSpec { oid: NepOid::EZS1_CONTCONF, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_CONTCONF" }), + (1142, NepOidSpec { oid: NepOid::EZS1_CONTZONE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_CONTZONE" }), + (1143, NepOidSpec { oid: NepOid::EZS1_CONTTOUT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_CONTTOUT" }), + (1144, NepOidSpec { oid: NepOid::EZS1_CONTMBYTE, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_CONTMBYTE" }), + (1145, NepOidSpec { oid: NepOid::EZS1_CONTMTOUT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "EZS1_CONTMTOUT" }), + (8000, NepOidSpec { oid: NepOid::DIGIN, hasindex: false, readonly: true, neptype: NepType::OCTETS, name: "DIGIN" }), + (8001, NepOidSpec { oid: NepOid::ANALOGIN, hasindex: true, readonly: true, neptype: NepType::UNUMBER, name: "ANALOGIN" }), + (8002, NepOidSpec { oid: NepOid::PWMOUT, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "PWMOUT" }), + (8003, NepOidSpec { oid: NepOid::TMRPERIOD, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "TMRPERIOD" }), + (8004, NepOidSpec { oid: NepOid::TMRDUTY, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "TMRDUTY" }), + (8007, NepOidSpec { oid: NepOid::STATUS, hasindex: false, readonly: false, neptype: NepType::OCTETS, name: "STATUS" }), + (8008, NepOidSpec { oid: NepOid::TMRIN, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "TMRIN" }), + (8021, NepOidSpec { oid: NepOid::CURRENT_PGM, hasindex: false, readonly: false, neptype: NepType::STRING, name: "CURRENT_PGM" }), + (8022, NepOidSpec { oid: NepOid::PGM_TIME, hasindex: false, readonly: false, neptype: NepType::UNUMBER, name: "PGM_TIME" }), + (8023, NepOidSpec { oid: NepOid::PGM_LIST, hasindex: true, readonly: false, neptype: NepType::STRING, name: "PGM_LIST" }), + (8024, NepOidSpec { oid: NepOid::CAN_SPEED, hasindex: true, readonly: false, neptype: NepType::UNUMBER, name: "CAN_SPEED" }), + (8030, NepOidSpec { oid: NepOid::BIN_OUTPUTS, hasindex: false, readonly: false, neptype: NepType::OCTETS, name: "BIN_OUTPUTS" }), + (8031, NepOidSpec { oid: NepOid::REZISTORS, hasindex: false, readonly: false, neptype: NepType::OCTETS, name: "REZISTORS" }), + ]); +} + + +pub fn parse(payload: &[u8]) -> Result, NepError> { + let hp_len = payload.len() as u64; + let mut hp = Cursor::new(payload); + + let mut parsed = vec![]; + + while hp.position() < hp_len { + let mut entry_start = hp.position(); + let mut entry_end = 0; + + let mut oid = hp.read_u8()? as u16; + //Log::debug("OID byte ".sprintf("0x%02x", oid)); + + let long_oid = (oid & 0x80) != 0; + let has_index = (oid & 0x40) != 0; + oid = oid & 0x3F; + if long_oid { + //Log::debug("Long OID"); + oid <<= 8; + let oid_lsb = hp.read_u8()?; + //Log::debug("OID LSB ".sprintf("0x%02x", oid_lsb)); + oid |= oid_lsb as u16; + } + + let mut index = 0; + if has_index { + //Log::debug("Has index"); + + index = hp.read_u8()? as u16; + //Log::debug("Index byte ".sprintf("0x%02x", index)); + let long_index = (index & 0x80) != 0; + index &= 0x7F; + + if long_index { + //Log::debug("Long index"); + index <<= 8; + let index_lsb = hp.read_u8()?; + //Log::debug("Index LSB ".sprintf("0x%02x", index_lsb)); + index |= index_lsb as u16; + } + } + +// \Log::debug("OID " . sprintf(long_oid ? "0x%04x" : "0x%02x", oid) +// . " (".oid."), index " . sprintf(longIndex ? "0x%04x" : "0x%02x", index)); + + let mut bad = false; + let nepoid; + let expected_type = if let Some(spec) = OID_TABLE.get(&oid) { + nepoid = spec.oid; + spec.neptype + } else { + warn!("Bad NEP oid"); + bad = true; + nepoid = NepOid::RESET; // Dummy + NepType::INVALID + }; + + let mut neptype = 0; + + let specbyte = hp.read_u8()?; + //Log::debug("Specbyte ".sprintf("0x%02x", specbyte)); + + let fieldlen = if 0 != (specbyte & 0x80) { + //Log::debug("Long type/len"); + + // long format + neptype = specbyte & 0x7F; + + let mut tmplen = hp.read_u8()? as u16; + if 0 != (tmplen & 0x80) { + //Log::debug("Double long len"); + // double length + let len_lsb = hp.read_u8()?; + tmplen = ((tmplen & 0x7F) << 8) | (len_lsb as u16); + } + tmplen + } else { + //Log::debug("Short type and len"); + neptype = (specbyte & 0x70) >> 4; + (specbyte & 0x0F) as u16 + }; + + if neptype > 7 { + warn!("Bad NEP type"); + bad = true; + } + + if neptype != expected_type as u8 { + trace!("OID non-standard type {}, expected {}", neptype, expected_type as u8); + } + + trace!("oid {oid}, type {neptype}, len {fieldlen}"); + + if bad { + debug!("Skip bad entry"); + hp.consume(fieldlen as usize); + continue; + } + + let value = match NepType::from(neptype) { + NepType::STRING => { + let mut buf = vec![0; fieldlen as usize]; + hp.read_exact(&mut buf[..])?; + NepValue::String(String::from_utf8_lossy(&buf).to_string()) + } + NepType::OCTETS => { + let mut buf = vec![0; fieldlen as usize]; + hp.read_exact(&mut buf[..])?; + NepValue::Octets(buf) + } + NepType::UNUMBER => { + match fieldlen { + 4 => NepValue::Unumber(hp.read_u32::()?), + 3 => NepValue::Unumber(hp.read_u24::()? as u32), + 2 => NepValue::Unumber(hp.read_u16::()? as u32), + 1 => NepValue::Unumber(hp.read_u8()? as u32), + _ => { + debug!("Skip bad entry (unumber bad len)"); + hp.consume(fieldlen as usize); + continue; + } + } + } + NepType::NUMBER => { + match fieldlen { + 4 => NepValue::Number(hp.read_i32::()?), + 3 => NepValue::Number(hp.read_i24::()? as i32), + 2 => NepValue::Number(hp.read_i16::()? as i32), + 1 => NepValue::Number(hp.read_i8()? as i32), + _ => { + debug!("Skip bad entry (number bad len)"); + hp.consume(fieldlen as usize); + continue; + } + } + } + NepType::OID => { + match fieldlen { + 2 => NepValue::Oid(hp.read_u16::()? as u16), + 1 => NepValue::Oid(hp.read_u8()? as u16), + _ => { + debug!("Skip bad entry (OID bad len)"); + hp.consume(fieldlen as usize); + continue; + } + } + } + NepType::IP => { + if fieldlen != 4 { + debug!("Skip bad entry (IP bad len)"); + hp.consume(fieldlen as usize); + continue; + } + let mut buf = [0; 4]; + hp.read_exact(&mut buf[..])?; + NepValue::IP(buf) + } + NepType::FLOAT => { + if fieldlen != 4 { + debug!("Skip bad entry (float bad len)"); + hp.consume(fieldlen as usize); + continue; + } + NepValue::Float(hp.read_f32::()?) + } + NepType::NULL => { + NepValue::Null + } + NepType::INVALID => { + debug!("Skip bad entry (unknown type)"); + hp.consume(fieldlen as usize); + continue; + } + }; + + if oid == NepOid::MSGTYPE as u16 && value == NepValue::Unumber(127) { + return Err(NepError::Encrypted); + } + + parsed.push(NepEntry { + oid: nepoid, + index, + value, + }); + } + + Ok(parsed) +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_decode() { + simple_logging::log_to_stderr(log::LevelFilter::Debug); + + //let bytes = hex::decode("3f210602220352032101041f3836333730333033323337353635360c2303a0203d210bc069013200bfc06a01320e4dc1ce0131ab1124609c5df0c064012103c0640221001124609c6c00c064012103c0640221001124609c7a10c064012103c0640221001124609c8820c064012103c0640221001124609c9630c064012103c0640221001124609ca440c064012103c064022100").unwrap(); + let bytes = hex::decode("3f2106c0d801319dc0d7018180adac4424348044041950077aea0000002f2f0413106c0100046d1e29c82904fd17010100000e780594562019004413e7130100426cbf2c840113886a010082016cdf28d3013b930300c4016d372fd4218104fd280182046cdf28840413886a0100c40413b8620100840513bb590100c40513de51010084061342480100c40613cc3b0100840713a92d0100c40713a9200100840813e7130100c40813cd06010084091341fa0000c40913b3ee0000").unwrap(); + + let parsed = super::parse(&bytes); + + eprintln!("Decoded: {:#?}", parsed.unwrap()); + + // TODO verify values + } +}