fp@220: /****************************************************************************** fp@220: * fp@220: * $Id$ fp@220: * fp@1326: * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH fp@220: * fp@220: * This file is part of the IgH EtherCAT Master. fp@220: * fp@1326: * The IgH EtherCAT Master is free software; you can redistribute it and/or fp@1326: * modify it under the terms of the GNU General Public License version 2, as fp@1326: * published by the Free Software Foundation. fp@1326: * fp@1326: * The IgH EtherCAT Master is distributed in the hope that it will be useful, fp@1326: * but WITHOUT ANY WARRANTY; without even the implied warranty of fp@1326: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General fp@1326: * Public License for more details. fp@1326: * fp@1326: * You should have received a copy of the GNU General Public License along fp@1326: * with the IgH EtherCAT Master; if not, write to the Free Software fp@220: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@220: * fp@1363: * --- fp@1363: * fp@1363: * The license mentioned above concerns the source code only. Using the fp@1363: * EtherCAT technology and brand is only permitted in compliance with the fp@1363: * industrial property and similar rights of Beckhoff Automation GmbH. fp@246: * fp@220: *****************************************************************************/ fp@220: fp@1501: #include fp@220: #include fp@220: #include fp@220: #include fp@1239: #include fp@220: fp@1501: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) fp@1501: #include fp@1501: #else fp@1501: #include fp@1501: #endif fp@1501: fp@223: #include "../../include/ecrt.h" // EtherCAT realtime interface fp@1613: fp@1613: #include "serial.h" fp@220: fp@820: /*****************************************************************************/ fp@820: fp@858: // Module parameters fp@220: #define FREQUENCY 100 fp@858: fp@1171: // Optional features fp@1567: fp@1567: #define PFX "ec_tty_example: " fp@820: fp@820: /*****************************************************************************/ fp@220: fp@220: // EtherCAT fp@612: static ec_master_t *master = NULL; fp@818: static ec_master_state_t master_state = {}; fp@1500: struct semaphore master_sem; fp@818: fp@612: static ec_domain_t *domain1 = NULL; fp@818: static ec_domain_state_t domain1_state = {}; fp@818: fp@1080: // Timer fp@820: static struct timer_list timer; fp@820: fp@820: /*****************************************************************************/ fp@820: fp@820: // process data fp@820: static uint8_t *domain1_pd; // process data memory fp@820: fp@1567: #define BusCouplerPos 0, 0 fp@1567: fp@1567: #define Beckhoff_EK1100 0x00000002, 0x044c2c52 fp@1080: fp@1080: static unsigned int counter = 0; fp@1567: fp@858: /*****************************************************************************/ fp@858: fp@818: void check_domain1_state(void) fp@818: { fp@818: ec_domain_state_t ds; fp@818: fp@1500: down(&master_sem); fp@818: ecrt_domain_state(domain1, &ds); fp@1500: up(&master_sem); fp@1022: fp@818: if (ds.working_counter != domain1_state.working_counter) fp@1022: printk(KERN_INFO PFX "Domain1: WC %u.\n", ds.working_counter); fp@818: if (ds.wc_state != domain1_state.wc_state) fp@1022: printk(KERN_INFO PFX "Domain1: State %u.\n", ds.wc_state); fp@818: fp@818: domain1_state = ds; fp@818: } fp@818: fp@818: /*****************************************************************************/ fp@818: fp@818: void check_master_state(void) fp@818: { fp@818: ec_master_state_t ms; fp@818: fp@1500: down(&master_sem); fp@818: ecrt_master_state(master, &ms); fp@1500: up(&master_sem); fp@818: fp@1022: if (ms.slaves_responding != master_state.slaves_responding) fp@1022: printk(KERN_INFO PFX "%u slave(s).\n", ms.slaves_responding); fp@1022: if (ms.al_states != master_state.al_states) fp@1022: printk(KERN_INFO PFX "AL states: 0x%02X.\n", ms.al_states); fp@1022: if (ms.link_up != master_state.link_up) fp@1022: printk(KERN_INFO PFX "Link is %s.\n", ms.link_up ? "up" : "down"); fp@818: fp@818: master_state = ms; fp@818: } fp@220: fp@220: /*****************************************************************************/ fp@220: fp@820: void cyclic_task(unsigned long data) fp@820: { fp@818: // receive process data fp@1500: down(&master_sem); fp@325: ecrt_master_receive(master); fp@220: ecrt_domain_process(domain1); fp@1500: up(&master_sem); fp@220: fp@818: // check process data state (optional) fp@818: check_domain1_state(); fp@512: fp@512: if (counter) { fp@512: counter--; fp@858: } else { // do this at 1 Hz fp@512: counter = FREQUENCY; fp@818: fp@818: // check for master state (optional) fp@818: check_master_state(); fp@1567: } fp@1567: fp@1613: run_serial_devices(domain1_pd); fp@818: fp@818: // send process data fp@1500: down(&master_sem); fp@509: ecrt_domain_queue(domain1); fp@325: ecrt_master_send(master); fp@1500: up(&master_sem); fp@220: fp@220: // restart timer fp@220: timer.expires += HZ / FREQUENCY; fp@220: add_timer(&timer); fp@220: } fp@220: fp@220: /*****************************************************************************/ fp@220: fp@1513: void send_callback(void *cb_data) fp@1513: { fp@1513: ec_master_t *m = (ec_master_t *) cb_data; fp@1513: down(&master_sem); fp@1513: ecrt_master_send_ext(m); fp@1513: up(&master_sem); fp@1513: } fp@1513: fp@1513: /*****************************************************************************/ fp@1513: fp@1513: void receive_callback(void *cb_data) fp@1513: { fp@1513: ec_master_t *m = (ec_master_t *) cb_data; fp@1513: down(&master_sem); fp@1513: ecrt_master_receive(m); fp@1500: up(&master_sem); fp@220: } fp@220: fp@220: /*****************************************************************************/ fp@220: fp@220: int __init init_mini_module(void) fp@220: { fp@1239: int ret = -1; fp@792: ec_slave_config_t *sc; fp@2421: fp@612: printk(KERN_INFO PFX "Starting...\n"); fp@220: fp@1239: master = ecrt_request_master(0); fp@1378: if (!master) { fp@1613: printk(KERN_ERR PFX "Requesting master 0 failed.\n"); fp@2421: ret = -EBUSY; fp@1613: goto out_return; fp@220: } fp@220: martin@1579: sema_init(&master_sem, 1); fp@1513: ecrt_master_callbacks(master, send_callback, receive_callback, master); fp@220: fp@612: printk(KERN_INFO PFX "Registering domain...\n"); fp@509: if (!(domain1 = ecrt_master_create_domain(master))) { fp@612: printk(KERN_ERR PFX "Domain creation failed!\n"); fp@612: goto out_release_master; fp@612: } fp@612: fp@1567: // Create configuration for bus coupler fp@1567: sc = ecrt_master_slave_config(master, BusCouplerPos, Beckhoff_EK1100); fp@1613: if (!sc) { fp@1613: printk(KERN_ERR PFX "Failed to create slave config.\n"); fp@1613: ret = -ENOMEM; fp@1613: goto out_release_master; fp@1613: } fp@1613: fp@1613: create_serial_devices(master, domain1); fp@809: fp@612: printk(KERN_INFO PFX "Activating master...\n"); fp@220: if (ecrt_master_activate(master)) { fp@612: printk(KERN_ERR PFX "Failed to activate master!\n"); fp@1613: goto out_free_serial; fp@1567: } fp@1567: fp@809: // Get internal process data for domain fp@820: domain1_pd = ecrt_domain_data(domain1); fp@612: fp@612: printk(KERN_INFO PFX "Starting cyclic sample thread.\n"); fp@220: init_timer(&timer); fp@820: timer.function = cyclic_task; fp@220: timer.expires = jiffies + 10; fp@220: add_timer(&timer); fp@220: fp@612: printk(KERN_INFO PFX "Started.\n"); fp@220: return 0; fp@220: fp@1613: out_free_serial: fp@1613: free_serial_devices(); fp@809: out_release_master: fp@654: printk(KERN_ERR PFX "Releasing master...\n"); fp@220: ecrt_release_master(master); fp@809: out_return: fp@654: printk(KERN_ERR PFX "Failed to load. Aborting.\n"); fp@1239: return ret; fp@220: } fp@220: fp@220: /*****************************************************************************/ fp@220: fp@220: void __exit cleanup_mini_module(void) fp@220: { fp@612: printk(KERN_INFO PFX "Stopping...\n"); fp@220: fp@449: del_timer_sync(&timer); fp@809: fp@1613: free_serial_devices(); fp@1613: fp@612: printk(KERN_INFO PFX "Releasing master...\n"); fp@449: ecrt_release_master(master); fp@220: fp@654: printk(KERN_INFO PFX "Unloading.\n"); fp@220: } fp@220: fp@220: /*****************************************************************************/ fp@220: fp@220: MODULE_LICENSE("GPL"); fp@512: MODULE_AUTHOR("Florian Pose "); fp@512: MODULE_DESCRIPTION("EtherCAT minimal test environment"); fp@220: fp@220: module_init(init_mini_module); fp@220: module_exit(cleanup_mini_module); fp@220: fp@220: /*****************************************************************************/