uavcan_add_slcan 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #!/bin/bash
  2. #
  3. # Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@zubax.com>
  4. #
  5. HELP="Register slcan-enabled Serial-to-CAN adapters as network interfaces.
  6. Usage:
  7. `basename $0` [options] <tty0> [[options] <tty1> ...]
  8. Interface indexes will be assigned automatically in ascending order, i.e.
  9. first device will be mapped to the interface slcan0, second will be mapped to
  10. slcan1, and so on. Each added option affects only the interfaces that follow
  11. it, which means that options must be properly ordered (see examples below).
  12. This tool requires superuser priveleges.
  13. The package 'can-utils' must be installed. On Debian/Ubuntu-based systems it
  14. can be installed via APT: apt-get install can-utils
  15. Options:
  16. --speed-code <X> (where X is a number in range [0, 8]; default: 8)
  17. -s<X>
  18. Set CAN speed to:
  19. 0 - 10 Kbps
  20. 1 - 20 Kbps
  21. 2 - 50 Kbps
  22. 3 - 100 Kbps
  23. 4 - 125 Kbps (UAVCAN recommended)
  24. 5 - 250 Kbps (UAVCAN recommended)
  25. 6 - 500 Kbps (UAVCAN recommended)
  26. 7 - 800 Kbps
  27. 8 - 1 Mbps (UAVCAN recommended, default)
  28. --remove-all
  29. -r
  30. Remove all SLCAN interfaces.
  31. If this option is used, it MUST be provided FIRST, otherwise it
  32. will remove the interfaces added earlier.
  33. --basename <X> (where X is a string containing [a-z], default: slcan)
  34. -b<X>
  35. Base name to use for the interfaces that follow this option.
  36. Default value is 'slcan'. This option can be provided multiple times,
  37. it will only affect the interfaces that were provided after it. If you
  38. want to affect all added interfaces, provide this option first (see
  39. examples below).
  40. --baudrate <X> (where X is an integer, default: 921600)
  41. -S<X>
  42. Configure baud rate to use on the interface.
  43. This option is mostly irrelevant for USB to CAN adapters.
  44. Example 1:
  45. `basename $0` --remove-all /dev/ttyUSB3 --basename can --baudrate 115200 \\
  46. /dev/ttyUSB0 --speed-code 4 /dev/ttyACM0
  47. The example above initializes the interfaces as follows:
  48. /dev/ttyUSB3 --> slcan0 1 Mbps baudrate 921600
  49. /dev/ttyUSB0 --> can0 1 Mbps baudrate 115200
  50. /dev/ttyACM0 --> can1 125 kbps baudrate 115200
  51. Example 2:
  52. `basename $0` --remove-all
  53. The example above only removes all SLCAN interfaces without adding new ones."
  54. function die() { echo $@ >&2; exit 1; }
  55. if [ "$1" == '--help' ] || [ "$1" == '-h' ]; then echo "$HELP"; exit; fi
  56. [ -n "$1" ] || die "Invalid usage. Use --help to get help."
  57. [ "$(id -u)" == "0" ] || die "Must be root."
  58. which slcan_attach > /dev/null || die "Please install can-utils first."
  59. # ---------------------------------------------------------
  60. function deinitialize() {
  61. echo "Stopping slcand..." >&2
  62. # Trying SIGINT first
  63. killall -INT slcand &> /dev/null
  64. sleep 0.3
  65. # Then trying the default signal, which is SIGTERM, if SIGINT didn't help
  66. slcand_kill_retries=10
  67. while killall slcand &> /dev/null
  68. do
  69. (( slcand_kill_retries -= 1 ))
  70. [[ "$slcand_kill_retries" > 0 ]] || die "Failed to stop slcand"
  71. sleep 1
  72. done
  73. }
  74. function handle_tty() {
  75. tty=$(readlink -f $1)
  76. tty=${tty/'/dev/'}
  77. iface_index=0
  78. while ifconfig "$IFACE_BASENAME$iface_index" &> /dev/null
  79. do
  80. iface_index=$((iface_index + 1))
  81. done
  82. slcan_iface_index=0
  83. while ifconfig "slcan$slcan_iface_index" &> /dev/null
  84. do
  85. slcan_iface_index=$((slcan_iface_index + 1))
  86. done
  87. iface="$IFACE_BASENAME$iface_index"
  88. slcan_iface="slcan$slcan_iface_index"
  89. echo "Attaching $tty to $iface speed code $SPEED_CODE baudrate $BAUDRATE" >&2
  90. # Configuring the baudrate
  91. stty -F /dev/$tty ispeed $BAUDRATE ospeed $BAUDRATE || return 1
  92. # Attaching the line discipline. Note that slcan_attach has option -n but it doesn't work.
  93. slcan_attach -f -o -s$SPEED_CODE /dev/$tty > /dev/null || return 2
  94. slcand $tty || return 3
  95. sleep 1 # FIXME
  96. # ...therefore we need to rename the interface manually
  97. ip link set $slcan_iface name $iface
  98. ifconfig $iface up || return 4
  99. }
  100. IFACE_BASENAME='slcan'
  101. SPEED_CODE=8
  102. BAUDRATE=921600
  103. next_option=''
  104. while [ -n "$1" ]; do
  105. case $1 in
  106. -r | --remove-all)
  107. deinitialize
  108. ;;
  109. -b*)
  110. IFACE_BASENAME=${1:2}
  111. ;;
  112. -S*)
  113. BAUDRATE=${1:2}
  114. ;;
  115. -s[0-8])
  116. SPEED_CODE=${1:2}
  117. ;;
  118. --*)
  119. next_option=${1:2}
  120. ;;
  121. -*)
  122. die "Invalid option: $1"
  123. ;;
  124. *)
  125. if [ "$next_option" = 'basename' ]; then IFACE_BASENAME=$1
  126. elif [ "$next_option" = 'speed-code' ]; then SPEED_CODE=$1
  127. elif [ "$next_option" = 'baudrate' ]; then BAUDRATE=$1
  128. elif [ "$next_option" = '' ]
  129. then
  130. handle_tty $1 || die "Failed to configure the interface $1"
  131. else
  132. die "Invalid option '$next_option'"
  133. fi
  134. next_option=''
  135. ;;
  136. esac
  137. shift
  138. done
  139. [ "$next_option" = '' ] || die "Expected argument for option '$next_option'"