Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix bad cli_as_callback implementation, fix #474 #506

Merged
merged 1 commit into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/build-and-test-amd64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ jobs:
test-wheels-unix-86_64:
name: Testing wheels for AMD64 unix
needs: [linux-build, osx-build]
continue-on-error: true
runs-on: ${{ matrix.os }}
strategy:
matrix:
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/windows-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ on:
branches: [master]
jobs:
windows_wheel:
continue-on-error: true
strategy:
matrix:
runs-on: [ "windows-2022", "windows-2019" ]
Expand Down
30 changes: 25 additions & 5 deletions snap7/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

import re
import logging
from ctypes import byref, create_string_buffer, sizeof
from ctypes import CFUNCTYPE, byref, create_string_buffer, sizeof
from ctypes import Array, c_byte, c_char_p, c_int, c_int32, c_uint16, c_ulong, c_void_p
from datetime import datetime
from typing import List, Optional, Tuple, Union
from typing import Any, Callable, List, Optional, Tuple, Union

from ..common import check_error, ipv4, load_library
from ..types import S7SZL, Areas, BlocksList, S7CpInfo, S7CpuInfo, S7DataItem
Expand Down Expand Up @@ -947,9 +947,29 @@ def check_as_completion(self, p_value) -> int:
check_error(result, context="client")
return result

def set_as_callback(self, pfn_clicompletion, p_usr):
# Cli_SetAsCallback
result = self._library.Cli_SetAsCallback(self._pointer, pfn_clicompletion, p_usr)
def set_as_callback(self, call_back: Callable[..., Any]) -> int:
logger.info("setting event callback")
callback_wrap: Callable[..., Any] = CFUNCTYPE(None, c_void_p, c_int, c_int)

def wrapper(usrptr: Optional[c_void_p], op_code: int, op_result: int) -> int:
"""Wraps python function into a ctypes function

Args:
usrptr: not used
op_code:
op_result:

Returns:
Should return an int
"""
logger.info(f"callback event: op_code: {op_code} op_result: {op_result}")
call_back(op_code, op_result)
return 0

self._callback = callback_wrap(wrapper)
usrPtr = c_void_p()

result = self._library.Cli_SetAsCallback(self._pointer, self._callback, usrPtr)
check_error(result, context="client")
return result

Expand Down
34 changes: 19 additions & 15 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import time
import pytest
import unittest
import platform
from datetime import datetime, timedelta, date
from multiprocessing import Process
from unittest import mock
Expand All @@ -17,7 +16,7 @@
from snap7 import util
from snap7.common import check_error
from snap7.server import mainloop
from snap7.types import S7AreaDB, S7DataItem, S7SZL, S7SZLList, buffer_type, buffer_size, S7Object, Areas, WordLen
from snap7.types import S7AreaDB, S7DataItem, S7SZL, S7SZLList, buffer_type, buffer_size, Areas, WordLen


logging.basicConfig(level=logging.WARNING)
Expand Down Expand Up @@ -989,23 +988,28 @@ def test_write_multi_vars(self):
self.assertEqual(expected_list[1], self.client.ct_read(0, 2))
self.assertEqual(expected_list[2], self.client.tm_read(0, 2))

@unittest.skipIf(platform.system() in ["Windows", "Darwin"], "Access Violation error")
def test_set_as_callback(self):
expected = b"\x11\x11"
self.callback_counter = 0
cObj = ctypes.cast(ctypes.pointer(ctypes.py_object(self)), S7Object)
def event_call_back(op_code, op_result):
logging.info(f"callback event: {op_code} op_result: {op_result}")

def callback(FUsrPtr, JobOp, response):
self = ctypes.cast(FUsrPtr, ctypes.POINTER(ctypes.py_object)).contents.value
self.callback_counter += 1
self.client.set_as_callback(event_call_back)

cfunc_type = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.POINTER(S7Object), ctypes.c_int, ctypes.c_int)
self.client.set_as_callback(cfunc_type(callback), cObj)
self.client.as_ct_write(0, 1, bytearray(expected))

self._as_check_loop()
self.assertEqual(expected, self.client.ct_read(0, 1))
self.assertEqual(1, self.callback_counter)
# expected = b"\x11\x11"
# self.callback_counter = 0
# cObj = ctypes.cast(ctypes.pointer(ctypes.py_object(self)), S7Object)

# def callback(FUsrPtr, JobOp, response):
# self = ctypes.cast(FUsrPtr, ctypes.POINTER(ctypes.py_object)).contents.value
# self.callback_counter += 1
#
# cfunc_type = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.POINTER(S7Object), ctypes.c_int, ctypes.c_int)
# self.client.set_as_callback(cfunc_type(callback), cObj)
# self.client.as_ct_write(0, 1, bytearray(expected))

# self._as_check_loop()
# self.assertEqual(expected, self.client.ct_read(0, 1))
# self.assertEqual(1, self.callback_counter)


@pytest.mark.client
Expand Down
Loading