feat(protocan): вынеси GUI-кадрирование в общий ABI
This commit is contained in:
@@ -6,6 +6,7 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
|
|||||||
|
|
||||||
# Ядро библиотеки: платформенных зависимостей нет, собирается под что угодно.
|
# Ядро библиотеки: платформенных зависимостей нет, собирается под что угодно.
|
||||||
set(PCAN_CORE_SOURCES
|
set(PCAN_CORE_SOURCES
|
||||||
|
src/gui_frame.c
|
||||||
src/pcan_abi.c
|
src/pcan_abi.c
|
||||||
src/pcan_crc.c
|
src/pcan_crc.c
|
||||||
src/pcan_frame.c
|
src/pcan_frame.c
|
||||||
|
|||||||
@@ -36,6 +36,15 @@ typedef struct {
|
|||||||
uint8_t data[8];
|
uint8_t data[8];
|
||||||
} pcan_abi_frame_t;
|
} pcan_abi_frame_t;
|
||||||
|
|
||||||
|
#define PCAN_ABI_GUI_PAYLOAD_MAX 512U
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t sequence;
|
||||||
|
uint16_t size;
|
||||||
|
uint8_t message_type;
|
||||||
|
uint8_t payload[PCAN_ABI_GUI_PAYLOAD_MAX];
|
||||||
|
} pcan_abi_gui_frame_t;
|
||||||
|
|
||||||
PCAN_ABI_API uint32_t pcan_abi_version(void);
|
PCAN_ABI_API uint32_t pcan_abi_version(void);
|
||||||
|
|
||||||
PCAN_ABI_API uint32_t pcan_abi_id_pack(uint8_t priority, uint8_t route,
|
PCAN_ABI_API uint32_t pcan_abi_id_pack(uint8_t priority, uint8_t route,
|
||||||
@@ -67,6 +76,21 @@ PCAN_ABI_API int pcan_abi_parser_stats(const void *parser_storage,
|
|||||||
uint32_t *bad_length,
|
uint32_t *bad_length,
|
||||||
uint32_t *stray_bytes);
|
uint32_t *stray_bytes);
|
||||||
|
|
||||||
|
PCAN_ABI_API uint32_t pcan_abi_gui_crc32(const uint8_t *data, size_t size);
|
||||||
|
PCAN_ABI_API size_t pcan_abi_gui_frame_encode(
|
||||||
|
uint8_t message_type, uint16_t sequence,
|
||||||
|
const uint8_t *payload, uint16_t payload_size,
|
||||||
|
uint8_t *output, size_t output_size);
|
||||||
|
PCAN_ABI_API size_t pcan_abi_gui_parser_size(void);
|
||||||
|
PCAN_ABI_API int pcan_abi_gui_parser_init(void *parser_storage,
|
||||||
|
size_t storage_size);
|
||||||
|
PCAN_ABI_API int pcan_abi_gui_parser_push(void *parser_storage, uint8_t byte,
|
||||||
|
pcan_abi_gui_frame_t *output);
|
||||||
|
PCAN_ABI_API int pcan_abi_gui_parser_stats(
|
||||||
|
const void *parser_storage, uint32_t *frames, uint32_t *crc_errors,
|
||||||
|
uint32_t *version_errors, uint32_t *length_errors,
|
||||||
|
uint32_t *stray_bytes);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ include $(CLEAR_VARS)
|
|||||||
LOCAL_MODULE := setcore
|
LOCAL_MODULE := setcore
|
||||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../include
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../include
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
|
../../src/gui_frame.c \
|
||||||
../../src/pcan_abi.c \
|
../../src/pcan_abi.c \
|
||||||
../../src/pcan_crc.c \
|
../../src/pcan_crc.c \
|
||||||
../../src/pcan_frame.c \
|
../../src/pcan_frame.c \
|
||||||
|
|||||||
@@ -30,4 +30,13 @@ object NativeProtoCan {
|
|||||||
external fun nativeDestroyParser(handle: Long)
|
external fun nativeDestroyParser(handle: Long)
|
||||||
external fun nativeFeedParser(handle: Long, input: ByteArray): ByteArray?
|
external fun nativeFeedParser(handle: Long, input: ByteArray): ByteArray?
|
||||||
external fun nativeParserStats(handle: Long): IntArray?
|
external fun nativeParserStats(handle: Long): IntArray?
|
||||||
|
external fun nativeGuiEncode(
|
||||||
|
messageType: Int,
|
||||||
|
sequence: Int,
|
||||||
|
input: ByteArray,
|
||||||
|
): ByteArray?
|
||||||
|
external fun nativeCreateGuiParser(): Long
|
||||||
|
external fun nativeDestroyGuiParser(handle: Long)
|
||||||
|
external fun nativeFeedGuiParser(handle: Long, input: ByteArray): ByteArray?
|
||||||
|
external fun nativeGuiParserStats(handle: Long): IntArray?
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ typedef struct {
|
|||||||
uint32_t sequence_lost;
|
uint32_t sequence_lost;
|
||||||
} android_parser_t;
|
} android_parser_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t *storage;
|
||||||
|
size_t storage_size;
|
||||||
|
} android_gui_parser_t;
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_ru_setcorp_setcore_NativeProtoCan_nativeAbiVersion(JNIEnv *env, jobject self)
|
Java_ru_setcorp_setcore_NativeProtoCan_nativeAbiVersion(JNIEnv *env, jobject self)
|
||||||
{
|
{
|
||||||
@@ -207,3 +212,106 @@ Java_ru_setcorp_setcore_NativeProtoCan_nativeParserStats(
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jbyteArray JNICALL
|
||||||
|
Java_ru_setcorp_setcore_NativeProtoCan_nativeGuiEncode(
|
||||||
|
JNIEnv *env, jobject self, jint message_type, jint sequence,
|
||||||
|
jbyteArray input)
|
||||||
|
{
|
||||||
|
(void)self;
|
||||||
|
jsize size = (*env)->GetArrayLength(env, input);
|
||||||
|
if (size > (jsize)PCAN_ABI_GUI_PAYLOAD_MAX) return NULL;
|
||||||
|
jbyte *data = (*env)->GetByteArrayElements(env, input, NULL);
|
||||||
|
uint8_t output[PCAN_ABI_GUI_PAYLOAD_MAX + 12U];
|
||||||
|
size_t written = pcan_abi_gui_frame_encode(
|
||||||
|
(uint8_t)message_type, (uint16_t)sequence, (const uint8_t *)data,
|
||||||
|
(uint16_t)size, output, sizeof output);
|
||||||
|
if (data != NULL) (*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT);
|
||||||
|
if (written == 0U) return NULL;
|
||||||
|
jbyteArray result = (*env)->NewByteArray(env, (jsize)written);
|
||||||
|
if (result != NULL) {
|
||||||
|
(*env)->SetByteArrayRegion(env, result, 0, (jsize)written,
|
||||||
|
(const jbyte *)output);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jlong JNICALL
|
||||||
|
Java_ru_setcorp_setcore_NativeProtoCan_nativeCreateGuiParser(JNIEnv *env, jobject self)
|
||||||
|
{
|
||||||
|
(void)env; (void)self;
|
||||||
|
android_gui_parser_t *parser = (android_gui_parser_t *)calloc(1U, sizeof *parser);
|
||||||
|
if (parser == NULL) return 0;
|
||||||
|
parser->storage_size = pcan_abi_gui_parser_size();
|
||||||
|
parser->storage = (uint8_t *)malloc(parser->storage_size);
|
||||||
|
if ((parser->storage == NULL) ||
|
||||||
|
!pcan_abi_gui_parser_init(parser->storage, parser->storage_size)) {
|
||||||
|
free(parser->storage); free(parser); return 0;
|
||||||
|
}
|
||||||
|
return (jlong)(intptr_t)parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_ru_setcorp_setcore_NativeProtoCan_nativeDestroyGuiParser(
|
||||||
|
JNIEnv *env, jobject self, jlong handle)
|
||||||
|
{
|
||||||
|
(void)env; (void)self;
|
||||||
|
android_gui_parser_t *parser = (android_gui_parser_t *)(intptr_t)handle;
|
||||||
|
if (parser != NULL) { free(parser->storage); free(parser); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Records: type[1], sequence LE[2], size LE[2], payload[size]. */
|
||||||
|
JNIEXPORT jbyteArray JNICALL
|
||||||
|
Java_ru_setcorp_setcore_NativeProtoCan_nativeFeedGuiParser(
|
||||||
|
JNIEnv *env, jobject self, jlong handle, jbyteArray input)
|
||||||
|
{
|
||||||
|
(void)self;
|
||||||
|
android_gui_parser_t *parser = (android_gui_parser_t *)(intptr_t)handle;
|
||||||
|
if (parser == NULL) return NULL;
|
||||||
|
jsize size = (*env)->GetArrayLength(env, input);
|
||||||
|
jbyte *data = (*env)->GetByteArrayElements(env, input, NULL);
|
||||||
|
size_t capacity = (size_t)size + ((size_t)size / 12U + 2U) * 5U + 512U;
|
||||||
|
uint8_t *records = (uint8_t *)malloc(capacity);
|
||||||
|
if (records == NULL) {
|
||||||
|
if (data != NULL) (*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
size_t used = 0U;
|
||||||
|
pcan_abi_gui_frame_t frame;
|
||||||
|
for (jsize i = 0; i < size; ++i) {
|
||||||
|
if (pcan_abi_gui_parser_push(parser->storage, (uint8_t)data[i], &frame) > 0) {
|
||||||
|
records[used++] = frame.message_type;
|
||||||
|
records[used++] = (uint8_t)frame.sequence;
|
||||||
|
records[used++] = (uint8_t)(frame.sequence >> 8);
|
||||||
|
records[used++] = (uint8_t)frame.size;
|
||||||
|
records[used++] = (uint8_t)(frame.size >> 8);
|
||||||
|
memcpy(&records[used], frame.payload, frame.size);
|
||||||
|
used += frame.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data != NULL) (*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT);
|
||||||
|
jbyteArray result = (*env)->NewByteArray(env, (jsize)used);
|
||||||
|
if ((result != NULL) && (used != 0U)) {
|
||||||
|
(*env)->SetByteArrayRegion(env, result, 0, (jsize)used,
|
||||||
|
(const jbyte *)records);
|
||||||
|
}
|
||||||
|
free(records);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jintArray JNICALL
|
||||||
|
Java_ru_setcorp_setcore_NativeProtoCan_nativeGuiParserStats(
|
||||||
|
JNIEnv *env, jobject self, jlong handle)
|
||||||
|
{
|
||||||
|
(void)self;
|
||||||
|
android_gui_parser_t *parser = (android_gui_parser_t *)(intptr_t)handle;
|
||||||
|
if (parser == NULL) return NULL;
|
||||||
|
uint32_t frames = 0U, crc = 0U, version = 0U, length = 0U, stray = 0U;
|
||||||
|
pcan_abi_gui_parser_stats(parser->storage, &frames, &crc, &version,
|
||||||
|
&length, &stray);
|
||||||
|
jint values[5] = { (jint)frames, (jint)crc, (jint)version,
|
||||||
|
(jint)length, (jint)stray };
|
||||||
|
jintArray result = (*env)->NewIntArray(env, 5);
|
||||||
|
if (result != NULL) (*env)->SetIntArrayRegion(env, result, 0, 5, values);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "pcan_crc.h"
|
#include "pcan_crc.h"
|
||||||
#include "pcan_frame.h"
|
#include "pcan_frame.h"
|
||||||
#include "pcan_id.h"
|
#include "pcan_id.h"
|
||||||
|
#include "gui_frame.h"
|
||||||
|
|
||||||
uint32_t pcan_abi_version(void)
|
uint32_t pcan_abi_version(void)
|
||||||
{
|
{
|
||||||
@@ -134,3 +135,69 @@ int pcan_abi_parser_stats(const void *parser_storage, uint32_t *frames,
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t pcan_abi_gui_crc32(const uint8_t *data, size_t size)
|
||||||
|
{
|
||||||
|
if ((data == NULL) && (size != 0U)) {
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
return gui_crc32(data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t pcan_abi_gui_frame_encode(uint8_t message_type, uint16_t sequence,
|
||||||
|
const uint8_t *payload,
|
||||||
|
uint16_t payload_size, uint8_t *output,
|
||||||
|
size_t output_size)
|
||||||
|
{
|
||||||
|
return gui_frame_encode(message_type, sequence, payload, payload_size,
|
||||||
|
output, output_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t pcan_abi_gui_parser_size(void)
|
||||||
|
{
|
||||||
|
return sizeof(gui_parser_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pcan_abi_gui_parser_init(void *parser_storage, size_t storage_size)
|
||||||
|
{
|
||||||
|
if ((parser_storage == NULL) || (storage_size < sizeof(gui_parser_t))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
gui_parser_init((gui_parser_t *)parser_storage);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pcan_abi_gui_parser_push(void *parser_storage, uint8_t byte,
|
||||||
|
pcan_abi_gui_frame_t *output)
|
||||||
|
{
|
||||||
|
gui_frame_t frame;
|
||||||
|
if ((parser_storage == NULL) || (output == NULL)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!gui_parser_push((gui_parser_t *)parser_storage, byte, &frame)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
output->message_type = frame.type;
|
||||||
|
output->sequence = frame.sequence;
|
||||||
|
output->size = frame.size;
|
||||||
|
if (frame.size != 0U) {
|
||||||
|
memcpy(output->payload, frame.payload, frame.size);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pcan_abi_gui_parser_stats(const void *parser_storage, uint32_t *frames,
|
||||||
|
uint32_t *crc_errors, uint32_t *version_errors,
|
||||||
|
uint32_t *length_errors, uint32_t *stray_bytes)
|
||||||
|
{
|
||||||
|
const gui_parser_t *parser = (const gui_parser_t *)parser_storage;
|
||||||
|
if (parser == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (frames != NULL) *frames = parser->stats.frames;
|
||||||
|
if (crc_errors != NULL) *crc_errors = parser->stats.crc_errors;
|
||||||
|
if (version_errors != NULL) *version_errors = parser->stats.version_errors;
|
||||||
|
if (length_errors != NULL) *length_errors = parser->stats.length_errors;
|
||||||
|
if (stray_bytes != NULL) *stray_bytes = parser->stats.stray_bytes;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -38,6 +38,37 @@ int main(void)
|
|||||||
(frame.data[0] != 0xAAU) || (frame.data[1] != 0xBBU)) {
|
(frame.data[0] != 0xAAU) || (frame.data[1] != 0xBBU)) {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t gui_raw[32];
|
||||||
|
size_t gui_size = pcan_abi_gui_frame_encode(
|
||||||
|
1U, 0x1234U, NULL, 0U, gui_raw, sizeof gui_raw);
|
||||||
|
static const uint8_t gui_want[] = {
|
||||||
|
0xA5U, 0x5AU, 0x01U, 0x01U, 0x12U, 0x34U, 0x00U, 0x00U,
|
||||||
|
0xEEU, 0x89U, 0x8CU, 0x9EU
|
||||||
|
};
|
||||||
|
if ((gui_size != sizeof gui_want) ||
|
||||||
|
(memcmp(gui_raw, gui_want, sizeof gui_want) != 0)) {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
size_t gui_parser_size = pcan_abi_gui_parser_size();
|
||||||
|
void *gui_parser = malloc(gui_parser_size);
|
||||||
|
pcan_abi_gui_frame_t gui_frame;
|
||||||
|
memset(&gui_frame, 0, sizeof gui_frame);
|
||||||
|
if ((gui_parser == NULL) ||
|
||||||
|
!pcan_abi_gui_parser_init(gui_parser, gui_parser_size)) {
|
||||||
|
free(gui_parser);
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
found = 0;
|
||||||
|
for (size_t i = 0U; i < gui_size; ++i) {
|
||||||
|
found += pcan_abi_gui_parser_push(gui_parser, gui_raw[i],
|
||||||
|
&gui_frame) > 0;
|
||||||
|
}
|
||||||
|
free(gui_parser);
|
||||||
|
if ((found != 1) || (gui_frame.message_type != 1U) ||
|
||||||
|
(gui_frame.sequence != 0x1234U) || (gui_frame.size != 0U)) {
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
puts("ABI tests passed");
|
puts("ABI tests passed");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ ROOT = Path(__file__).resolve().parent.parent
|
|||||||
INCLUDE = ROOT / "include"
|
INCLUDE = ROOT / "include"
|
||||||
SOURCES = [
|
SOURCES = [
|
||||||
ROOT / "src" / name for name in (
|
ROOT / "src" / name for name in (
|
||||||
"pcan_abi.c", "pcan_crc.c", "pcan_frame.c", "pcan_id.c",
|
"gui_frame.c", "pcan_abi.c", "pcan_crc.c", "pcan_frame.c", "pcan_id.c",
|
||||||
"pcan_link.c", "pcan_ring.c", "pcan_gas.c",
|
"pcan_link.c", "pcan_ring.c", "pcan_gas.c",
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
"""Переносимые модули ProtoCAN и тонкая обёртка общего C99-ядра."""
|
"""Переносимые модули ProtoCAN и тонкая обёртка общего C99-ядра."""
|
||||||
|
|
||||||
from .native import NativeCore, NativeCoreUnavailable, NativeFrame, NativeParser
|
from .native import (
|
||||||
|
NativeCore, NativeCoreUnavailable, NativeFrame, NativeGuiFrame,
|
||||||
|
NativeGuiParser, NativeParser,
|
||||||
|
)
|
||||||
|
|
||||||
__all__ = ["NativeCore", "NativeCoreUnavailable", "NativeFrame", "NativeParser"]
|
__all__ = [
|
||||||
|
"NativeCore", "NativeCoreUnavailable", "NativeFrame", "NativeGuiFrame",
|
||||||
|
"NativeGuiParser", "NativeParser",
|
||||||
|
]
|
||||||
|
|||||||
@@ -28,6 +28,15 @@ class _AbiFrame(ctypes.Structure):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class _AbiGuiFrame(ctypes.Structure):
|
||||||
|
_fields_ = [
|
||||||
|
("sequence", ctypes.c_uint16),
|
||||||
|
("size", ctypes.c_uint16),
|
||||||
|
("message_type", ctypes.c_uint8),
|
||||||
|
("payload", ctypes.c_uint8 * 512),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class NativeFrame:
|
class NativeFrame:
|
||||||
sequence: int
|
sequence: int
|
||||||
@@ -36,6 +45,13 @@ class NativeFrame:
|
|||||||
data: bytes
|
data: bytes
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class NativeGuiFrame:
|
||||||
|
message_type: int
|
||||||
|
sequence: int
|
||||||
|
payload: bytes
|
||||||
|
|
||||||
|
|
||||||
def _library_candidates() -> Iterable[Path | str]:
|
def _library_candidates() -> Iterable[Path | str]:
|
||||||
explicit = os.environ.get("SETCORE_LIBRARY")
|
explicit = os.environ.get("SETCORE_LIBRARY")
|
||||||
if explicit:
|
if explicit:
|
||||||
@@ -108,6 +124,24 @@ class NativeCore:
|
|||||||
ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32),
|
ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32),
|
||||||
]
|
]
|
||||||
lib.pcan_abi_parser_stats.restype = ctypes.c_int
|
lib.pcan_abi_parser_stats.restype = ctypes.c_int
|
||||||
|
lib.pcan_abi_gui_crc32.argtypes = [ctypes.c_void_p, ctypes.c_size_t]
|
||||||
|
lib.pcan_abi_gui_crc32.restype = ctypes.c_uint32
|
||||||
|
lib.pcan_abi_gui_frame_encode.argtypes = [
|
||||||
|
ctypes.c_uint8, ctypes.c_uint16, ctypes.c_void_p, ctypes.c_uint16,
|
||||||
|
ctypes.c_void_p, ctypes.c_size_t,
|
||||||
|
]
|
||||||
|
lib.pcan_abi_gui_frame_encode.restype = ctypes.c_size_t
|
||||||
|
lib.pcan_abi_gui_parser_size.restype = ctypes.c_size_t
|
||||||
|
lib.pcan_abi_gui_parser_init.argtypes = [ctypes.c_void_p, ctypes.c_size_t]
|
||||||
|
lib.pcan_abi_gui_parser_init.restype = ctypes.c_int
|
||||||
|
lib.pcan_abi_gui_parser_push.argtypes = [
|
||||||
|
ctypes.c_void_p, ctypes.c_uint8, ctypes.POINTER(_AbiGuiFrame),
|
||||||
|
]
|
||||||
|
lib.pcan_abi_gui_parser_push.restype = ctypes.c_int
|
||||||
|
lib.pcan_abi_gui_parser_stats.argtypes = [
|
||||||
|
ctypes.c_void_p, *(ctypes.POINTER(ctypes.c_uint32) for _ in range(5)),
|
||||||
|
]
|
||||||
|
lib.pcan_abi_gui_parser_stats.restype = ctypes.c_int
|
||||||
|
|
||||||
def id_pack(self, priority: int, route: int, device_type: int,
|
def id_pack(self, priority: int, route: int, device_type: int,
|
||||||
device_id: int, message_type: int, body: int) -> int:
|
device_id: int, message_type: int, body: int) -> int:
|
||||||
@@ -146,6 +180,26 @@ class NativeCore:
|
|||||||
def parser(self) -> "NativeParser":
|
def parser(self) -> "NativeParser":
|
||||||
return NativeParser(self)
|
return NativeParser(self)
|
||||||
|
|
||||||
|
def gui_crc32(self, data: bytes) -> int:
|
||||||
|
source = (ctypes.c_uint8 * len(data)).from_buffer_copy(data) if data else None
|
||||||
|
return int(self.lib.pcan_abi_gui_crc32(source, len(data)))
|
||||||
|
|
||||||
|
def gui_encode(self, message_type: int, sequence: int,
|
||||||
|
payload: bytes) -> bytes:
|
||||||
|
if len(payload) > 512:
|
||||||
|
raise ValueError("GUI payload cannot exceed 512 bytes")
|
||||||
|
source = ((ctypes.c_uint8 * len(payload)).from_buffer_copy(payload)
|
||||||
|
if payload else None)
|
||||||
|
output = (ctypes.c_uint8 * (8 + 512 + 4))()
|
||||||
|
size = int(self.lib.pcan_abi_gui_frame_encode(
|
||||||
|
message_type, sequence, source, len(payload), output, len(output)))
|
||||||
|
if size == 0:
|
||||||
|
raise ValueError("SETCore rejected the GUI frame")
|
||||||
|
return bytes(output[:size])
|
||||||
|
|
||||||
|
def gui_parser(self) -> "NativeGuiParser":
|
||||||
|
return NativeGuiParser(self)
|
||||||
|
|
||||||
|
|
||||||
class NativeParser:
|
class NativeParser:
|
||||||
def __init__(self, core: NativeCore) -> None:
|
def __init__(self, core: NativeCore) -> None:
|
||||||
@@ -182,6 +236,42 @@ class NativeParser:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class NativeGuiParser:
|
||||||
|
def __init__(self, core: NativeCore) -> None:
|
||||||
|
self._core = core
|
||||||
|
size = int(core.lib.pcan_abi_gui_parser_size())
|
||||||
|
self._storage = ctypes.create_string_buffer(size)
|
||||||
|
if not core.lib.pcan_abi_gui_parser_init(self._storage, size):
|
||||||
|
raise NativeCoreUnavailable("SETCore GUI parser initialization failed")
|
||||||
|
|
||||||
|
def feed(self, chunk: bytes) -> list[NativeGuiFrame]:
|
||||||
|
frames: list[NativeGuiFrame] = []
|
||||||
|
raw = _AbiGuiFrame()
|
||||||
|
for byte in chunk:
|
||||||
|
result = self._core.lib.pcan_abi_gui_parser_push(
|
||||||
|
self._storage, byte, ctypes.byref(raw))
|
||||||
|
if result < 0:
|
||||||
|
raise NativeCoreUnavailable("SETCore GUI parser rejected its context")
|
||||||
|
if result > 0:
|
||||||
|
frames.append(NativeGuiFrame(
|
||||||
|
int(raw.message_type), int(raw.sequence),
|
||||||
|
bytes(raw.payload[:raw.size])))
|
||||||
|
return frames
|
||||||
|
|
||||||
|
def stats(self) -> dict[str, int]:
|
||||||
|
values = [ctypes.c_uint32() for _ in range(5)]
|
||||||
|
if not self._core.lib.pcan_abi_gui_parser_stats(
|
||||||
|
self._storage, *(ctypes.byref(value) for value in values)):
|
||||||
|
raise NativeCoreUnavailable("SETCore GUI parser stats unavailable")
|
||||||
|
return {
|
||||||
|
"frames": values[0].value,
|
||||||
|
"crc_errors": values[1].value,
|
||||||
|
"version_errors": values[2].value,
|
||||||
|
"length_errors": values[3].value,
|
||||||
|
"stray_bytes": values[4].value,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
_default_core: NativeCore | None = None
|
_default_core: NativeCore | None = None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user