Skip to content

File baton_node.h

File List > inc > baton_node.h

Go to the documentation of this file

#ifndef BATON_NODE_H
#define BATON_NODE_H

#include <stdbool.h>
#include <stdint.h>

#include "baton_config.h"
#include "baton_defs.h"
#include "baton_link.h"
#include "baton_queue.h"

#ifdef __cplusplus
extern "C"
{
#endif

#define BATON_OK 0              
#define BATON_ERR_PARAM (-1)    
#define BATON_ERR_NOT_INIT (-2) 
#define BATON_ERR_MSG_ID (-3)   
#define BATON_ERR_LEN (-4)      
#define BATON_ERR_ADDR (-5)     
#define BATON_ERR_FULL (-6)     
#define BATON_ROLE_MASTER 0U 
#define BATON_ROLE_SLAVE 1U  
#define BATON_PRIO_NORMAL 0U 
#define BATON_PRIO_HIGH 1U   
#define BATON_MASK_BYTES ((BATON_MAX_NODES + 7U) / 8U)
#define BATON_POLL_PREFIX 1U
#define BATON_RESP_PREFIX (1U + BATON_MASK_BYTES)
#define BATON_MAX_MSG_LEN (BATON_MAX_PAYLOAD - BATON_RESP_PREFIX - BATON_TLV_HEADER_SIZE)

#define BATON_DEAD_STREAK 3U
#define BATON_DEAD_POLL_DIV 4U

/* Deviation DEV-04 (Rule 20.10): token pasting builds the public names from the lists. */
/* cppcheck-suppress misra-c2012-20.10 */
#define BATON_X_MSG_ENUM_(name, id, max_length) BATON_MSG_##name = (id),
/* cppcheck-suppress misra-c2012-20.10 */
#define BATON_X_MSG_SIZE_(name, id, max_length) BATON_MSG_##name##_MAX_LEN = (max_length),
#define BATON_X_COUNT_(name, id, max_length) +1U
#define BATON_X_STATE_SIZE_(name, id, max_length) +(uint32_t) (max_length)
enum baton_msg_id
{
    BATON_STATE_LIST(BATON_X_MSG_ENUM_) BATON_EVENT_LIST(BATON_X_MSG_ENUM_) BATON_MSG_INVALID_ =
        0x100
};

enum baton_msg_max_len
{
    BATON_STATE_LIST(BATON_X_MSG_SIZE_) BATON_EVENT_LIST(BATON_X_MSG_SIZE_) BATON_MSG_SIZE_DUMMY_ =
        0
};

#define BATON_STATE_COUNT (0U BATON_STATE_LIST(BATON_X_COUNT_))
#define BATON_EVENT_COUNT (0U BATON_EVENT_LIST(BATON_X_COUNT_))
#define BATON_STATE_DATA_SIZE (1U BATON_STATE_LIST(BATON_X_STATE_SIZE_))

typedef void (*baton_critical_fn)(void* context);

typedef void (*baton_message_fn)(void* context, uint8_t src, uint8_t msg_id, const uint8_t* data,
                                 uint8_t length);

typedef void (*baton_drop_fn)(void* context, uint8_t msg_id, uint8_t dst, uint32_t missed_nodes);

typedef void (*baton_poll_done_fn)(void* context, uint8_t slave, bool responded,
                                   uint32_t nack_nodes);

struct baton_node_config
{
    /* Topology */
    uint8_t role;                   
    uint8_t own_address;            
    uint8_t master_address;         
    const uint8_t* slave_addresses; 
    uint8_t slave_count;            
    /* Timing (milliseconds unless stated) */
    uint32_t baudrate;             
    uint16_t slot_time_ms;         
    uint16_t ack_timeout_ms;       
    uint8_t max_retries;           
    uint8_t tx_gap_ms;             
    uint8_t inter_byte_timeout_ms; 
    uint16_t cycle_period_ms; 
    uint32_t event_ttl_ms;    
    /* UART */
    bool rx_echo;         
    baton_write_fn write; 
    /* Critical section (optional, both or neither) */
    baton_critical_fn enter_critical; 
    baton_critical_fn exit_critical;  
    /* Application callbacks (optional, called from baton_node_process()) */
    baton_message_fn on_message;     
    baton_drop_fn on_drop;           
    baton_poll_done_fn on_poll_done; 
    void* context; 
};

struct baton_stats
{
    uint32_t tx_frames;         
    uint32_t rx_frames;         
    uint32_t crc_errors;        
    uint32_t rx_timeouts;       
    uint32_t rx_overflows;      
    uint32_t collisions;        
    uint32_t tx_timeouts;       
    uint32_t ack_timeouts;      
    uint32_t retries;           
    uint32_t resp_timeouts;     
    uint32_t duplicates;        
    uint32_t bad_messages;      
    uint32_t events_dropped;    
    uint32_t queue_full;        
    uint16_t queue_high_used;   
    uint16_t queue_normal_used; 
};

struct baton_channel
{
    uint16_t inflight[BATON_MAX_MSGS_PER_FRAME]; 
    uint8_t inflight_count; 
    uint8_t tx_seq;         
    bool tx_first;          
    uint8_t rx_seq;         
    bool rx_valid;          
    bool rx_last_first;     
    uint8_t resp_seq;       
    bool resp_valid;        
    uint8_t fail_streak;    
};

struct baton_node
{
    struct baton_node_config config; 
    struct baton_link link;          
    bool initialized;                
    uint8_t node_address[BATON_MAX_NODES]; 
    uint8_t node_count;                    
    uint8_t self_index;                    
    uint32_t others_mask;                  
    uint8_t tx_frame[BATON_FRAME_MAX];       
    uint8_t ack_frame[BATON_FRAME_OVERHEAD]; 
    struct baton_queue queue[2];                          
    uint8_t queue_high_memory[BATON_QUEUE_HIGH_SIZE];     
    uint8_t queue_normal_memory[BATON_QUEUE_NORMAL_SIZE]; 
    uint8_t state_data[BATON_STATE_DATA_SIZE];    
    uint8_t state_length[BATON_STATE_COUNT + 1U]; 
    uint32_t state_dirty[BATON_STATE_COUNT + 1U]; 
    struct baton_channel channel[BATON_MAX_NODES]; 
    uint8_t link_state;  
    uint32_t link_timer; 
    uint32_t slot_start; 
    uint8_t slot_peer;   
    uint8_t slot_k;      
    uint8_t slot_rr;     
    uint8_t slot_pass;   
    uint8_t retries;     
    uint32_t slot_nack;  
    uint8_t poll_seq;    
    uint8_t current;      
    uint32_t cycle_start; 
    uint32_t cycle_count; 
    uint32_t now_ms;            
    uint32_t last_housekeep_ms; 
    struct baton_stats stats;   
};

void baton_node_default_config(struct baton_node_config* config);

int baton_node_init(struct baton_node* node, const struct baton_node_config* config,
                    uint32_t now_ms);

void baton_node_process(struct baton_node* node, uint32_t now_ms);

int baton_node_send(struct baton_node* node, uint8_t dst, uint8_t msg_id, const void* data,
                    uint8_t length, uint8_t priority);

int baton_node_publish(struct baton_node* node, uint8_t msg_id, const void* data, uint8_t length);

void baton_node_rx_isr(struct baton_node* node, uint8_t byte);

void baton_node_tx_done_isr(struct baton_node* node);

void baton_node_get_stats(const struct baton_node* node, struct baton_stats* stats);

#ifdef __cplusplus
}
#endif

#endif /* BATON_NODE_H */