Skip to content
Snippets Groups Projects
fsm_slave.c 39.2 KiB
Newer Older
void ec_fsm_slave_conf_enter_pdo_sync(
        ec_fsm_slave_t *fsm /**< slave state machine */
        )
{
    ec_slave_t *slave = fsm->slave;
    ec_datagram_t *datagram = fsm->datagram;
    unsigned int i, offset, num_syncs;
    const ec_sync_t *sync;
    ec_direction_t dir;
    uint16_t size;
    if (!slave->sii_sync_count) {
    if (slave->sii_mailbox_protocols) {
        offset = 2; // slave has mailboxes
    } else {
        offset = 0;
    }
    num_syncs = slave->sii_sync_count - offset;
    // configure sync managers for process data
    ec_datagram_npwr(datagram, slave->station_address,
            0x0800 + EC_SYNC_PAGE_SIZE * offset,
            EC_SYNC_PAGE_SIZE * num_syncs);
    memset(datagram->data, 0x00, EC_SYNC_PAGE_SIZE * num_syncs);

    for (i = 0; i < num_syncs; i++) {
        sync = &slave->sii_syncs[i + offset];
        dir = ec_sync_direction(sync);
        size = ec_pdo_mapping_total_size(&slave->config->mapping[dir]);
        ec_sync_config(sync, size, datagram->data + EC_SYNC_PAGE_SIZE * i);
    fsm->state = ec_fsm_slave_conf_state_pdo_sync;
}

/*****************************************************************************/

/**
 * Configure PDO sync managers.
void ec_fsm_slave_conf_state_pdo_sync(ec_fsm_slave_t *fsm /**< slave state machine */)
{
    ec_datagram_t *datagram = fsm->datagram;
    ec_slave_t *slave = fsm->slave;

    if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
        return;

    if (datagram->state != EC_DATAGRAM_RECEIVED) {
        fsm->state = ec_fsm_slave_state_error;
        EC_ERR("Failed to receive process data sync manager configuration"
               " datagram for slave %i (datagram state %i).\n",
               slave->ring_position, datagram->state);
        return;
    }

    if (datagram->working_counter != 1) {
        slave->error_flag = 1;
        fsm->state = ec_fsm_slave_state_error;
        EC_ERR("Failed to set process data sync managers of slave %i: ",
                slave->ring_position);
        ec_datagram_print_wc_error(datagram);
        return;
    }

    ec_fsm_slave_conf_enter_fmmu(fsm);
}

/*****************************************************************************/

/**
 * Check for FMMUs to be configured.
 */

void ec_fsm_slave_conf_enter_fmmu(ec_fsm_slave_t *fsm /**< slave state machine */)
{
    ec_slave_t *slave = fsm->slave;
    ec_datagram_t *datagram = fsm->datagram;
    unsigned int i;
    const ec_fmmu_config_t *fmmu;
    const ec_sync_t *sync;

    if (!slave->base_fmmu_count) { // skip FMMU configuration
        ec_fsm_slave_conf_enter_saveop(fsm);
        return;
    }

    // configure FMMUs
    ec_datagram_npwr(datagram, slave->station_address,
                     0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
    memset(datagram->data, 0x00, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
    for (i = 0; i < slave->config->used_fmmus; i++) {
        fmmu = &slave->config->fmmu_configs[i];
        if (!(sync = ec_slave_get_pdo_sync(slave, fmmu->dir))) {
            fsm->state = ec_fsm_slave_state_error;
            EC_ERR("Failed to determine PDO sync manager for FMMU on slave"
                    " %u!\n", slave->ring_position);
            return;
        }
        ec_fmmu_config_page(fmmu, sync,
                datagram->data + EC_FMMU_PAGE_SIZE * i);
    }

    fsm->retries = EC_FSM_RETRIES;
    fsm->state = ec_fsm_slave_conf_state_fmmu;
}

/*****************************************************************************/

/**
   Slave configuration state: FMMU.
*/

void ec_fsm_slave_conf_state_fmmu(ec_fsm_slave_t *fsm /**< slave state machine */)
{
    ec_datagram_t *datagram = fsm->datagram;
    ec_slave_t *slave = fsm->slave;

    if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
        return;

    if (datagram->state != EC_DATAGRAM_RECEIVED) {
        fsm->state = ec_fsm_slave_state_error;
        EC_ERR("Failed to receive FMMUs datagram for slave %i"
                " (datagram state %i).\n",
               slave->ring_position, datagram->state);
        EC_ERR("Failed to set FMMUs of slave %i: ",
        ec_datagram_print_wc_error(datagram);
        return;
    }

    ec_fsm_slave_conf_enter_saveop(fsm);
}

/*****************************************************************************/

/**
 * Request SAVEOP state.
 */

void ec_fsm_slave_conf_enter_saveop(ec_fsm_slave_t *fsm /**< slave state machine */)
{
    fsm->state = ec_fsm_slave_conf_state_saveop;
    ec_fsm_change_start(&fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_SAVEOP);
    ec_fsm_change_exec(&fsm->fsm_change); // execute immediately
}

/*****************************************************************************/

/**
   Slave configuration state: SAVEOP.
*/

void ec_fsm_slave_conf_state_saveop(ec_fsm_slave_t *fsm /**< slave state machine */)
{
    ec_master_t *master = fsm->slave->master;
    ec_slave_t *slave = fsm->slave;

    if (ec_fsm_change_exec(&fsm->fsm_change)) return;

    if (!ec_fsm_change_success(&fsm->fsm_change)) {
        if (!fsm->fsm_change.spontaneous_change)
            fsm->slave->error_flag = 1;
        fsm->state = ec_fsm_slave_state_error;
        return;
    }

    // slave is now in SAVEOP

    if (master->debug_level) {
        EC_DBG("Slave %i is now in SAVEOP.\n", slave->ring_position);
    }

    if (fsm->slave->current_state == fsm->slave->requested_state) {
        fsm->state = ec_fsm_slave_state_end; // successful
        if (master->debug_level) {
            EC_DBG("Finished configuration of slave %i.\n",
                   slave->ring_position);
        }
        return;
    }

    // set state to OP
    fsm->state = ec_fsm_slave_conf_state_op;
    ec_fsm_change_start(&fsm->fsm_change, slave, EC_SLAVE_STATE_OP);
    ec_fsm_change_exec(&fsm->fsm_change); // execute immediately
}

/*****************************************************************************/

/**
   Slave configuration state: OP
*/

void ec_fsm_slave_conf_state_op(ec_fsm_slave_t *fsm /**< slave state machine */)
{
    ec_master_t *master = fsm->slave->master;
    ec_slave_t *slave = fsm->slave;

    if (ec_fsm_change_exec(&fsm->fsm_change)) return;

    if (!ec_fsm_change_success(&fsm->fsm_change)) {
        if (!fsm->fsm_change.spontaneous_change)
            slave->error_flag = 1;
        fsm->state = ec_fsm_slave_state_error;
        return;
    }

    // slave is now in OP

    if (master->debug_level) {
        EC_DBG("Slave %i is now in OP.\n", slave->ring_position);
        EC_DBG("Finished configuration of slave %i.\n", slave->ring_position);
    }

    fsm->state = ec_fsm_slave_state_end; // successful
}

/******************************************************************************
 *  Common state functions
 *****************************************************************************/

/**
   State: ERROR.
*/

void ec_fsm_slave_state_error(ec_fsm_slave_t *fsm /**< slave state machine */)
{
}

/*****************************************************************************/

/**
   State: END.
*/

void ec_fsm_slave_state_end(ec_fsm_slave_t *fsm /**< slave state machine */)
{
}

/*****************************************************************************/