def write(self, value: bytes, request: AmsPacket = None): """Update the variable value, respecting notifications""" if self.value != value: if self.notifications: header = structs.SAdsNotificationHeader() header.hNotification = 0 header.nTimeStamp = dt_to_filetime(datetime.now()) header.cbSampleSize = len(value) # Perform byte-write into the header dst = ctypes.addressof( header) + structs.SAdsNotificationHeader.data.offset ctypes.memmove(dst, value, len(value)) for notification_handle in self.notifications: # It's hard to guess the exact AmsAddr from here, so instead # ignore the address and search for the note_handle for key, func in callback_store.items(): # callback_store is keyed by (AmsAddr, int) if key[1] != notification_handle: continue header.hNotification = notification_handle addr = key[0] # Call c-wrapper for user callback func(addr.amsAddrStruct(), header, 0) self.value = value
def test_notification_decorator_filetime(self): # type: () -> None """Test passthrough of FILETIME value by notification decorator""" @self.plc.notification(timestamp_as_filetime=True) def callback(handle, name, timestamp, value): self.assertEqual(timestamp, 132223104000000000) notification = structs.SAdsNotificationHeader() notification.nTimeStamp = 132223104000000000 notification.cbSampleSize = 1 notification.data = 5 callback(pointer(notification), "TestName")
def create_notification_struct(self, payload): # type: (bytes) -> structs.SAdsNotificationHeader buf = b"\x00" * 12 # hNotification, nTimeStamp buf += struct.pack("<i", len(payload)) buf += payload notification = structs.SAdsNotificationHeader() resize(notification, len(buf)) memmove( pointer(notification), (ctypes.c_ubyte * len(buf)).from_buffer_copy(buf), sizeof(notification), ) return notification
def create_notification_struct(payload: bytes) -> \ structs.SAdsNotificationHeader: """Create notification callback structure""" buf = b"\x00" * 12 # hNotification, nTimeStamp buf += struct.pack("<i", len(payload)) buf += payload notification = structs.SAdsNotificationHeader() resize(notification, len(buf)) memmove( pointer(notification), (ctypes.c_ubyte * len(buf)).from_buffer_copy(buf), sizeof(notification), ) return notification
def test_notification_decorator(self): # type: () -> None """Test decoding of header by notification decorator""" @self.plc.notification() def callback(handle, name, timestamp, value): self.assertEqual(handle, 1234) self.assertEqual(name, "TestName") self.assertEqual(timestamp, datetime.datetime(2020, 1, 1)) self.assertEqual(value, bytearray((5, ))) notification = structs.SAdsNotificationHeader() notification.hNotification = 1234 notification.nTimeStamp = 132223104000000000 notification.cbSampleSize = 1 notification.data = 5 callback(pointer(notification), "TestName")