Skip to content

File syn_opcua.h

File List > proto > syn_opcua.h

Go to the documentation of this file

#ifndef SYN_OPCUA_H
#define SYN_OPCUA_H

#include "../common/syn_defs.h"
#include "../net/syn_transport.h"
#include "../pt/syn_pt.h"
#include "../sched/syn_sched.h"

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

#if !defined(SYN_USE_OPCUA) || SYN_USE_OPCUA

#ifdef __cplusplus
extern "C" {
#endif

/* ── Constants & Limits ─────────────────────────────────────────────────── */

#define SYN_OPCUA_DEFAULT_PORT 4840U        
#define SYN_OPCUA_MAX_NODES 32U             
#define SYN_OPCUA_MAX_REFERENCES 8U         
#define SYN_OPCUA_MAX_STRING_LEN 64U        
#define SYN_OPCUA_PROTOCOL_VERSION 0U       
#define SYN_OPCUA_DEFAULT_BUFFER_SIZE 1024U 
/* OPC UA Standard StatusCode constants */
#define SYN_OPCUA_STATUS_GOOD 0x00000000U               
#define SYN_OPCUA_STATUS_UNCERTAIN 0x40000000U          
#define SYN_OPCUA_STATUS_BAD_UNEXPECTED 0x80010000U     
#define SYN_OPCUA_STATUS_BAD_INTERNAL_ERROR 0x80020000U 
#define SYN_OPCUA_STATUS_BAD_NODE_ID_UNKNOWN            \
    0x80340000U 
#define SYN_OPCUA_STATUS_BAD_ATTRIBUTE_ID_INVALID 0x80350000U 
#define SYN_OPCUA_STATUS_BAD_NOT_READABLE 0x803A0000U         
#define SYN_OPCUA_STATUS_BAD_NOT_WRITABLE 0x803B0000U         
#define SYN_OPCUA_STATUS_BAD_SERVICE_UNSUPPORTED \
    0x80430000U 
#define SYN_OPCUA_STATUS_BAD_SECURITY_CHECKS_FAILED \
    0x80130000U 
/* Standard OPC UA Attribute IDs */
#define SYN_OPCUA_ATTR_NODE_ID 1U       
#define SYN_OPCUA_ATTR_NODE_CLASS 2U    
#define SYN_OPCUA_ATTR_BROWSE_NAME 3U   
#define SYN_OPCUA_ATTR_DISPLAY_NAME 4U  
#define SYN_OPCUA_ATTR_VALUE 13U        
#define SYN_OPCUA_ATTR_DATA_TYPE 14U    
#define SYN_OPCUA_ATTR_VALUE_RANK 15U   
#define SYN_OPCUA_ATTR_ACCESS_LEVEL 17U 
/* Standard Node Types & Namespaces */
#define SYN_OPCUA_NS_STANDARD 0U 
#define SYN_OPCUA_NS_VENDOR 1U   
/* Standard Well-Known Node IDs */
#define SYN_OPCUA_NODEID_ROOT 84U                  
#define SYN_OPCUA_NODEID_OBJECTS_FOLDER 85U        
#define SYN_OPCUA_NODEID_SERVER 2253U              
#define SYN_OPCUA_NODEID_SERVER_SERVERSTATUS 2256U 
/* ── Type Definitions ────────────────────────────────────────────────────── */

typedef enum {
    SYN_OPCUA_NODECLASS_UNSPECIFIED = 0,
    SYN_OPCUA_NODECLASS_OBJECT = 1,
    SYN_OPCUA_NODECLASS_VARIABLE = 2,
    SYN_OPCUA_NODECLASS_METHOD = 4
} SYN_OPCUA_NodeClass;

typedef enum {
    SYN_OPCUA_TYPE_NULL = 0,
    SYN_OPCUA_TYPE_BOOLEAN = 1,
    SYN_OPCUA_TYPE_SBYTE = 2,
    SYN_OPCUA_TYPE_BYTE = 3,
    SYN_OPCUA_TYPE_INT16 = 4,
    SYN_OPCUA_TYPE_UINT16 = 5,
    SYN_OPCUA_TYPE_INT32 = 6,
    SYN_OPCUA_TYPE_UINT32 = 7,
    SYN_OPCUA_TYPE_INT64 = 8,
    SYN_OPCUA_TYPE_UINT64 = 9,
    SYN_OPCUA_TYPE_FLOAT = 10,
    SYN_OPCUA_TYPE_DOUBLE = 11,
    SYN_OPCUA_TYPE_STRING = 12,
    SYN_OPCUA_TYPE_DATETIME = 13
} SYN_OPCUA_DataType;

typedef enum { SYN_OPCUA_NODEID_NUMERIC = 0, SYN_OPCUA_NODEID_STRING = 1 } SYN_OPCUA_NodeIdType;

typedef struct {
    uint16_t ns_index;            
    SYN_OPCUA_NodeIdType id_type; 
    union {
        uint32_t num;    
        const char *str; 
    } id;                
} SYN_OPCUA_NodeId;

typedef struct {
    SYN_OPCUA_DataType type; 
    union {
        bool boolean;       
        int8_t sbyte;       
        uint8_t byte;       
        int16_t int16;      
        uint16_t uint16;    
        int32_t int32;      
        uint32_t uint32;    
        int64_t int64;      
        uint64_t uint64;    
        float float_val;    
        double double_val;  
        const char *string; 
    } val;                  
} SYN_OPCUA_Variant;

typedef struct {
    SYN_OPCUA_Variant value; 
    uint32_t status_code;    
    uint64_t source_ts_ms;   
} SYN_OPCUA_DataValue;

struct SYN_OPCUA_Server;
struct SYN_OPCUA_Node;

typedef SYN_Status (*SYN_OPCUA_ReadCb)(struct SYN_OPCUA_Server *srv,
                                       const struct SYN_OPCUA_Node *node,
                                       SYN_OPCUA_DataValue *out_val, void *user_data);

typedef SYN_Status (*SYN_OPCUA_WriteCb)(struct SYN_OPCUA_Server *srv,
                                        const struct SYN_OPCUA_Node *node,
                                        const SYN_OPCUA_DataValue *in_val, void *user_data);

typedef struct SYN_OPCUA_Node {
    SYN_OPCUA_NodeId node_id;       
    SYN_OPCUA_NodeClass node_class; 
    const char *browse_name;        
    const char *display_name;       
    SYN_OPCUA_DataType data_type;   
    SYN_OPCUA_DataValue value;      
    uint8_t access_level;           
    /* Hierarchical parent linking */
    SYN_OPCUA_NodeId parent_id; 
    SYN_OPCUA_ReadCb on_read;   
    SYN_OPCUA_WriteCb on_write; 
    void *user_data;            
} SYN_OPCUA_Node;

typedef struct {
    const char *endpoint_url; 
    const char *server_name;  
    SYN_Transport *transport; 
    void *user_data;          
    uint8_t *rx_buf;    
    size_t rx_buf_size; 
    uint8_t *tx_buf;    
    size_t tx_buf_size; 
} SYN_OPCUA_Config;

typedef enum {
    SYN_OPCUA_STATE_CLOSED = 0,     
    SYN_OPCUA_STATE_HELLO_RECEIVED, 
    SYN_OPCUA_STATE_SECURE_CHANNEL, 
    SYN_OPCUA_STATE_SESSION_ACTIVE  
} SYN_OPCUA_ServerState;

typedef struct SYN_OPCUA_Server {
    SYN_OPCUA_Config cfg;        
    SYN_OPCUA_ServerState state; 
    SYN_PT pt;                   
    uint32_t secure_channel_id; 
    uint32_t security_token_id; 
    uint32_t sequence_number;   
    uint32_t request_id;        
    SYN_OPCUA_Node nodes[SYN_OPCUA_MAX_NODES]; 
    size_t node_count;                         
} SYN_OPCUA_Server;

/* ── Public API ─────────────────────────────────────────────────────────── */

SYN_Status syn_opcua_server_init(SYN_OPCUA_Server *srv, const SYN_OPCUA_Config *cfg);

SYN_Status syn_opcua_server_register_node(SYN_OPCUA_Server *srv, const SYN_OPCUA_Node *node);

SYN_OPCUA_Node *syn_opcua_server_find_node_num(SYN_OPCUA_Server *srv, uint16_t ns, uint32_t num_id);

SYN_Status syn_opcua_server_write_variable(SYN_OPCUA_Server *srv, uint16_t ns, uint32_t num_id,
                                           const SYN_OPCUA_Variant *val);

SYN_Status syn_opcua_server_read_variable(const SYN_OPCUA_Server *srv, uint16_t ns, uint32_t num_id,
                                          SYN_OPCUA_Variant *out_val);

SYN_Status syn_opcua_server_process_message(SYN_OPCUA_Server *srv, const uint8_t *rx, size_t rx_len,
                                            uint8_t *tx, size_t max_tx, size_t *out_len);

SYN_Status syn_opcua_server_step(SYN_OPCUA_Server *srv, uint32_t now_ms);

SYN_PT_Status syn_opcua_server_pt(SYN_PT *pt, SYN_Task *task);

#ifdef __cplusplus
}
#endif

#endif /* SYN_USE_OPCUA */

#endif /* SYN_OPCUA_H */