140 lines
5.2 KiB
C
140 lines
5.2 KiB
C
/*
|
|
* Исторический протокол основного контроллера ПМ67/TMS320F2812. Формирование команд и проверка
|
|
* ответов находятся в общем ядре; адреса памяти C28x считаются словами, тогда как длины
|
|
* передачи могут задаваться байтами.
|
|
*/
|
|
|
|
#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_fixed_request(uint8_t controller, uint8_t command,
|
|
const uint8_t *payload, size_t payload_size, uint8_t *output, size_t output_size)
|
|
{
|
|
uint16_t crc;
|
|
if (output == NULL || (payload == NULL && payload_size != 0U) ||
|
|
payload_size > SIZE_MAX - 4U || output_size < payload_size + 4U) return 0U;
|
|
output[0] = controller;
|
|
output[1] = command;
|
|
if (payload_size != 0U) memcpy(output + 2U, payload, payload_size);
|
|
crc = tms2812_crc16(output, payload_size + 2U);
|
|
output[payload_size + 2U] = (uint8_t)crc;
|
|
output[payload_size + 3U] = (uint8_t)(crc >> 8);
|
|
return payload_size + 4U;
|
|
}
|
|
|
|
size_t tms2812_build_memory_request(uint8_t controller, uint8_t command,
|
|
uint32_t word_address, uint16_t value, uint8_t *output, size_t output_size)
|
|
{
|
|
uint8_t payload[8];
|
|
if (command == 0U) { command = TMS2812_CMD_PEEK; word_address = TMS2812_PING_ADDRESS; }
|
|
if (command != TMS2812_CMD_PEEK && command != TMS2812_CMD_POKE) return 0U;
|
|
put_le32(payload, word_address);
|
|
put_le32(payload + 4U, value);
|
|
return tms2812_build_fixed_request(controller, command, payload,
|
|
command == TMS2812_CMD_PEEK ? 4U : 8U, output, output_size);
|
|
}
|
|
|
|
size_t tms2812_build_test_request(uint8_t controller, uint16_t duration,
|
|
uint16_t pause, const uint8_t *digits, size_t digit_count,
|
|
uint8_t *output, size_t output_size)
|
|
{
|
|
uint8_t payload[16];
|
|
if (digits == NULL || digit_count != 12U) return 0U;
|
|
payload[0] = (uint8_t)duration; payload[1] = (uint8_t)(duration >> 8);
|
|
payload[2] = (uint8_t)pause; payload[3] = (uint8_t)(pause >> 8);
|
|
memcpy(payload + 4U, digits, 12U);
|
|
return tms2812_build_fixed_request(controller, TMS2812_CMD_TEST_ALL,
|
|
payload, sizeof payload, output, output_size);
|
|
}
|
|
|
|
int tms2812_validate_response(const uint8_t *data, size_t size,
|
|
uint8_t controller, uint8_t command, size_t full_size, int allow_short_tail)
|
|
{
|
|
size_t offset;
|
|
uint16_t crc;
|
|
if (data == NULL) return TMS2812_ERROR_ARGUMENT;
|
|
if (full_size < 6U) return TMS2812_ERROR_ARGUMENT;
|
|
if (size > full_size || size < full_size - (allow_short_tail ? 2U : 0U))
|
|
return TMS2812_ERROR_LENGTH;
|
|
if (data[0] != controller || data[1] != command) return TMS2812_ERROR_HEADER;
|
|
offset = full_size - 4U;
|
|
crc = (uint16_t)(data[offset] | ((uint16_t)data[offset + 1U] << 8));
|
|
return crc == tms2812_crc16(data, offset) ? TMS2812_OK : TMS2812_ERROR_CRC;
|
|
}
|
|
|
|
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;
|
|
}
|