Files
EtherCAT/ethercatctl.new
T

213 lines
7.3 KiB
Bash
Executable File

#!/bin/bash
# AD82: modified ethercatctl script:
# replace ethernet drivers with ec_* dedicated ec drivers for selected interfaces only
# Load EtherCAT configuration
ETHERCAT_CONFIG="/etc/ethercat.conf"
if [ -f "$ETHERCAT_CONFIG" ]; then
. "$ETHERCAT_CONFIG"
fi
# Define commands matching standard EtherLab scripts+apps
ETHERCAT=/opt/etherlab/bin/ethercat
MODPROBE="/sbin/modprobe"
MODINFO="/sbin/modinfo"
MODPROBE_FLAGS=""
IP=/usr/sbin/ip
# -------------------------------------------------------------------------
# Dynamic Parsing of MASTERn_DEVICE and MASTERn_BACKUP
# -------------------------------------------------------------------------
DEVICES=""
BACKUPS=""
# Loop through and build comma-separated lists of MAC addresses
for var in $(compgen -v | grep '^MASTER[0-9]\+_DEVICE'); do
mac=$(eval echo "\$$var" | tr 'A-Z' 'a-z')
if [ -n "$mac" ] && [ "$mac" != "none" ]; then
if [ -z "${DEVICES}" ]; then DEVICES="$mac"; else DEVICES="${DEVICES},$mac"; fi
fi
done
for var in $(compgen -v | grep '^MASTER[0-9]\+_BACKUP'); do
mac=$(eval echo "\$$var" | tr 'A-Z' 'a-z')
if [ -n "$mac" ] && [ "$mac" != "none" ]; then
if [ -z "${BACKUPS}" ]; then BACKUPS="$mac"; else BACKUPS="${BACKUPS},$mac"; fi
fi
done
# Create a space-separated list for our bash regex matching later
TARGET_MACS=$(echo "${DEVICES} ${BACKUPS}" | tr ',' ' ')
start_devices() {
# Check if we actually have devices configured
if [ -z "${DEVICES}" ]; then
echo "[Fatal] No MASTERn_DEVICE MAC addresses found in config. Aborting."
exit 1
fi
# 1. Bring up standard interfaces first (needed in case we DO fall back to generic)
for iface in ${LINK_DEVICES}; do
echo " Bringing up interface: ${IP} link set ${iface} up"
${IP} link set "${iface}" up 2>/dev/null
done
# 2. Load the core master module
echo "Loading EtherCAT master core module with configured MACs..."
if ! ${MODPROBE} ${MODPROBE_FLAGS} ec_master \
main_devices="${DEVICES}" backup_devices="${BACKUPS}"; then
echo "[Fatal] Failed to load ec_master core module. Aborting."
exit 1
fi
# 3. Target and SWAP PCI drivers BEFORE loading ec_* modules
echo "Starting targeted EtherCAT device binding..."
for iface in /sys/class/net/*; do
[ -e "$iface" ] || continue
ifname=$(basename "$iface")
[ "$ifname" = "lo" ] && continue
if [ -f "$iface/address" ]; then
iface_mac=$(cat "$iface/address" | tr 'A-Z' 'a-z')
else
continue
fi
# Check if this interface MAC is one of our targets (Main or Backup)
if [[ $TARGET_MACS =~ $iface_mac ]]; then
if [ -e "$iface/device" ]; then
pci_bus_id=$(basename $(readlink "$iface/device"))
if [[ "$pci_bus_id" =~ ^[0-9a-fA-F]{4}: ]]; then
current_driver=$(basename $(readlink "$iface/device/driver") 2>/dev/null)
if [ -n "$current_driver" ]; then
# If the driver matches a hardware module we have optimized drivers for:
if [[ " $DEVICE_MODULES " =~ " $current_driver " ]]; then
target_driver="ec_$current_driver"
# but do nothing if selected ec_ driver is not installed
/sbin/modinfo ${target_driver} >/dev/null 2>/dev/null || continue
echo "Matching optimized interface: $ifname ($iface_mac) -> Target: '$target_driver'"
echo " Unbinding $pci_bus_id from $current_driver..."
echo -n "$pci_bus_id" > "/sys/bus/pci/drivers/$current_driver/unbind" 2>/dev/null
sleep 0.2
# Note: Binding might fail here if the module isn't loaded yet,
# but loading the module next will auto-probe and grab it.
if [ -d "/sys/bus/pci/drivers/$target_driver" ]; then
echo " Binding $pci_bus_id to $target_driver..."
echo -n "$pci_bus_id" > "/sys/bus/pci/drivers/$target_driver/bind" 2>/dev/null
fi
else
echo "Interface $ifname ($iface_mac) matches config but uses standard driver '$current_driver'. Leaving for ec_generic."
fi
fi
fi
fi
fi
done
# 4. Load optimized modules first, generic absolute last!
echo "Loading configured EtherCAT device modules..."
# Sort modules so 'generic' always goes to the end of the line
SORTED_MODULES=$(echo "$DEVICE_MODULES" | awk '{for(i=1;i<=NF;i++) if($i!="generic") print $i; print "generic"}')
for mod in $SORTED_MODULES; do
[ -z "$mod" ] && continue
echo " Loading ec_$mod..."
${MODPROBE} ${MODPROBE_FLAGS} "ec_$mod" 2>/dev/null || echo " [Warning] Failed to modprobe ec_$mod"
sleep 0.1
done
}
stop_devices() {
echo "Stopping EtherCAT device binding (restoring standard drivers)..."
# Unbind PCI devices first while drivers are still loaded
for mod in $DEVICE_MODULES; do
target_driver="ec_$mod"
if [ -d "/sys/bus/pci/drivers/$target_driver" ]; then
for pci_dev in /sys/bus/pci/drivers/$target_driver/[0-9a-fA-F]*; do
[ -e "$pci_dev" ] || continue
pci_bus_id=$(basename "$pci_dev")
if [ "$pci_bus_id" != "bind" ]
then
echo "Unbinding $pci_bus_id from $target_driver..."
echo -n "$pci_bus_id" > "/sys/bus/pci/drivers/$target_driver/unbind" 2>/dev/null
echo "Binding $pci_bus_id to ${target_driver#ec_}..."
echo -n "$pci_bus_id" > "/sys/bus/pci/drivers/${target_driver#ec_}/bind" 2>/dev/null
fi
done
fi
done
# Force PCI bus rescan so standard modules claim their hardware back
echo "Triggering PCI bus rescan..."
echo 1 > "/sys/bus/pci/rescan"
sleep 0.5
echo "Unloading EtherCAT device modules..."
for mod in $DEVICE_MODULES; do
echo " Unloading ec_$mod..."
rmmod "ec_$mod" 2>/dev/null
done
echo "Unloading EtherCAT master core module..."
rmmod ec_master 2>/dev/null
}
status_devices() {
echo "Checking for EtherCAT master 1.6.3 status "
# count masters in configuration file
MASTER_COUNT=0
while true; do
DEVICE=$(eval echo "\${MASTER${MASTER_COUNT}_DEVICE}")
if [ -z "${DEVICE}" ]; then break; fi
MASTER_COUNT=$((${MASTER_COUNT} + 1))
done
RESULT=0
for i in $(seq 0 "$((${MASTER_COUNT} - 1))"); do
echo -n " Master${i} "
# Check if the master is in idle or operation phase
${ETHERCAT} master --master "${i}" 2>/dev/null | \
grep -qE 'Phase:[[:space:]]*Idle|Phase:[[:space:]]*Operation'
EXITCODE=$?
if [ ${EXITCODE} -eq 0 ]; then
echo " running"
else
echo " dead"
RESULT=1
fi
done
}
case "$1" in
start)
start_devices
;;
stop)
stop_devices
;;
status)
status_devices
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
;;
esac