Skip to content

File syn_lss.c

File List > proto > syn_lss.c

Go to the documentation of this file

#include "syn_lss.h"

#include "../util/syn_assert.h"
#include "../util/syn_pack.h"

#include <string.h>

void syn_lss_slave_init(SYN_LSSSlave *slave, const SYN_LSSAddress *addr, uint8_t initial_node_id)
{
    SYN_ASSERT(slave != NULL && addr != NULL);
    memset(slave, 0, sizeof(*slave));
    slave->mode = SYN_LSS_MODE_OPERATION;
    slave->node_id = initial_node_id;
    slave->baud_table = SYN_LSS_BAUD_250K;
    slave->addr = *addr;
    slave->store_req = false;
}

bool syn_lss_slave_process(SYN_LSSSlave *slave, const SYN_CAN_Frame *frame, SYN_CAN_Frame *resp)
{
    SYN_ASSERT(slave != NULL && frame != NULL && resp != NULL);

    /* LSS Requests must use COB-ID 0x7E5 and DLC 8 */
    if (frame->id != SYN_LSS_COB_ID_MASTER || frame->dlc < 8) {
        return false;
    }

    uint8_t cs = frame->data[0];
    memset(resp, 0, sizeof(*resp));
    resp->id = SYN_LSS_COB_ID_SLAVE;
    resp->dlc = 8;

    switch (cs) {
    case SYN_LSS_CS_SWITCH_MODE_GLOBAL:
        slave->mode = frame->data[1];
        return false; /* Global switch has no response */

    case SYN_LSS_CS_CONFIGURE_NODE_ID:
        if (slave->mode == SYN_LSS_MODE_CONFIGURATION) {
            uint8_t new_id = frame->data[1];
            resp->data[0] = SYN_LSS_CS_CONFIGURE_NODE_ID;
            if (new_id >= 1 && new_id <= 127) {
                slave->node_id = new_id;
                resp->data[1] = 0; /* Error code 0 = protocol error / OK */
                resp->data[2] = 0; /* Spec error 0 = success */
            } else {
                resp->data[1] = 1; /* Out of range error */
                resp->data[2] = 0xFF;
            }
            return true;
        }
        break;

    case SYN_LSS_CS_CONFIGURE_BIT_TIMING:
        if (slave->mode == SYN_LSS_MODE_CONFIGURATION) {
            uint8_t baud_idx = frame->data[2];
            resp->data[0] = SYN_LSS_CS_CONFIGURE_BIT_TIMING;
            if (baud_idx <= SYN_LSS_BAUD_10K) {
                slave->baud_table = baud_idx;
                resp->data[1] = 0; /* Success */
                resp->data[2] = 0;
            } else {
                resp->data[1] = 1; /* Unsupported bit timing */
                resp->data[2] = 0xFF;
            }
            return true;
        }
        break;

    case SYN_LSS_CS_STORE_CONFIG:
        if (slave->mode == SYN_LSS_MODE_CONFIGURATION) {
            slave->store_req = true;
            resp->data[0] = SYN_LSS_CS_STORE_CONFIG;
            resp->data[1] = 0; /* Success */
            resp->data[2] = 0;
            return true;
        }
        break;

    case SYN_LSS_CS_INQUIRE_VENDOR:
        if (slave->mode == SYN_LSS_MODE_CONFIGURATION) {
            resp->data[0] = SYN_LSS_CS_INQUIRE_VENDOR;
            syn_poke_u32_le(slave->addr.vendor_id, resp->data, 1);
            return true;
        }
        break;

    case SYN_LSS_CS_INQUIRE_PRODUCT:
        if (slave->mode == SYN_LSS_MODE_CONFIGURATION) {
            resp->data[0] = SYN_LSS_CS_INQUIRE_PRODUCT;
            syn_poke_u32_le(slave->addr.product_code, resp->data, 1);
            return true;
        }
        break;

    case SYN_LSS_CS_INQUIRE_REV:
        if (slave->mode == SYN_LSS_MODE_CONFIGURATION) {
            resp->data[0] = SYN_LSS_CS_INQUIRE_REV;
            syn_poke_u32_le(slave->addr.revision_no, resp->data, 1);
            return true;
        }
        break;

    case SYN_LSS_CS_INQUIRE_SERIAL:
        if (slave->mode == SYN_LSS_MODE_CONFIGURATION) {
            resp->data[0] = SYN_LSS_CS_INQUIRE_SERIAL;
            syn_poke_u32_le(slave->addr.serial_no, resp->data, 1);
            return true;
        }
        break;

    default:
        break;
    }

    return false;
}

void syn_lss_master_build_switch_mode(SYN_CAN_Frame *frame, uint8_t mode)
{
    SYN_ASSERT(frame != NULL);
    memset(frame, 0, sizeof(*frame));
    frame->id = SYN_LSS_COB_ID_MASTER;
    frame->dlc = 8;
    frame->data[0] = SYN_LSS_CS_SWITCH_MODE_GLOBAL;
    frame->data[1] = mode;
}

void syn_lss_master_build_config_node_id(SYN_CAN_Frame *frame, uint8_t new_node_id)
{
    SYN_ASSERT(frame != NULL);
    memset(frame, 0, sizeof(*frame));
    frame->id = SYN_LSS_COB_ID_MASTER;
    frame->dlc = 8;
    frame->data[0] = SYN_LSS_CS_CONFIGURE_NODE_ID;
    frame->data[1] = new_node_id;
}

void syn_lss_master_build_config_bit_timing(SYN_CAN_Frame *frame, uint8_t baud_table_idx)
{
    SYN_ASSERT(frame != NULL);
    memset(frame, 0, sizeof(*frame));
    frame->id = SYN_LSS_COB_ID_MASTER;
    frame->dlc = 8;
    frame->data[0] = SYN_LSS_CS_CONFIGURE_BIT_TIMING;
    frame->data[1] = 0; /* Selector: 0 = Table, 1 = Bitrate */
    frame->data[2] = baud_table_idx;
}

void syn_lss_master_build_store_config(SYN_CAN_Frame *frame)
{
    SYN_ASSERT(frame != NULL);
    memset(frame, 0, sizeof(*frame));
    frame->id = SYN_LSS_COB_ID_MASTER;
    frame->dlc = 8;
    frame->data[0] = SYN_LSS_CS_STORE_CONFIG;
}