Hi, I had an issue trying to make a test cardreader PD in python on Windows with submit_event(). After bashing my head into a wall with Claude for a while I managed to fix the issue.
Full transparency: I'm very much out of my depth here, so here is Claude's synopsis on what went wrong and how to fix it. Apologies for the AI slop.
Summary
osdp_pd_submit_event() silently fails on Windows builds because the IS_ENABLED() macro evaluates incorrectly under MSVC's legacy preprocessor, creating a code path mismatch between the Python C extension and the core library.
Root Cause
libosdp uses a Linux kernel-style IS_ENABLED() macro (from c-utils/include/utils/utils.h):
#define __IS_ENABLED1(x) __IS_ENABLED2(__XXXX ## x)
#define __XXXX1 __YYYY,
#define __IS_ENABLED2(y) __IS_ENABLED3(y 1, 0)
#define __IS_ENABLED3(_i, val, ...) val
#define IS_ENABLED(x) __IS_ENABLED1(x)
This relies on token-pasting:
When OPT_OSDP_APP_OWNED_QUEUE_DATA=1, __XXXX ## 1 → __XXXX1 → expands to __YYYY, which injects a comma and makes __IS_ENABLED3 return 1.
MSVC's legacy preprocessor does not expand macro arguments before ## token pasting like GCC/Clang do.
Result:
IS_ENABLED(OPT_OSDP_APP_OWNED_QUEUE_DATA) evaluates to 0 on MSVC even when the flag is defined.
This creates a mismatch:
File | Guard | Evaluates to | Behavior
-- | -- | -- | --
python/osdp_sys/pd.c | #ifdef OPT_OSDP_APP_OWNED_QUEUE_DATA | true | Allocates event with calloc, calls osdp_pd_submit_event()
src/osdp_pd.c | IS_ENABLED(OPT_OSDP_APP_OWNED_QUEUE_DATA) | false | Takes !IS_ENABLED branch → calls pd_event_alloc()
src/osdp_pd.c | #ifndef OPT_OSDP_APP_OWNED_QUEUE_DATA | false | pd_event_alloc() compiled as no-op returning NULL
So:
osdp_pd_submit_event()
-> pd_event_alloc()
-> returns NULL
-> return -1
Python wrapper converts this to:
PeripheralDevice.submit_event(...) -> False
No events are queued or sent.
Impact
On Windows:
-
PeripheralDevice.submit_event() always returns False
-
No card reads / keypad / manufacturer events sent
-
PD replies to POLL with
ACK (0x40) instead of REPLY_RAW (0x50)
-
Appears as if event submission is broken
Affected Versions
-
libosdp 3.2.0 (PyPI Windows wheel)
-
Any build using
IS_ENABLED() with MSVC legacy preprocessor
Fix Options
Option A — Compiler flag (workaround)
Enable conformant MSVC preprocessor:
set CL=/Zc:preprocessor
pip install --no-binary :all: --no-cache-dir libosdp==3.2.0
This fixes IS_ENABLED() evaluation.
Option B — Code fix (preferred)
Make both files use identical guards.
In src/osdp_pd.c:
// Before
if (IS_ENABLED(OPT_OSDP_APP_OWNED_QUEUE_DATA)) {
// After
#ifdef OPT_OSDP_APP_OWNED_QUEUE_DATA
This matches python/osdp_sys/pd.c and avoids macro dependence.
Option C — Disable flag (alternate path)
Requires full Git source (PyPI tarball missing slab.c):
set OPT_OSDP_APP_OWNED_QUEUE_DATA=off
pip install "git+https://github.com/goToMain/libosdp@v3.2.0#egg=libosdp&subdirectory=python"
Additional Issue
PyPI source tarball for v3.2.0 is missing:
When building with:
OPT_OSDP_APP_OWNED_QUEUE_DATA=off
Build fails:
RuntimeError: Path 'vendor\utils/src/slab.c' does not exist
Full Git clone (with submodules) is required.
Suggested Resolution
Either:
-
Replace
IS_ENABLED() with #ifdef in src/osdp_pd.c
-
Or force
/Zc:preprocessor in Windows build flags
-
Or remove mixed guard usage across compilation units
This restores correct event submission on Windows.
Hi, I had an issue trying to make a test cardreader PD in python on Windows with submit_event(). After bashing my head into a wall with Claude for a while I managed to fix the issue.
Full transparency: I'm very much out of my depth here, so here is Claude's synopsis on what went wrong and how to fix it. Apologies for the AI slop.
Summary
osdp_pd_submit_event()silently fails on Windows builds because theIS_ENABLED()macro evaluates incorrectly under MSVC's legacy preprocessor, creating a code path mismatch between the Python C extension and the core library.Root Cause
libosdp uses a Linux kernel-style
IS_ENABLED()macro (fromc-utils/include/utils/utils.h):This relies on token-pasting:
When
OPT_OSDP_APP_OWNED_QUEUE_DATA=1,__XXXX ## 1→__XXXX1→ expands to__YYYY,which injects a comma and makes__IS_ENABLED3return1.MSVC's legacy preprocessor does not expand macro arguments before
##token pasting like GCC/Clang do.Result:
IS_ENABLED(OPT_OSDP_APP_OWNED_QUEUE_DATA)evaluates to 0 on MSVC even when the flag is defined.This creates a mismatch:
So:
Python wrapper converts this to:
No events are queued or sent.
Impact
On Windows:
PeripheralDevice.submit_event()always returnsFalseACK (0x40)instead ofREPLY_RAW (0x50)Affected Versions
IS_ENABLED()with MSVC legacy preprocessorFix Options
Option A — Compiler flag (workaround)
Enable conformant MSVC preprocessor:
This fixes
IS_ENABLED()evaluation.Option B — Code fix (preferred)
Make both files use identical guards.
In
src/osdp_pd.c:This matches
python/osdp_sys/pd.cand avoids macro dependence.Option C — Disable flag (alternate path)
Requires full Git source (PyPI tarball missing slab.c):
Additional Issue
PyPI source tarball for v3.2.0 is missing:
When building with:
Build fails:
Full Git clone (with submodules) is required.
Suggested Resolution
Either:
IS_ENABLED()with#ifdefinsrc/osdp_pd.c/Zc:preprocessorin Windows build flagsThis restores correct event submission on Windows.