Share PM67 upload protocol through C core
This commit is contained in:
@@ -18,7 +18,9 @@ set(SETPROTOCOL_V2_SOURCES
|
||||
# Совместимые ProtoCAN/SETGUI v1 форматы переходного периода.
|
||||
set(SETPROTOCOL_LEGACY_SOURCES
|
||||
src/balsam_can.c
|
||||
src/set_crc.c
|
||||
src/periph28335.c
|
||||
src/tms2812.c
|
||||
src/gui_catalog.c
|
||||
src/gui_frame.c
|
||||
src/pcan_abi.c
|
||||
@@ -102,6 +104,9 @@ if(SETP_BUILD_TESTS)
|
||||
add_executable(test_periph28335 tests/test_periph28335.c)
|
||||
target_link_libraries(test_periph28335 PRIVATE setprotocol_static)
|
||||
add_test(NAME shared_periph28335 COMMAND test_periph28335)
|
||||
add_executable(test_tms2812 tests/test_tms2812.c)
|
||||
target_link_libraries(test_tms2812 PRIVATE setprotocol_static)
|
||||
add_test(NAME shared_tms2812 COMMAND test_tms2812)
|
||||
add_executable(test_trends tests/test_trends.c)
|
||||
target_link_libraries(test_trends PRIVATE setprotocol_static)
|
||||
add_test(NAME shared_trends COMMAND test_trends)
|
||||
|
||||
@@ -101,6 +101,21 @@ PCAN_ABI_API const char *pcan_abi_periph28335_project_name(
|
||||
PCAN_ABI_API const char *pcan_abi_periph28335_command_name(
|
||||
size_t project_index, size_t command_index);
|
||||
|
||||
/* PM67/TMS320F2812 legacy memory upload. */
|
||||
PCAN_ABI_API uint16_t pcan_abi_tms2812_crc16(
|
||||
const uint8_t *data, size_t size);
|
||||
PCAN_ABI_API size_t pcan_abi_tms2812_build_upload(
|
||||
uint8_t controller, uint32_t word_address, uint32_t byte_count,
|
||||
uint8_t *output, size_t output_size);
|
||||
PCAN_ABI_API size_t pcan_abi_tms2812_expected_upload_size(
|
||||
uint32_t byte_count);
|
||||
PCAN_ABI_API int pcan_abi_tms2812_validate_upload(
|
||||
const uint8_t *data, size_t size, uint8_t controller,
|
||||
uint32_t byte_count);
|
||||
PCAN_ABI_API int pcan_abi_tms2812_decode_upload(
|
||||
const uint8_t *data, size_t size, uint8_t controller,
|
||||
uint32_t byte_count, uint8_t *output, size_t output_size);
|
||||
|
||||
PCAN_ABI_API size_t pcan_abi_frame_encode(uint8_t sequence, uint8_t flags,
|
||||
uint32_t can_id,
|
||||
const uint8_t *data, uint8_t dlc,
|
||||
|
||||
19
c/set-protocol/include/set_crc.h
Normal file
19
c/set-protocol/include/set_crc.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/** @file set_crc.h @brief Shared checksums used by legacy SET controllers. */
|
||||
#ifndef SET_CRC_H
|
||||
#define SET_CRC_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** CRC-16/Modbus: reflected polynomial 0xA001, initial value 0xFFFF. */
|
||||
uint16_t set_crc16_modbus(const uint8_t *data, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SET_CRC_H */
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "balsam_can.h"
|
||||
#include "periph28335.h"
|
||||
#include "tms2812.h"
|
||||
|
||||
/* Основной SET protocol v2. */
|
||||
#include "set_protocol.h"
|
||||
|
||||
49
c/set-protocol/include/tms2812.h
Normal file
49
c/set-protocol/include/tms2812.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @file tms2812.h
|
||||
* @brief Shared PM67/TMS320F2812 legacy upload protocol.
|
||||
*/
|
||||
#ifndef TMS2812_H
|
||||
#define TMS2812_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TMS2812_CMD_UPLOAD 52U
|
||||
#define TMS2812_UPLOAD_REQUEST_SIZE 12U
|
||||
#define TMS2812_UPLOAD_RESPONSE_OVERHEAD 8U
|
||||
|
||||
typedef enum {
|
||||
TMS2812_OK = 0,
|
||||
TMS2812_ERROR_ARGUMENT = -1,
|
||||
TMS2812_ERROR_RANGE = -2,
|
||||
TMS2812_ERROR_LENGTH = -3,
|
||||
TMS2812_ERROR_CRC = -4,
|
||||
TMS2812_ERROR_HEADER = -5,
|
||||
TMS2812_ERROR_CAPACITY = -6
|
||||
} tms2812_status_t;
|
||||
|
||||
uint16_t tms2812_crc16(const uint8_t *data, size_t size);
|
||||
|
||||
size_t tms2812_build_upload_request(
|
||||
uint8_t controller, uint32_t word_address, uint32_t byte_count,
|
||||
uint8_t *output, size_t output_size);
|
||||
|
||||
size_t tms2812_expected_upload_response_size(uint32_t byte_count);
|
||||
|
||||
int tms2812_validate_upload_response(
|
||||
const uint8_t *data, size_t size, uint8_t controller,
|
||||
uint32_t byte_count);
|
||||
|
||||
int tms2812_decode_upload_response(
|
||||
const uint8_t *data, size_t size, uint8_t controller,
|
||||
uint32_t byte_count, uint8_t *output, size_t output_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* TMS2812_H */
|
||||
@@ -13,7 +13,9 @@ LOCAL_SRC_FILES := \
|
||||
../../src/set_trends.c \
|
||||
../../src/set_spectrum.c \
|
||||
../../src/balsam_can.c \
|
||||
../../src/set_crc.c \
|
||||
../../src/periph28335.c \
|
||||
../../src/tms2812.c \
|
||||
../../src/gui_catalog.c \
|
||||
../../src/gui_frame.c \
|
||||
../../src/pcan_abi.c \
|
||||
|
||||
@@ -46,6 +46,11 @@ object NativeSetProtocol {
|
||||
external fun nativePeriph28335ProjectCount(): Int
|
||||
external fun nativePeriph28335ProjectName(projectIndex: Int): String?
|
||||
external fun nativePeriph28335CommandName(projectIndex: Int, commandIndex: Int): String?
|
||||
external fun nativeTms2812Crc16(input: ByteArray): Int
|
||||
external fun nativeTms2812BuildUpload(controller: Int, wordAddress: Long, byteCount: Long): ByteArray?
|
||||
external fun nativeTms2812ExpectedUploadSize(byteCount: Long): Int
|
||||
external fun nativeTms2812ValidateUpload(input: ByteArray, controller: Int, byteCount: Int): Boolean
|
||||
external fun nativeTms2812DecodeUpload(input: ByteArray, controller: Int, byteCount: Int): ByteArray?
|
||||
external fun nativeEncodeFrame(
|
||||
sequence: Int,
|
||||
flags: Int,
|
||||
|
||||
@@ -8,6 +8,97 @@
|
||||
#include "set_spectrum.h"
|
||||
#include "balsam_can.h"
|
||||
#include "periph28335.h"
|
||||
#include "tms2812.h"
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeTms2812Crc16(
|
||||
JNIEnv *env, jobject self, jbyteArray input)
|
||||
{
|
||||
(void)self;
|
||||
if (input == NULL) return 0;
|
||||
jsize size = (*env)->GetArrayLength(env, input);
|
||||
jbyte *data = (*env)->GetByteArrayElements(env, input, NULL);
|
||||
if ((data == NULL) && (size != 0)) return 0;
|
||||
uint16_t crc = tms2812_crc16((const uint8_t *)data, (size_t)size);
|
||||
if (data != NULL) (*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT);
|
||||
return (jint)crc;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeTms2812BuildUpload(
|
||||
JNIEnv *env, jobject self, jint controller, jlong word_address,
|
||||
jlong byte_count)
|
||||
{
|
||||
(void)self;
|
||||
uint8_t output[TMS2812_UPLOAD_REQUEST_SIZE];
|
||||
if (controller < 0 || controller > 255 || word_address < 0 ||
|
||||
(uint64_t)word_address > UINT32_MAX || byte_count < 1 ||
|
||||
(uint64_t)byte_count > UINT32_MAX) return NULL;
|
||||
size_t written = tms2812_build_upload_request(
|
||||
(uint8_t)controller, (uint32_t)word_address, (uint32_t)byte_count,
|
||||
output, sizeof output);
|
||||
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 jint JNICALL
|
||||
Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeTms2812ExpectedUploadSize(
|
||||
JNIEnv *env, jobject self, jlong byte_count)
|
||||
{
|
||||
(void)env; (void)self;
|
||||
if (byte_count < 1 || (uint64_t)byte_count > UINT32_MAX) return 0;
|
||||
size_t size = tms2812_expected_upload_response_size((uint32_t)byte_count);
|
||||
return size <= INT32_MAX ? (jint)size : 0;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeTms2812ValidateUpload(
|
||||
JNIEnv *env, jobject self, jbyteArray input, jint controller,
|
||||
jint byte_count)
|
||||
{
|
||||
(void)self;
|
||||
if (input == NULL || controller < 0 || controller > 255 || byte_count < 1)
|
||||
return JNI_FALSE;
|
||||
jsize size = (*env)->GetArrayLength(env, input);
|
||||
jbyte *data = (*env)->GetByteArrayElements(env, input, NULL);
|
||||
if (data == NULL) return JNI_FALSE;
|
||||
int status = tms2812_validate_upload_response(
|
||||
(const uint8_t *)data, (size_t)size, (uint8_t)controller,
|
||||
(uint32_t)byte_count);
|
||||
(*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT);
|
||||
return status == TMS2812_OK ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeTms2812DecodeUpload(
|
||||
JNIEnv *env, jobject self, jbyteArray input, jint controller,
|
||||
jint byte_count)
|
||||
{
|
||||
(void)self;
|
||||
if (input == NULL || controller < 0 || controller > 255 || byte_count < 1)
|
||||
return NULL;
|
||||
jsize size = (*env)->GetArrayLength(env, input);
|
||||
jbyte *data = (*env)->GetByteArrayElements(env, input, NULL);
|
||||
if (data == NULL) return NULL;
|
||||
uint8_t *output = (uint8_t *)malloc((size_t)byte_count);
|
||||
if (output == NULL) {
|
||||
(*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT);
|
||||
return NULL;
|
||||
}
|
||||
int status = tms2812_decode_upload_response(
|
||||
(const uint8_t *)data, (size_t)size, (uint8_t)controller,
|
||||
(uint32_t)byte_count, output, (size_t)byte_count);
|
||||
(*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT);
|
||||
if (status != TMS2812_OK) { free(output); return NULL; }
|
||||
jbyteArray result = (*env)->NewByteArray(env, byte_count);
|
||||
if (result != NULL) (*env)->SetByteArrayRegion(
|
||||
env, result, 0, byte_count, (const jbyte *)output);
|
||||
free(output);
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_ru_setcorp_setprotocol_NativeSetProtocol_nativePeriph28335Crc16(
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "pcan_crc.h"
|
||||
#include "balsam_can.h"
|
||||
#include "periph28335.h"
|
||||
#include "tms2812.h"
|
||||
#include "pcan_frame.h"
|
||||
#include "pcan_id.h"
|
||||
#include "gui_frame.h"
|
||||
@@ -162,6 +163,40 @@ const char *pcan_abi_periph28335_command_name(
|
||||
return periph28335_command_name(project_index, command_index);
|
||||
}
|
||||
|
||||
uint16_t pcan_abi_tms2812_crc16(const uint8_t *data, size_t size)
|
||||
{
|
||||
return tms2812_crc16(data, size);
|
||||
}
|
||||
|
||||
size_t pcan_abi_tms2812_build_upload(
|
||||
uint8_t controller, uint32_t word_address, uint32_t byte_count,
|
||||
uint8_t *output, size_t output_size)
|
||||
{
|
||||
return tms2812_build_upload_request(
|
||||
controller, word_address, byte_count, output, output_size);
|
||||
}
|
||||
|
||||
size_t pcan_abi_tms2812_expected_upload_size(uint32_t byte_count)
|
||||
{
|
||||
return tms2812_expected_upload_response_size(byte_count);
|
||||
}
|
||||
|
||||
int pcan_abi_tms2812_validate_upload(
|
||||
const uint8_t *data, size_t size, uint8_t controller,
|
||||
uint32_t byte_count)
|
||||
{
|
||||
return tms2812_validate_upload_response(
|
||||
data, size, controller, byte_count);
|
||||
}
|
||||
|
||||
int pcan_abi_tms2812_decode_upload(
|
||||
const uint8_t *data, size_t size, uint8_t controller,
|
||||
uint32_t byte_count, uint8_t *output, size_t output_size)
|
||||
{
|
||||
return tms2812_decode_upload_response(
|
||||
data, size, controller, byte_count, output, output_size);
|
||||
}
|
||||
|
||||
size_t pcan_abi_frame_encode(uint8_t sequence, uint8_t flags,
|
||||
uint32_t can_id, const uint8_t *data, uint8_t dlc,
|
||||
uint8_t *output, size_t output_size)
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "set_crc.h"
|
||||
|
||||
typedef struct {
|
||||
const char *project;
|
||||
const char *commands[PERIPH28335_COMMAND_COUNT];
|
||||
@@ -32,19 +34,7 @@ static uint16_t get_be16(const uint8_t *input)
|
||||
|
||||
uint16_t periph28335_crc16_modbus(const uint8_t *data, size_t size)
|
||||
{
|
||||
uint16_t crc = 0xFFFFU;
|
||||
size_t index;
|
||||
uint8_t bit;
|
||||
if ((data == NULL) && (size != 0U)) return 0U;
|
||||
for (index = 0U; index < size; ++index) {
|
||||
crc ^= data[index];
|
||||
for (bit = 0U; bit < 8U; ++bit) {
|
||||
crc = (crc & 1U) != 0U
|
||||
? (uint16_t)((crc >> 1) ^ 0xA001U)
|
||||
: (uint16_t)(crc >> 1);
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
return set_crc16_modbus(data, size);
|
||||
}
|
||||
|
||||
size_t periph28335_append_crc(const uint8_t *payload, size_t payload_size,
|
||||
|
||||
18
c/set-protocol/src/set_crc.c
Normal file
18
c/set-protocol/src/set_crc.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "set_crc.h"
|
||||
|
||||
uint16_t set_crc16_modbus(const uint8_t *data, size_t size)
|
||||
{
|
||||
uint16_t crc = 0xFFFFU;
|
||||
size_t index;
|
||||
uint8_t bit;
|
||||
if ((data == NULL) && (size != 0U)) return 0U;
|
||||
for (index = 0U; index < size; ++index) {
|
||||
crc ^= data[index];
|
||||
for (bit = 0U; bit < 8U; ++bit) {
|
||||
crc = (crc & 1U) != 0U
|
||||
? (uint16_t)((crc >> 1) ^ 0xA001U)
|
||||
: (uint16_t)(crc >> 1);
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
78
c/set-protocol/src/tms2812.c
Normal file
78
c/set-protocol/src/tms2812.c
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "tms2812.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "set_crc.h"
|
||||
|
||||
static void put_le32(uint8_t *output, uint32_t value)
|
||||
{
|
||||
output[0] = (uint8_t)value;
|
||||
output[1] = (uint8_t)(value >> 8);
|
||||
output[2] = (uint8_t)(value >> 16);
|
||||
output[3] = (uint8_t)(value >> 24);
|
||||
}
|
||||
|
||||
uint16_t tms2812_crc16(const uint8_t *data, size_t size)
|
||||
{
|
||||
return set_crc16_modbus(data, size);
|
||||
}
|
||||
|
||||
size_t tms2812_build_upload_request(
|
||||
uint8_t controller, uint32_t word_address, uint32_t byte_count,
|
||||
uint8_t *output, size_t output_size)
|
||||
{
|
||||
uint16_t crc;
|
||||
if ((output == NULL) || (output_size < TMS2812_UPLOAD_REQUEST_SIZE) ||
|
||||
(byte_count == 0U)) return 0U;
|
||||
output[0] = controller;
|
||||
output[1] = TMS2812_CMD_UPLOAD;
|
||||
put_le32(&output[2], word_address);
|
||||
put_le32(&output[6], byte_count);
|
||||
crc = tms2812_crc16(output, 10U);
|
||||
output[10] = (uint8_t)crc;
|
||||
output[11] = (uint8_t)(crc >> 8);
|
||||
return TMS2812_UPLOAD_REQUEST_SIZE;
|
||||
}
|
||||
|
||||
size_t tms2812_expected_upload_response_size(uint32_t byte_count)
|
||||
{
|
||||
if (byte_count == 0U ||
|
||||
(uint64_t)byte_count + TMS2812_UPLOAD_RESPONSE_OVERHEAD > SIZE_MAX) {
|
||||
return 0U;
|
||||
}
|
||||
return (size_t)byte_count + TMS2812_UPLOAD_RESPONSE_OVERHEAD;
|
||||
}
|
||||
|
||||
int tms2812_validate_upload_response(
|
||||
const uint8_t *data, size_t size, uint8_t controller,
|
||||
uint32_t byte_count)
|
||||
{
|
||||
size_t expected = tms2812_expected_upload_response_size(byte_count);
|
||||
size_t crc_offset;
|
||||
uint16_t expected_crc;
|
||||
uint16_t actual_crc;
|
||||
if (data == NULL) return TMS2812_ERROR_ARGUMENT;
|
||||
if (expected == 0U) return TMS2812_ERROR_RANGE;
|
||||
if (size != expected) return TMS2812_ERROR_LENGTH;
|
||||
if ((data[0] != controller) || (data[1] != TMS2812_CMD_UPLOAD))
|
||||
return TMS2812_ERROR_HEADER;
|
||||
crc_offset = (size_t)byte_count + 2U;
|
||||
expected_crc = tms2812_crc16(data, crc_offset);
|
||||
actual_crc = (uint16_t)(data[crc_offset] |
|
||||
((uint16_t)data[crc_offset + 1U] << 8));
|
||||
return actual_crc == expected_crc ? TMS2812_OK : TMS2812_ERROR_CRC;
|
||||
}
|
||||
|
||||
int tms2812_decode_upload_response(
|
||||
const uint8_t *data, size_t size, uint8_t controller,
|
||||
uint32_t byte_count, uint8_t *output, size_t output_size)
|
||||
{
|
||||
int status = tms2812_validate_upload_response(
|
||||
data, size, controller, byte_count);
|
||||
if (status != TMS2812_OK) return status;
|
||||
if ((output == NULL) || (output_size < byte_count))
|
||||
return TMS2812_ERROR_CAPACITY;
|
||||
memcpy(output, &data[2], byte_count);
|
||||
return TMS2812_OK;
|
||||
}
|
||||
35
c/set-protocol/tests/test_tms2812.c
Normal file
35
c/set-protocol/tests/test_tms2812.c
Normal file
@@ -0,0 +1,35 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tms2812.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
uint8_t request[TMS2812_UPLOAD_REQUEST_SIZE];
|
||||
static const uint8_t prefix[] = {
|
||||
0x05U, 0x34U, 0x78U, 0x56U, 0x34U, 0x12U,
|
||||
0x00U, 0x10U, 0x00U, 0x00U
|
||||
};
|
||||
uint8_t reply[4U + TMS2812_UPLOAD_RESPONSE_OVERHEAD];
|
||||
uint8_t decoded[4];
|
||||
uint16_t crc;
|
||||
|
||||
if (tms2812_build_upload_request(5U, 0x12345678UL, 0x1000U,
|
||||
request, sizeof request) != sizeof request ||
|
||||
memcmp(request, prefix, sizeof prefix) != 0) return 1;
|
||||
reply[0] = 5U;
|
||||
reply[1] = TMS2812_CMD_UPLOAD;
|
||||
reply[2] = 0x10U; reply[3] = 0x20U; reply[4] = 0x30U; reply[5] = 0x40U;
|
||||
crc = tms2812_crc16(reply, 6U);
|
||||
reply[6] = (uint8_t)crc;
|
||||
reply[7] = (uint8_t)(crc >> 8);
|
||||
memset(&reply[8], 0, 4U);
|
||||
if (tms2812_decode_upload_response(reply, sizeof reply, 5U, 4U,
|
||||
decoded, sizeof decoded) != TMS2812_OK ||
|
||||
memcmp(decoded, &reply[2], sizeof decoded) != 0) return 2;
|
||||
reply[6] ^= 1U;
|
||||
if (tms2812_validate_upload_response(reply, sizeof reply, 5U, 4U)
|
||||
!= TMS2812_ERROR_CRC) return 3;
|
||||
puts("PM67/TMS320F2812 upload protocol tests passed");
|
||||
return 0;
|
||||
}
|
||||
@@ -21,7 +21,7 @@ JNI_INCLUDES: list[Path] = []
|
||||
SOURCES = [
|
||||
ROOT / "src" / name for name in (
|
||||
"set_protocol.c", "set_can.c", "set_firmware.c", "set_telemetry.c", "set_plot.c", "set_trends.c", "set_spectrum.c",
|
||||
"balsam_can.c", "periph28335.c", "gui_catalog.c", "gui_frame.c", "pcan_abi.c", "pcan_crc.c",
|
||||
"balsam_can.c", "set_crc.c", "periph28335.c", "tms2812.c", "gui_catalog.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",
|
||||
)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
| CAN Бальзам | `c/set-protocol/src/balsam_can.c` |
|
||||
| График, тренды и спектр | `c/set-protocol/src/set_plot.c`, `set_trends.c`, `set_spectrum.c` |
|
||||
| ПМ35 / TMS320F28335: MODBUS-подобные запросы, CRC16/Modbus, ответы и каталог команд | `c/set-protocol/src/periph28335.c` |
|
||||
| ПМ67 / TMS320F2812: CMD_UPLOAD, CRC16/Modbus и проверка ответа | `c/set-protocol/src/tms2812.c` |
|
||||
|
||||
Python вызывает это ядро через `python/protocan/native.py`, Android — через
|
||||
`ports/android/setprotocol_jni.c`. Файлы на Python и Kotlin являются портами и
|
||||
@@ -24,7 +25,7 @@ Python вызывает это ядро через `python/protocan/native.py`,
|
||||
| Приоритет | Android | SETGUI | Что вынести в C |
|
||||
|---|---|---|---|
|
||||
| 0 | `ports/android/.../CanBridgeProtocol.kt`, `GuiProtocol.kt` | Python transport wrappers | удалить оставшиеся алгоритмические fallback, так как codec/parser уже есть в C |
|
||||
| 1 | `core/Tms2812Protocol.kt` | `core/tms_flash.py`, `core/tms_terminal.py` | весь RS-протокол ПМ67/2812, CRC, команды и validators |
|
||||
| 1 | остальные команды `core/Tms2812Protocol.kt` | `core/tms_terminal.py` | оставшиеся команды и parser непрерывной телеметрии ПМ67/2812; CMD_UPLOAD уже перенесён |
|
||||
| 2 | `core/Ds18b20Protocol.kt` | `core/ds18b20.py` | кодеки списков/данных/EEPROM, CRC8 и значения датчиков |
|
||||
| 3 | `core/CanFirmwareProtocol.kt` | `core/can_firmware.py` | автомат CAN boot, статусы, окна блоков |
|
||||
| 4 | `core/SlCanProtocol.kt` | `adapters/slcan_adapter.py` и CAN transport | ASCII codec/parser SLCAN; доступ к COM остаётся в портах |
|
||||
|
||||
@@ -177,6 +177,24 @@ class NativeProtocol:
|
||||
ctypes.c_size_t, ctypes.c_size_t,
|
||||
]
|
||||
lib.pcan_abi_periph28335_command_name.restype = ctypes.c_char_p
|
||||
lib.pcan_abi_tms2812_crc16.argtypes = [ctypes.c_void_p, ctypes.c_size_t]
|
||||
lib.pcan_abi_tms2812_crc16.restype = ctypes.c_uint16
|
||||
lib.pcan_abi_tms2812_build_upload.argtypes = [
|
||||
ctypes.c_uint8, ctypes.c_uint32, ctypes.c_uint32,
|
||||
ctypes.c_void_p, ctypes.c_size_t,
|
||||
]
|
||||
lib.pcan_abi_tms2812_build_upload.restype = ctypes.c_size_t
|
||||
lib.pcan_abi_tms2812_expected_upload_size.argtypes = [ctypes.c_uint32]
|
||||
lib.pcan_abi_tms2812_expected_upload_size.restype = ctypes.c_size_t
|
||||
lib.pcan_abi_tms2812_validate_upload.argtypes = [
|
||||
ctypes.c_void_p, ctypes.c_size_t, ctypes.c_uint8, ctypes.c_uint32,
|
||||
]
|
||||
lib.pcan_abi_tms2812_validate_upload.restype = ctypes.c_int
|
||||
lib.pcan_abi_tms2812_decode_upload.argtypes = [
|
||||
ctypes.c_void_p, ctypes.c_size_t, ctypes.c_uint8, ctypes.c_uint32,
|
||||
ctypes.c_void_p, ctypes.c_size_t,
|
||||
]
|
||||
lib.pcan_abi_tms2812_decode_upload.restype = ctypes.c_int
|
||||
lib.pcan_abi_frame_encode.argtypes = [
|
||||
ctypes.c_uint8, ctypes.c_uint8, ctypes.c_uint32,
|
||||
ctypes.c_void_p, ctypes.c_uint8, ctypes.c_void_p, ctypes.c_size_t,
|
||||
@@ -335,6 +353,35 @@ class NativeProtocol:
|
||||
result[raw_name.decode("utf-8")] = tuple(commands)
|
||||
return result
|
||||
|
||||
def tms2812_crc16(self, data: bytes) -> int:
|
||||
return int(self.lib.pcan_abi_tms2812_crc16(
|
||||
self._bytes_buffer(data), len(data)))
|
||||
|
||||
def tms2812_build_upload(self, controller: int, word_address: int,
|
||||
byte_count: int) -> bytes:
|
||||
output = (ctypes.c_uint8 * 12)()
|
||||
size = int(self.lib.pcan_abi_tms2812_build_upload(
|
||||
controller, word_address, byte_count, output, len(output)))
|
||||
if size == 0:
|
||||
raise ValueError("SETProtocol rejected PM67 upload request")
|
||||
return bytes(output[:size])
|
||||
|
||||
def tms2812_expected_upload_size(self, byte_count: int) -> int:
|
||||
return int(self.lib.pcan_abi_tms2812_expected_upload_size(byte_count))
|
||||
|
||||
def tms2812_validate_upload(self, data: bytes, controller: int,
|
||||
byte_count: int) -> int:
|
||||
return int(self.lib.pcan_abi_tms2812_validate_upload(
|
||||
self._bytes_buffer(data), len(data), controller, byte_count))
|
||||
|
||||
def tms2812_decode_upload(self, data: bytes, controller: int,
|
||||
byte_count: int) -> tuple[int, bytes]:
|
||||
output = (ctypes.c_uint8 * byte_count)()
|
||||
status = int(self.lib.pcan_abi_tms2812_decode_upload(
|
||||
self._bytes_buffer(data), len(data), controller, byte_count,
|
||||
output, len(output)))
|
||||
return status, bytes(output) if status == 0 else b""
|
||||
|
||||
def encode(self, sequence: int, flags: int, can_id: int, data: bytes) -> bytes:
|
||||
if len(data) > 8:
|
||||
raise ValueError("DLC cannot exceed 8 bytes")
|
||||
|
||||
60
python/protocan/tms2812.py
Normal file
60
python/protocan/tms2812.py
Normal file
@@ -0,0 +1,60 @@
|
||||
"""Thin Python adapter for the shared C99 PM67/TMS320F2812 protocol."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .native import get_native_protocol
|
||||
|
||||
|
||||
CMD_UPLOAD = 52
|
||||
UPLOAD_RESPONSE_OVERHEAD = 8
|
||||
|
||||
|
||||
def _core():
|
||||
return get_native_protocol()
|
||||
|
||||
|
||||
def crc16_modbus(data: bytes, initial: int = 0xFFFF) -> int:
|
||||
if initial != 0xFFFF:
|
||||
raise ValueError("Произвольное начальное значение CRC не входит в протокол ПМ67")
|
||||
return _core().tms2812_crc16(bytes(data))
|
||||
|
||||
|
||||
def build_upload_request(controller: int, word_address: int,
|
||||
byte_count: int) -> bytes:
|
||||
_range("адрес контроллера", controller, 0xFF)
|
||||
_range("адрес слова", word_address, 0xFFFFFFFF)
|
||||
if not 1 <= byte_count <= 0xFFFFFFFF:
|
||||
raise ValueError("размер блока вне диапазона 1..0xFFFFFFFF")
|
||||
return _core().tms2812_build_upload(controller, word_address, byte_count)
|
||||
|
||||
|
||||
def expected_upload_response_size(byte_count: int) -> int:
|
||||
if not 1 <= byte_count <= 0xFFFFFFFF:
|
||||
raise ValueError("размер блока вне диапазона 1..0xFFFFFFFF")
|
||||
return _core().tms2812_expected_upload_size(byte_count)
|
||||
|
||||
|
||||
def decode_upload_reply(raw: bytes, controller: int, byte_count: int) -> bytes:
|
||||
expected = expected_upload_response_size(byte_count)
|
||||
if len(raw) != expected:
|
||||
raise ValueError(
|
||||
f"ответ CMD_UPLOAD: ожидалось {expected} байт, получено {len(raw)}"
|
||||
)
|
||||
status, data = _core().tms2812_decode_upload(
|
||||
bytes(raw), controller, byte_count)
|
||||
errors = {
|
||||
-1: "неверные аргументы CMD_UPLOAD",
|
||||
-2: "размер CMD_UPLOAD вне диапазона",
|
||||
-3: "неверная длина ответа CMD_UPLOAD",
|
||||
-4: "CRC ответа CMD_UPLOAD не совпадает",
|
||||
-5: "ответ CMD_UPLOAD имеет неверный адрес или номер команды",
|
||||
-6: "недостаточный буфер CMD_UPLOAD",
|
||||
}
|
||||
if status != 0:
|
||||
raise ValueError(errors.get(status, f"ошибка ответа CMD_UPLOAD: {status}"))
|
||||
return data
|
||||
|
||||
|
||||
def _range(name: str, value: int, maximum: int) -> None:
|
||||
if not 0 <= value <= maximum:
|
||||
raise ValueError(f"{name} вне диапазона 0..{maximum}")
|
||||
Reference in New Issue
Block a user