use std::{fmt, io, num, error, convert, array};
use std::time::Instant;
use std::sync::{Arc, Mutex};
use bytes::{Bytes, BytesMut};
use num_enum::{IntoPrimitive, TryFromPrimitive};
#[macro_use]
mod misc {
#[macro_export]
macro_rules! u16_low_byte {
($x:expr) => {
$x as u8 & 0xff
};
}
#[macro_export]
macro_rules! u16_high_byte {
($x:expr) => {
($x >> 8) as u8 & 0xff
};
}
#[macro_export]
macro_rules! u32_hw_hb {
($x:expr) => {
($x >> 24) as u8 & 0xff
};
}
#[macro_export]
macro_rules! u32_hw_lb {
($x:expr) => {
($x >> 16) as u8 & 0xff
};
}
#[macro_export]
macro_rules! u32_lw_hb {
($x:expr) => {
($x >> 8) as u8 & 0xff
};
}
#[macro_export]
macro_rules! u32_lw_lb {
($x:expr) => {
$x as u8 & 0xff
};
}
#[allow(dead_code)]
fn print_type_of<T>(_: &T) {
println!("{}", std::any::type_name::<T>())
}
}
pub type AmsNetId = [u8; 6];
pub type Result<T> = std::result::Result<T, AdsError>;
pub type Notification = fn(u32, u64, Bytes, Option<Arc<Mutex<BytesMut>>>) -> ();
#[derive(Debug, Clone)]
pub struct AdsError {
pub n_error : u32,
pub s_msg : String
}
impl error::Error for AdsError{}
impl fmt::Display for AdsError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "AdsClientError 0x{:x} - {}", self.n_error, self.s_msg)
}
}
impl From<io::Error> for AdsError{
fn from(error: io::Error) -> Self {
AdsError {n_error : 10, s_msg : error.to_string()}
}
}
impl From<num::TryFromIntError> for AdsError{
fn from(error: num::TryFromIntError) -> Self {
AdsError {n_error : 1, s_msg : error.to_string() }
}
}
impl From<array::TryFromSliceError> for AdsError{
fn from(error: array::TryFromSliceError) -> Self {
AdsError {n_error : 1, s_msg : error.to_string() }
}
}
impl From<num::ParseIntError> for AdsError{
fn from(error: num::ParseIntError) -> Self {
AdsError {n_error : 1, s_msg : error.to_string() }
}
}
impl From<convert::Infallible> for AdsError{
fn from(_error: convert::Infallible) -> Self {
AdsError {n_error : 1, s_msg : String::from("") }
}
}
#[derive(Copy, Clone)]
pub enum AdsTransMode {
ServerCycle = 3,
OnChange = 4
}
pub struct AdsNotificationAttrib {
pub cb_length : u32,
pub trans_mode : AdsTransMode,
pub max_delay : u32,
pub cycle_time : u32
}
#[derive(Debug)]
#[derive(Default)]
#[derive(PartialEq)]
#[derive(Eq)]
pub struct AdsStampHeader {
pub timestamp : u64,
pub samples : u32
}
#[derive(Debug)]
#[derive(Default)]
#[derive(PartialEq)]
#[derive(Eq)]
pub struct AdsNotificationSample {
pub not_hdl : u32,
pub sample_size : u32
}
#[derive(Default)]
#[derive(Debug)]
pub struct HandleData {
pub ams_err : u32,
pub payload : Option<Bytes>
}
#[derive(Debug)]
pub struct Handle {
pub cmd_type : AdsCommand,
pub invoke_id : u32,
pub data : HandleData,
pub timestamp : Instant, }
#[derive(Debug)]
pub struct NotHandle {
pub callback : Notification,
pub not_hdl : u32,
pub user_data : Option<Arc<Mutex<BytesMut>>>,
}
#[derive(Debug)]
pub enum AdsTimeout {
DefaultTimeout,
CustomTimeout(u64)
}
#[derive(Default)]
#[derive(Debug)]
#[derive(PartialEq)]
pub struct StateInfo {
pub ads_state : AdsState,
pub device_state : u16
}
#[derive(Debug)]
pub struct DeviceStateInfo {
pub major : u8,
pub minor : u8,
pub build : u16,
pub device_name : String
}
#[derive(Copy, Clone)]
#[allow(dead_code)]
#[derive(Debug)]
pub enum AdsCommand {
Invalid = 0,
ReadDeviceInfo = 1,
Read = 2,
Write = 3,
ReadState = 4,
WriteControl = 5,
AddDeviceNotification = 6,
DeleteDeviceNotification = 7,
DeviceNotification = 8,
ReadWrite = 9
}
impl Default for AdsCommand {
fn default() -> Self { AdsCommand::Invalid }
}
impl TryFrom<u16> for AdsCommand{
type Error = AdsError;
fn try_from(v: u16) -> Result<Self> {
match v {
x if x == AdsCommand::ReadDeviceInfo as u16 => Ok(AdsCommand::ReadDeviceInfo),
x if x == AdsCommand::Read as u16 => Ok(AdsCommand::Read),
x if x == AdsCommand::Write as u16 => Ok(AdsCommand::Write),
x if x == AdsCommand::ReadState as u16 => Ok(AdsCommand::ReadState),
x if x == AdsCommand::WriteControl as u16 => Ok(AdsCommand::WriteControl),
x if x == AdsCommand::AddDeviceNotification as u16 => Ok(AdsCommand::AddDeviceNotification),
x if x == AdsCommand::DeleteDeviceNotification as u16 => Ok(AdsCommand::DeleteDeviceNotification),
x if x == AdsCommand::DeviceNotification as u16 => Ok(AdsCommand::DeviceNotification),
x if x == AdsCommand::ReadWrite as u16 => Ok(AdsCommand::ReadWrite),
_ => Err(AdsError{n_error : 1, s_msg : String::from("AdsCommand: Conversion from u16 failed")})
}
}
}
#[derive(Copy, Clone)]
#[allow(dead_code)]
#[derive(PartialEq)]
#[derive(Debug)]
pub enum AdsState {
Invalid = 0,
Idle = 1,
Reset = 2,
Init = 3,
Start = 4,
Run = 5,
Stop = 6,
SaveCFG = 7,
LoadCFG = 8,
Powerfailure = 9,
PowerGood = 10,
Error = 11,
Shutdown = 12,
Suspend = 13,
Resume = 14,
Config = 15, Reconfig = 16, }
impl Default for AdsState {
fn default() -> Self { AdsState::Invalid }
}
impl TryFrom<u16> for AdsState {
type Error = AdsError;
fn try_from(v: u16) -> Result<Self> {
match v {
x if x == AdsState::Invalid as u16 => Ok(AdsState::Invalid),
x if x == AdsState::Idle as u16 => Ok(AdsState::Idle),
x if x == AdsState::Reset as u16 => Ok(AdsState::Reset),
x if x == AdsState::Init as u16 => Ok(AdsState::Init),
x if x == AdsState::Start as u16 => Ok(AdsState::Start),
x if x == AdsState::Run as u16 => Ok(AdsState::Run),
x if x == AdsState::Stop as u16 => Ok(AdsState::Stop),
x if x == AdsState::SaveCFG as u16 => Ok(AdsState::SaveCFG),
x if x == AdsState::LoadCFG as u16 => Ok(AdsState::LoadCFG),
x if x == AdsState::Powerfailure as u16 => Ok(AdsState::Powerfailure),
x if x == AdsState::PowerGood as u16 => Ok(AdsState::PowerGood),
x if x == AdsState::Error as u16 => Ok(AdsState::Error),
x if x == AdsState::Shutdown as u16 => Ok(AdsState::Shutdown),
x if x == AdsState::Suspend as u16 => Ok(AdsState::Suspend),
x if x == AdsState::Resume as u16 => Ok(AdsState::Resume),
x if x == AdsState::Config as u16 => Ok(AdsState::Config),
x if x == AdsState::Reconfig as u16 => Ok(AdsState::Reconfig),
_ => Err(AdsError{n_error : 1, s_msg : String::from("AdsState: Conversion from u16 failed")})
}
}
}
#[derive(Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Clone, Copy, PartialOrd)]
#[repr(u32)]
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
pub enum AdsErrorCode {
ERR_NOERROR = 0,
ERR_INTERNAL = 1,
ERR_NORTIME = 2,
ERR_ALLOCLOCKEDMEM = 3,
ERR_INSERTMAILBOX = 4,
ERR_WRONGRECEIVEHMSG = 5,
ERR_TARGETPORTNOTFOUND = 6,
ERR_TARGETMACHINENOTFOUND = 7,
ERR_UNKNOWNCMDID = 8,
ERR_BADTASKID = 9,
ERR_NOIO = 10,
ERR_UNKNOWNAMSCMD = 11,
ERR_WIN32ERROR = 12,
ERR_PORTNOTCONNECTED = 13,
ERR_INVALIDAMSLENGTH = 14,
ERR_INVALIDAMSNETID = 15,
ERR_LOWINSTLEVEL = 16,
ERR_NODEBUGINTAVAILABLE = 17,
ERR_PORTDISABLED = 18,
ERR_PORTALREADYCONNECTED = 19,
ERR_AMSSYNC_W32ERROR = 20,
ERR_AMSSYNC_TIMEOUT = 21,
ERR_AMSSYNC_AMSERROR = 22,
ERR_AMSSYNC_NOINDEXINMAP = 23,
ERR_INVALIDAMSPORT = 24,
ERR_NOMEMORY = 25,
ERR_TCPSEND = 26,
ERR_HOSTUNREACHABLE = 27,
ERR_INVALIDAMSFRAGMENT = 28,
ERR_TLSSEND = 29,
ERR_ACCESSDENIED = 30,
ROUTERERR_NOLOCKEDMEMORY = 1280,
ROUTERERR_RESIZEMEMORY = 1281,
ROUTERERR_MAILBOXFULL = 1282,
ROUTERERR_DEBUGBOXFULL = 1283,
ROUTERERR_UNKNOWNPORTTYPE = 1284,
ROUTERERR_NOTINITIALIZED = 1285,
ROUTERERR_PORTALREADYINUSE = 1286,
ROUTERERR_NOTREGISTERED = 1287,
ROUTERERR_NOMOREQUEUES = 1288,
ROUTERERR_INVALIDPORT = 1289,
ROUTERERR_NOTACTIVATED = 1290,
ROUTERERR_FRAGMENTBOXFULL = 1291,
ROUTERERR_FRAGMENTTIMEOUT = 1292,
ROUTERERR_TOBEREMOVED = 1293,
ADSERR_DEVICE_ERROR = 1792,
ADSERR_DEVICE_SRVNOTSUPP = 1793,
ADSERR_DEVICE_INVALIDGRP = 1794,
ADSERR_DEVICE_INVALIDOFFSET = 1795,
ADSERR_DEVICE_INVALIDACCESS = 1796,
ADSERR_DEVICE_INVALIDSIZE = 1797,
ADSERR_DEVICE_INVALIDDATA = 1798,
ADSERR_DEVICE_NOTREADY = 1799,
ADSERR_DEVICE_BUSY = 1800,
ADSERR_DEVICE_INVALIDCONTEXT = 1801,
ADSERR_DEVICE_NOMEMORY = 1802,
ADSERR_DEVICE_INVALIDPARM = 1803,
ADSERR_DEVICE_NOTFOUND = 1804,
ADSERR_DEVICE_SYNTAX = 1805,
ADSERR_DEVICE_INCOMPATIBLE = 1806,
ADSERR_DEVICE_EXISTS = 1807,
ADSERR_DEVICE_SYMBOLNOTFOUND = 1808,
ADSERR_DEVICE_SYMBOLVERSIONINVALID = 1809,
ADSERR_DEVICE_INVALIDSTATE = 1810,
ADSERR_DEVICE_TRANSMODENOTSUPP = 1811,
ADSERR_DEVICE_NOTIFYHNDINVALID = 1812,
ADSERR_DEVICE_CLIENTUNKNOWN = 1813,
ADSERR_DEVICE_NOMOREHDLS = 1814,
ADSERR_DEVICE_INVALIDWATCHSIZE = 1815,
ADSERR_DEVICE_NOTINIT = 1816,
ADSERR_DEVICE_TIMEOUT = 1817,
ADSERR_DEVICE_NOINTERFACE = 1818,
ADSERR_DEVICE_INVALIDINTERFACE = 1819,
ADSERR_DEVICE_INVALIDCLSID = 1820,
ADSERR_DEVICE_INVALIDOBJID = 1821,
ADSERR_DEVICE_PENDING = 1822,
ADSERR_DEVICE_ABORTED = 1823,
ADSERR_DEVICE_WARNING = 1824,
ADSERR_DEVICE_INVALIDARRAYIDX = 1825,
ADSERR_DEVICE_SYMBOLNOTACTIVE = 1826,
ADSERR_DEVICE_ACCESSDENIED = 1827,
ADSERR_DEVICE_LICENSENOTFOUND = 1828,
ADSERR_DEVICE_LICENSEEXPIRED = 1829,
ADSERR_DEVICE_LICENSEEXCEEDED = 1830,
ADSERR_DEVICE_LICENSEINVALID = 1831,
ADSERR_DEVICE_LICENSESYSTEMID = 1832,
ADSERR_DEVICE_LICENSENOTIMELIMIT = 1833,
ADSERR_DEVICE_LICENSEFUTUREISSUE = 1834,
ADSERR_DEVICE_LICENSETIMETOLONG = 1835,
ADSERR_DEVICE_EXCEPTION = 1836,
ADSERR_DEVICE_LICENSEDUPLICATED = 1837,
ADSERR_DEVICE_SIGNATUREINVALID = 1838,
ADSERR_DEVICE_CERTIFICATEINVALID = 1839,
ADSERR_DEVICE_LICENSEOEMNOTFOUND = 1840,
ADSERR_DEVICE_LICENSERESTRICTED = 1841,
ADSERR_DEVICE_LICENSEDEMODENIED = 1842,
ADSERR_DEVICE_INVALIDFNCID = 1843,
ADSERR_DEVICE_OUTOFRANGE = 1844,
ADSERR_DEVICE_INVALIDALIGNMENT = 1845,
ADSERR_DEVICE_LICENSEPLATFORM = 1846,
ADSERR_DEVICE_FORWARD_PL = 1847,
ADSERR_DEVICE_FORWARD_DL = 1848,
ADSERR_DEVICE_FORWARD_RT = 1849,
ADSERR_CLIENT_ERROR = 1856,
ADSERR_CLIENT_INVALIDPARM = 1857,
ADSERR_CLIENT_LISTEMPTY = 1858,
ADSERR_CLIENT_VARUSED = 1859,
ADSERR_CLIENT_DUPLINVOKEID = 1860,
ADSERR_CLIENT_SYNCTIMEOUT = 1861,
ADSERR_CLIENT_W32ERROR = 1862,
ADSERR_CLIENT_TIMEOUTINVALID = 1863,
ADSERR_CLIENT_PORTNOTOPEN = 1864,
ADSERR_CLIENT_NOAMSADDR = 1865,
ADSERR_CLIENT_SYNCINTERNAL = 1872,
ADSERR_CLIENT_ADDHASH = 1873,
ADSERR_CLIENT_REMOVEHASH = 1874,
ADSERR_CLIENT_NOMORESYM = 1875,
ADSERR_CLIENT_SYNCRESINVALID = 1876,
ADSERR_CLIENT_SYNCPORTLOCKED = 1877,
ADSERR_CLIENT_REQUESTCANCELLED = 1878,
RTERR_INTERNAL = 4096,
RTERR_BADTIMERPERIODS = 4097,
RTERR_INVALIDTASKPTR = 4098,
RTERR_INVALIDSTACKPTR = 4099,
RTERR_PRIOEXISTS = 4100,
RTERR_NOMORETCB = 4101,
RTERR_NOMORESEMAS = 4102,
RTERR_NOMOREQUEUES = 4103,
RTERR_EXTIRQALREADYDEF = 4109,
RTERR_EXTIRQNOTDEF = 4110,
RTERR_EXTIRQINSTALLFAILED = 4111,
RTERR_IRQLNOTLESSOREQUAL = 4112,
RTERR_VMXNOTSUPPORTED = 4119,
RTERR_VMXDISABLED = 4120,
RTERR_VMXCONTROLSMISSING = 4121,
RTERR_VMXENABLEFAILS = 4122,
WSAETIMEDOUT = 10060,
WSAECONNREFUSED = 10061,
WSAEHOSTUNREACH = 10065,
UNKNOWN,
}
impl From<AdsError> for AdsErrorCode {
fn from(value: AdsError) -> Self {
AdsErrorCode::try_from(value.n_error).unwrap_or(AdsErrorCode::UNKNOWN)
}
}