Compare commits

..

2 Commits

Author SHA1 Message Date
Erki
0f8b5bb0b1 SRAM parser and decoder 2022-08-24 23:42:39 +03:00
Erki
c9e069b494 trx testing, 1 2022-08-24 23:42:24 +03:00
10 changed files with 249 additions and 6 deletions

View File

@ -10,6 +10,7 @@
#include "app_settings.hpp" #include "app_settings.hpp"
#include "radio_interrupts.hpp" #include "radio_interrupts.hpp"
#include "radio_protocol_frame.hpp"
namespace radio namespace radio
{ {
@ -34,7 +35,10 @@ public:
private: private:
radio::HwInstance* m_radio; radio::HwInstance* m_radio;
Utility::FunctionOwned<TransparentClient, void (radio::HwInstance*)> m_isr_cb_pointer; Utility::FunctionOwned<TransparentClient, void (radio::HwInstance*)> m_isr_cb_pointer;
RadioSettings m_active_settings;
std::optional<radio::Interrupts> m_pending_irqs = std::nullopt; std::optional<radio::Interrupts> m_pending_irqs = std::nullopt;
std::optional<radio::protocol::FrameStructure> m_tx_buffer_frame = std::nullopt;
std::array<std::uint8_t, 128> m_tx_buffer_raw;
enum class AppState enum class AppState
{ {
@ -53,6 +57,8 @@ private:
void m_processState(); void m_processState();
void m_initiateTx(); void m_initiateTx();
bool m_txBufferIsReady(); bool m_txBufferIsReady();
void m_prepareTransmission(const std::uint16_t dst_mac, const std::array<std::uint8_t, 22>& buffer);
}; };
} }

View File

@ -15,7 +15,7 @@
namespace Hal = Peripherals::Hal::Samd; namespace Hal = Peripherals::Hal::Samd;
using Logger = Utility::AsyncLogger<Hal::SerialInterfaceAsync<usart_async_descriptor>, Hal::StaticHal, 5, 255>; using Logger = Utility::AsyncLogger<Hal::SerialInterfaceAsync<usart_async_descriptor>, Hal::StaticHal, 10, 255>;
namespace namespace
{ {

View File

@ -6,8 +6,11 @@
#include "app_transparent_client.hpp" #include "app_transparent_client.hpp"
#include "skullc_samd21_hal.hpp" #include "skullc_samd21_hal.hpp"
#include "utility_logging.hpp" #include "radio_protocol.hpp"
#include <cstdio>
#include <utility_logging.hpp>
#include <utility_atomicscopeguard.hpp> #include <utility_atomicscopeguard.hpp>
namespace App namespace App
@ -30,6 +33,8 @@ void TransparentClient::apply_settings(const RadioSettings& settings)
m_radio->set_pan_id(settings.pan_id); m_radio->set_pan_id(settings.pan_id);
m_radio->set_tx_power(settings.tx_power_dbm); m_radio->set_tx_power(settings.tx_power_dbm);
m_radio->set_max_retries(settings.retries); m_radio->set_max_retries(settings.retries);
m_active_settings = settings;
} }
void TransparentClient::process() void TransparentClient::process()
@ -48,6 +53,20 @@ void TransparentClient::process()
if (new_state_request) if (new_state_request)
m_transitionToState(*new_state_request); m_transitionToState(*new_state_request);
static int count = 0;
static bool sent = false;
if (count++ == 5000 && !sent)
{
sent = true;
if (m_active_settings.short_address == 11)
{
SKULLC_LOG_DEBUG("Attempting send.");
const std::array<std::uint8_t, 22> buff = {"Lol this is a message"};
m_prepareTransmission(18, buff);
}
}
m_processState(); m_processState();
} }
@ -134,12 +153,47 @@ void TransparentClient::m_processState()
void TransparentClient::m_initiateTx() void TransparentClient::m_initiateTx()
{ {
return; m_radio->set_current_state(radio::HwInstance::States::PLL_ON);
const std::size_t buffer_size = radio::protocol::composeFrameBuffer(m_tx_buffer_raw.data(), *m_tx_buffer_frame);
SKULLC_LOG_DEBUG("APP: Initiating TX of %u bytes.", buffer_size);
char raw_data[255] = { 0 };
for (std::size_t i = 0, data_offset = 0; i < buffer_size; i++)
{
data_offset += std::sprintf(&raw_data[data_offset], "%02X", m_tx_buffer_raw[i]);
}
Utility::skullc_logger->log("\n\rDATA\n\r%s\n\r", raw_data);
m_radio->sram_write(m_tx_buffer_raw.data(), buffer_size + 1);
m_radio->set_current_state(radio::HwInstance::States::BUSY_TX);
m_tx_buffer_frame = std::nullopt;
} }
bool TransparentClient::m_txBufferIsReady() bool TransparentClient::m_txBufferIsReady()
{ {
return false; return m_tx_buffer_frame.has_value();
}
void TransparentClient::m_prepareTransmission(const std::uint16_t dst_mac, const std::array<std::uint8_t, 22>& buffer)
{
using namespace radio::protocol;
Address src_address;
src_address.setShortAddress(m_active_settings.short_address);
src_address.pan_id = m_active_settings.pan_id;
Address dst_address;
dst_address.setShortAddress(dst_mac);
dst_address.pan_id = m_active_settings.pan_id;
FrameStructure frame = FrameStructure::createDataFrame()
.setSourceAddress(src_address)
.setDestinationAddress(dst_address)
.setPayload(buffer);
m_tx_buffer_frame = frame;
} }
} }

View File

@ -11,6 +11,9 @@
namespace Hal = Peripherals::Hal::Samd; namespace Hal = Peripherals::Hal::Samd;
#define APP_NODE_ID 11
//#define APP_NODE_ID 18
namespace namespace
{ {
@ -39,7 +42,8 @@ int main()
SKULLC_LOG_DEBUG("Begin."); SKULLC_LOG_DEBUG("Begin.");
const App::RadioSettings settings; App::RadioSettings settings;
settings.short_address = APP_NODE_ID;
m_app.setup(settings); m_app.setup(settings);

View File

@ -66,6 +66,8 @@ struct HwInstance
} }
} }
void sram_write(const std::uint8_t* data, const std::size_t length, const std::uint8_t offset = 0);
States current_state() const; States current_state() const;
bool set_current_state(const States& new_state); bool set_current_state(const States& new_state);

View File

@ -10,7 +10,7 @@
namespace radio::protocol namespace radio::protocol
{ {
std::size_t composeFrameBuffer(const FrameStructure& frame); std::size_t composeFrameBuffer(std::uint8_t* data, const FrameStructure& frame);
FrameStructure decomposeFrameBuffer(const std::uint8_t* data); FrameStructure decomposeFrameBuffer(const std::uint8_t* data);
} }

View File

@ -120,6 +120,21 @@ void HwInstance::register_write(const Registers& address, const uint8_t value)
gpio_set_pin_level(OUT_RADIO_CS, true); gpio_set_pin_level(OUT_RADIO_CS, true);
} }
void HwInstance::sram_write(const std::uint8_t* data, const std::size_t length, const std::uint8_t offset)
{
std::uint8_t header_data[2] = {
std::uint8_t(0x40),
offset
};
gpio_set_pin_level(OUT_RADIO_CS, false);
io_write(m_spi_io, header_data, 2);
io_write(m_spi_io, data, length);
gpio_set_pin_level(OUT_RADIO_CS, true);
}
HwInstance::States HwInstance::current_state() const HwInstance::States HwInstance::current_state() const
{ {
return m_current_state; return m_current_state;

View File

@ -57,6 +57,7 @@ FrameStructure FrameStructure::createDataFrame()
FrameStructure& FrameStructure::setPayload(const std::uint8_t* data, const std::uint8_t length) FrameStructure& FrameStructure::setPayload(const std::uint8_t* data, const std::uint8_t length)
{ {
std::memmove(payload.data(), data, length); std::memmove(payload.data(), data, length);
payload_length = length;
return *this; return *this;
} }

View File

@ -0,0 +1,142 @@
from dataclasses import dataclass
from enum import Enum
from typing import Optional
MAX_PAYLOAD_LENGTH = 127
@dataclass
class PhyHeader:
frame_length: int
@property
def size(self) -> int:
return 1
@staticmethod
def from_bytes(data: bytes) -> "PhyHeader":
return PhyHeader(data[0] & 0x7F)
class FrameType(Enum):
BEACON = 0b000
DATA = 0b001
ACKNOWLEDGE = 0b010
MAC_COMMAND = 0b011
class AddressingMode(Enum):
NOT_SPECIFIED = 0b00
RESERVED = 0b01
SHORT = 0b10
LONG = 0b11
@dataclass
class FrameControlField:
type: FrameType
security_enabled: bool
frame_pending: bool
ack_requested: bool
pan_id_compression: bool
destination_addressing_mode: AddressingMode
frame_version: int
source_addressing_mode: AddressingMode
@property
def size(self) -> int:
return 2
@staticmethod
def from_bytes(data: bytes) -> "FrameControlField":
frame_type = FrameType((data[0] & 0b1110_0000) >> 5)
security_enabled = bool(data[0] & 0b0001_0000 >> 4)
frame_pending = bool((data[0] & 0b0000_1000) >> 3)
ack_requested = bool((data[0] & 0b0000_0100) >> 2)
pan_id_compression = bool((data[0] & 0b0000_0010) >> 1)
dst_addressing = AddressingMode((data[1] & 0b0011_0000) >> 4)
frame_version = (data[1] & 0b0000_1100) >> 2
src_addressing = AddressingMode((data[1] & 0b0000_0011))
return FrameControlField(
frame_type,
security_enabled,
frame_pending,
ack_requested,
pan_id_compression,
dst_addressing,
frame_version,
src_addressing
)
@dataclass
class Address:
mac: int
pan_id: int
is_short_mode: bool = False
@property
def size(self) -> int:
if self.is_short_mode:
return 2 + 2
else:
return 2 + 8
@staticmethod
def from_bytes(data: bytes, addressing_mode: AddressingMode) -> Optional["Address"]:
if addressing_mode == AddressingMode.NOT_SPECIFIED:
return None
pan = int.from_bytes(data[0:2], byteorder="little")
if addressing_mode == AddressingMode.SHORT:
is_short = True
address = int.from_bytes(data[2:4], byteorder="little")
else:
is_short = False
address = int.from_bytes(data[2:10], byteorder="little")
return Address(
address,
pan,
is_short
)
@dataclass
class MacProtocolDataUnit:
frame_control_field: FrameControlField
sequence_number: int
destination_address: Optional[Address]
source_address: Optional[Address]
payload: bytes
frame_checksum: int
def payload_length(self, header: PhyHeader) -> int:
# Payload length = length - FCF size - sequence nr (2 bytes) - src address size - dst address size
# - checksum size (2 bytes)
return header.frame_length - self.frame_control_field.size \
- 2 \
- self.source_address.size \
- self.destination_address.size \
- 2
@staticmethod
def from_bytes(data: bytes, header: PhyHeader) -> "MacProtocolDataUnit":
offset = 0
fcf = FrameControlField.from_bytes(data)
offset += fcf.size
sequence_nr = int.from_bytes(data[offset:], byteorder="little")
offset += 2
dst_address = Address.from_bytes(data[offset:], fcf.destination_addressing_mode)
offset += dst_address.size if dst_address else 0
src_address = Address.from_bytes(data[offset:], fcf.source_addressing_mode)
offset += src_address.size if src_address else 0
# @todo: payload and CRC parsing.
return MacProtocolDataUnit(fcf, sequence_nr, dst_address, src_address, bytes(), 0)

View File

@ -0,0 +1,19 @@
from packet_structs import *
def decode_sram(data: bytes) -> (PhyHeader, MacProtocolDataUnit):
header = PhyHeader.from_bytes(data)
mpdu = MacProtocolDataUnit.from_bytes(data[1:], header)
return header, mpdu
if __name__ == "__main__":
raw_data_str = "230198002300120023000B004C6F6C20746869732069732061206D65737361676500"
raw_data = bytes.fromhex(raw_data_str)
print(f"Raw:\n\r{raw_data}\n\r")
header, mpdu = decode_sram(raw_data)
print(f"Header: {header}")
print(f"MPDU: {mpdu}")