You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
5.2 KiB

#!/usr/bin/env python3
"""
Decoder Module - vzug-e-hinge
==============================
Decodes raw UART and I2C data into telemetry fields.
Current Implementation: Simple pass-through
TODO: Implement actual byte unpacking later
Author: Kynsight
Version: 1.0.0 (pass-through)
Date: 2025-11-09
"""
from typing import Dict, Any
def decode_uart_packet(packet_bytes: bytes) -> Dict[str, Any]:
"""
Decode UART packet bytes into telemetry fields.
Current Implementation: Pass-through (returns raw data)
TODO: Implement actual decoding based on packet format
Expected packet format: EF FE [14 bytes] EE (17 bytes total)
Future implementation should extract:
- motor_current (2 bytes)
- encoder_value (2 bytes)
- relative_encoder_value (2 bytes)
- v24_pec_diff (2 bytes)
- pwm (1 byte)
Args:
packet_bytes: Raw packet bytes (including start/end markers)
Returns:
Dictionary with decoded fields (currently just raw data)
Example:
packet_bytes = b'\\xEF\\xFE...[14 bytes]...\\xEE'
decoded = decode_uart_packet(packet_bytes)
# Currently returns: {'raw_hex': 'ef fe ... ee', 'raw_bytes': b'...'}
# Future: {'motor_current': 123, 'encoder_value': 456, ...}
"""
return {
'raw_hex': packet_bytes.hex(' '),
'raw_bytes': packet_bytes,
'packet_length': len(packet_bytes)
}
def decode_i2c_sample(i2c_bytes: bytes) -> Dict[str, Any]:
"""
Decode I2C sample bytes into angle telemetry.
Current Implementation: Pass-through (returns raw data)
TODO: Implement actual decoding based on I2C format
Expected I2C format: 2 bytes (14-bit angle value)
Future implementation should extract:
- i2c_raw14 (14-bit raw value)
- i2c_angle_deg (converted to degrees)
- i2c_zero_raw14 (zero position)
- i2c_delta_raw14 (delta from zero)
Args:
i2c_bytes: Raw I2C bytes (typically 2 bytes for angle)
Returns:
Dictionary with decoded fields (currently just raw data)
Example:
i2c_bytes = b'\\x3F\\xFF' # 14-bit angle
decoded = decode_i2c_sample(i2c_bytes)
# Currently returns: {'raw_hex': '3f ff', 'raw_bytes': b'...'}
# Future: {'i2c_raw14': 16383, 'i2c_angle_deg': 359.98, ...}
"""
return {
'raw_hex': i2c_bytes.hex(' '),
'raw_bytes': i2c_bytes,
'sample_length': len(i2c_bytes)
}
# =============================================================================
# Future Implementation Template
# =============================================================================
# def decode_uart_packet_full(packet_bytes: bytes) -> Dict[str, Any]:
# """
# Full UART packet decoder (to be implemented).
#
# Packet format: EF FE [14 bytes] EE
#
# Byte layout:
# [0-1]: Start marker (EF FE)
# [2-3]: motor_current (signed 16-bit, little-endian)
# [4-5]: encoder_value (unsigned 16-bit, little-endian)
# [6-7]: relative_encoder_value (signed 16-bit, little-endian)
# [8-9]: v24_pec_diff (signed 16-bit, little-endian)
# [10]: pwm (unsigned 8-bit)
# [11-15]: Reserved
# [16]: End marker (EE)
# """
# # Verify packet length
# if len(packet_bytes) != 17:
# raise ValueError(f"Invalid packet length: {len(packet_bytes)}, expected 17")
#
# # Verify markers
# if packet_bytes[0:2] != b'\xEF\xFE':
# raise ValueError("Invalid start marker")
# if packet_bytes[16:17] != b'\xEE':
# raise ValueError("Invalid end marker")
#
# # Extract data bytes (skip markers)
# data = packet_bytes[2:16]
#
# return {
# 'motor_current': int.from_bytes(data[0:2], 'little', signed=True),
# 'encoder_value': int.from_bytes(data[2:4], 'little', signed=False),
# 'relative_encoder_value': int.from_bytes(data[4:6], 'little', signed=True),
# 'v24_pec_diff': int.from_bytes(data[6:8], 'little', signed=True),
# 'pwm': data[8]
# }
# def decode_i2c_sample_full(i2c_bytes: bytes) -> Dict[str, Any]:
# """
# Full I2C sample decoder (to be implemented).
#
# I2C format: 2 bytes (14-bit angle value)
#
# Byte layout:
# [0]: High byte (bits 13-6)
# [1]: Low byte (bits 5-0 in upper 6 bits)
# """
# if len(i2c_bytes) != 2:
# raise ValueError(f"Invalid I2C sample length: {len(i2c_bytes)}, expected 2")
#
# # Extract 14-bit value
# raw14 = ((i2c_bytes[0] << 6) | (i2c_bytes[1] >> 2)) & 0x3FFF
#
# # Convert to degrees (14-bit = 0-360°)
# angle_deg = (raw14 / 16384.0) * 360.0
#
# return {
# 'i2c_raw14': raw14,
# 'i2c_angle_deg': angle_deg
# }
if __name__ == "__main__":
# Simple test
print("Decoder Module - Pass-Through Mode")
print("=" * 60)
# Test UART packet decoding
test_uart = b'\xEF\xFE' + b'\x01' * 14 + b'\xEE'
decoded_uart = decode_uart_packet(test_uart)
print(f"UART packet decoded: {decoded_uart}")
# Test I2C sample decoding
test_i2c = b'\x3F\xFF'
decoded_i2c = decode_i2c_sample(test_i2c)
print(f"I2C sample decoded: {decoded_i2c}")
print()
print("✓ Decoder ready (pass-through mode)")
print("TODO: Implement actual decoding later")