back to index

chip doc - USB interfaces


USB-serial
      general
            UART vs RS232
            baud rates
                  common specials
            chip connections
            "in-house standard" interface
                  Slave Collar
            automatic device symlink assignment
      CH340
                  lsusb -vvv
      PL2303
      CP2102
                  lsusb -vvv
            config software
            CP2104
      FT232R
                  lsusb -vvv
            config software
            other chips
                  FT230XQ
                  FT231X
      HT42B534
            config software
            other chips from the family
      CY7C65213
      others
      not-just-UART
            FT200XD, USB-I2C
            FT220X, USB-SPI
            FT2232HL
            CH341
            FT600/601, USB3 FIFO

Summary

software setting
      tty by path
            Raspberry Pi v3 ports
            udevadm rule/script for friendly path names
      udevadm
            udevadm monitor -p for connecting a CP2102
            same with udevadm info
            environment in script invoked from rules
            udevadm rules

USB-serial


general

UART vs RS232

baud rates

The baudrates are derived from the chip's internal clock (usually 12, 48 or 96 MHz) by setting up the divider registers.

Some chips support only a defined set of baud rates and won't operate on anything else.

Others (eg. CP2102) have rewritable table of supported baudrates and associated dividers.

Yet others (eg. FT232R) support arbitrary baudrates out of the box.

common specials

chip connections

"in-house standard" interface

Pinout:

  USB-serial   Ardu   ESP
        male   female female
         RTS          RESET         pin added; 
         DTR   RESET  GPIO0         programming selector for ESP32/ESP8266, pulled H for normal boot, L for prog; to RESET via capacitor on arduinos
         Rx    Tx     Tx
         Tx    Rx     Rx
         +5V   +5V    +5V(to-3.3v)  some boards need 3.3v stabilizer; may be disconnected for internally powered devices, or via diode
         GND   GND    GND
       +3.3V                        pin removed, sometimes used separately with pigtail

WARN: on linux, DTR is ALWAYS pulsed on port open (kernel driver issue). One would think after such time they'd put in an IOCTL to disable this if needed. On port open, standard arduino will reset.

Moving reset pin from DTR to better controllable RTS may be helpful here. Modifying the reset tool to pulse both DTR and RTS may help. Customizing the reset circuitry with bigger series cap and smaller cap to the ground on the arduino side may tune the reset circuit to require long enough DTR pulses to make it insensitive to situations when port is open and DTR is then immediately commanded to unset.

Slave Collar

adapter between Tasmota ESP8266/ESP32 devices and Arduinos

Pinout:

    Arduino              ESPxxxx
      n/c                 RESET     reset for ESP, not connected
    RESET --------------- GPIO0     GPIO0 used as ArduSlave reset
       Tx ---R1k----\/--- Tx        ESP Tx connected via 1k resistor to Ardu Rx (can be direct, resistor to protect ESP in case slave rebels and puts 5V high on its Rx pin; must be H at ESP boot or ESP won't start)
       Rx ---R1k----/\*-- Rx        ESP Rx connected via resistor divider to Ardu Tx (to convert 5v to 3.3v; can use a zener instead)
      +5V ------------|-- +5V       5V power bus; may be powered from either side or from a side connector
      GND ----*-------|-- GND       GND, what else to say
              \--R2k2-

automatic device symlink assignment


CH340

flavors:

           package  xtal      eeprom     temperature
   CH340B  SOP-16   internal  built-in   -20..+70    reset output, reset input, Tx-in-progress output (pin 15)
   CH340C  SOP-16   internal             -20..+70    second most common
   CH340E  MSOP-10  internal             -20..+70    no DCD,RI,DSR,DTR; Tx-in-progress output (pin 6)
   CH340G  SOP-16   external  n/a        -40..+85    most common "in the wild"
   CH340R  SSOP-20  external             -40..+85    USB-config-complete output, forbid-device-suspend input;for infrared/IrDA, reverse polarity Tx and modem signals; selectable InfraredSIR/commonUART by pin
   CH340N  SOIC-8   internal                         only Rx,Tx,RTS; relabeled CH330N? datasheet
   CH340T  SSOP-20  external             -40..+85    USB-config-complete output, forbid-device-suspend input, Tx-in-progress output (pin 17)

NOT CONFIGURABLE PRODUCT STRING! Cannot differentiate between devices by /dev/serial/by-id!!! (except variant B which is very uncommon)

lsusb -vvv

lsusb-ch340.txt


PL2303


CP2102

Can differentiate between devices by /dev/serial/by-id, can use product-ID in automatic udev rules, can define arbitrary baudrates albeit with some leg work.

lsusb -vvv

lsusb-cp2102.txt

config software

cp210x-program

example output:

[usb device]
product_string = CP2102 Arduino USB-serial interface
serial_number = 0001
vendor_id = 10C4
product_id = EA60
version = 1.00
bus_powered = no
max_power = 100
locked = no
part_number = 2
vendor_string = Silicon Labs

[baudrate table]
1500000 = FFF0, FFFA, 1 # 1500000 Baud, 12 us
1500000 = FFF0, FFFA, 1 # 1500000 Baud, 12 us
1200000 = FFEC, FFF8, 1 # 1200000 Baud, 16 us
 921600 = FFE6, FFF6, 1 #  923077 Baud, 20 us
 576000 = FFD6, FFF0, 1 #  571429 Baud, 32 us
 500000 = FFD0, FFEE, 1 #  500000 Baud, 36 us
 460800 = FFCC, FFEC, 1 #  461538 Baud, 40 us
 256000 = FFA2, FFDC, 1 #  255319 Baud, 72 us
 250000 = FFA0, FFDC, 1 #  250000 Baud, 72 us
 230400 = FF98, FFD9, 1 #  230769 Baud, 78 us
 153600 = FF64, FFC5, 1 #  153846 Baud, 118 us
 128000 = FF44, FFB9, 1 #  127660 Baud, 142 us
 115200 = FF30, FFB2, 1 #  115385 Baud, 156 us
  76800 = FEC8, FF8B, 1 #   76923 Baud, 234 us
  64000 = FE89, FF73, 1 #   64000 Baud, 282 us
  57600 = FE5F, FF63, 1 #   57554 Baud, 314 us
  56000 = FE53, FF5F, 1 #   55944 Baud, 322 us
  51200 = FE2B, FF50, 1 #   51173 Baud, 352 us
  38400 = FD8F, FF15, 1 #   38400 Baud, 470 us
  28800 = FCBF, FEC7, 1 #   28812 Baud, 626 us
  19200 = FB1E, FE2B, 1 #   19200 Baud, 938 us
  16000 = FA24, FE0C, 1 #   16000 Baud, 1.000 ms
  14400 = F97D, FE0C, 1 #   14397 Baud, 1.000 ms
   9600 = F63C, FE0C, 1 #    9600 Baud, 1.000 ms
   7200 = F2FB, FE0C, 1 #    7201 Baud, 1.000 ms
   4800 = EC78, FE0C, 1 #    4800 Baud, 1.000 ms
   4000 = E890, FE0C, 1 #    4000 Baud, 1.000 ms
   2400 = D8F0, FE0C, 1 #    2400 Baud, 1.000 ms
   1800 = CBEB, FE0C, 1 #    1800 Baud, 1.000 ms
   1200 = B1E0, FE0C, 1 #    1200 Baud, 1.000 ms
    600 = 63C0, FE0C, 1 #     600 Baud, 1.000 ms
    300 = B1E0, FE0C, 4 #     300 Baud, 1.000 ms

CP2104


FT232R

Can differentiate between devices by /dev/serial/by-id, can use product-ID in automatic udev rules, can use arbitrary baudrates.

lsusb -vvv

lsusb-ft232rl.txt

config software

ftdi-eeprom

other chips

FT has a whole family of chips. FT232/245B and R for standard speeds, FT2232D for standard speed two-channel, FT232H for high speed, 2232H for high speed dual and 4232H for quad. The newer FT-X subfamily has many options differing in size, pin number, purpose... from full and basic UART to 8bit and 4bit SPI, I2C, and 8bit FIFO.

FT230XQ

FT231X


HT42B534

No TX-in-progress output. Configurable product string.

config software

other chips from the family


CY7C65213


others


not-just-UART

FT200XD, USB-I2C

FT220X, USB-SPI

FT2232HL

CH341

FT600/601, USB3 FIFO


Summary


software setting


tty by path

discriminate between devices by their path, derived from the physical connector they are plugged into, as of /dev/serial/by-path/

examples:

ls -l /dev/serial/by-path/
lrwxrwxrwx 1 root root 13 Nov 16 23:57 platform-3f980000.usb-usb-0:1.2:1.0-port0 -> ../../ttyUSB0
lrwxrwxrwx 1 root root 13 Nov 20 23:22 platform-3f980000.usb-usb-0:1.5.6.1:1.0-port0 -> ../../ttyUSB1

lsusb -t
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/5p, 480M
|__ Port 1: Dev 3, If 0, Class=Vendor Specific Class, Driver=smsc95xx, 480M
|__ Port 2: Dev 26, If 0, Class=Vendor Specific Class, Driver=cp210x, 12M
|__ Port 3: Dev 66, If 0, Class=Mass Storage, Driver=usb-storage, 480M
|__ Port 5: Dev 28, If 0, Class=Hub, Driver=hub/7p, 480M
|__ Port 1: Dev 68, If 0, Class=(Defined at Interface level), Driver=, 1.5M
|__ Port 4: Dev 38, If 0, Class=Human Interface Device, Driver=usbhid, 12M
|__ Port 6: Dev 69, If 0, Class=Hub, Driver=hub/4p, 480M
|__ Port 1: Dev 70, If 0, Class=Vendor Specific Class, Driver=cp210x, 12M

physically labeling the ports with numbers is helpful for such configurations

should be possible to write udev rule that creates /dev/ttyUSB_x.y.z port from physical port, may need a RUN or PROGRAM command in the rule

Raspberry Pi v3 ports

    ----------    ---------    ---------
   |          |  |  USB 2  |  |  USB 4  |
   | ETHERNET |  | ------- |  | ------- |
   |          |  |  USB 3  |  |  USB 5  |
  ========================================

port 1 == internal ethernet card, SMSC95xx

udevadm rule/script for friendly path names

in /etc/udev/rules/99-usb.rules (or whatever):

ACTION=="add", SUBSYSTEM=="tty", SUBSYSTEMS=="usb" PROGRAM="/usr/bin/usbserial-getdevpath.sh %k" SYMLINK+="%c"

in /usr/bin/usbserial-getdevpath.sh:

#!/bin/bash
x=`echo "$ID_PATH"|cut -d ':' -f 2`
if [ "${x:0:2}" == "1." ]; then x=${x:2}; else exit 1; fi
echo "ttyUSB.$x"

On raspberry pi the USB devices always start with platform-3f980000.usb-usb-0:1. so we can afford to just throw out the part before first colon and then throw out the first two characters that are always 1..

The part after the second colon is specific to the device itself. Multiport devices like FT2232 will fail here and will require the script to be amended. (TODO.)


udevadm

udevadm monitor -p for connecting a CP2102

KERNEL[2246689.154895] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3 (usb)
ACTION=add
BUSNUM=001
DEVNAME=/dev/bus/usb/001/043
DEVNUM=043
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3
DEVTYPE=usb_device
MAJOR=189
MINOR=42
PRODUCT=10c4/ea60/100
SEQNUM=1690
SUBSYSTEM=usb
TYPE=0/0/0

KERNEL[2246689.170447] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0 (usb)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0
DEVTYPE=usb_interface
INTERFACE=255/0/0
MODALIAS=usb:v10C4pEA60d0100dc00dsc00dp00icFFisc00ip00in00
PRODUCT=10c4/ea60/100
SEQNUM=1691
SUBSYSTEM=usb
TYPE=0/0/0

KERNEL[2246689.173837] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0/ttyUSB1 (usb-serial)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0/ttyUSB1
SEQNUM=1692
SUBSYSTEM=usb-serial

KERNEL[2246689.191081] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0/ttyUSB1/tty/ttyUSB1 (tty)
ACTION=add
DEVNAME=/dev/ttyUSB1
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0/ttyUSB1/tty/ttyUSB1
MAJOR=188
MINOR=1
SEQNUM=1693
SUBSYSTEM=tty

UDEV  [2246689.346077] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3 (usb)
ACTION=add
BUSNUM=001
DEVNAME=/dev/bus/usb/001/043
DEVNUM=043
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3
DEVTYPE=usb_device
ID_BUS=usb
ID_MODEL=CP2102_Arduino_USB-serial_interface
ID_MODEL_ENC=CP2102\x20Arduino\x20USB-serial\x20interface
ID_MODEL_FROM_DATABASE=CP210x UART Bridge / myAVR mySmartUSB light
ID_MODEL_ID=ea60
ID_REVISION=0100
ID_SERIAL=Silicon_Labs_CP2102_Arduino_USB-serial_interface_0001
ID_SERIAL_SHORT=0001
ID_USB_INTERFACES=:ff0000:
ID_VENDOR=Silicon_Labs
ID_VENDOR_ENC=Silicon\x20Labs
ID_VENDOR_FROM_DATABASE=Cygnal Integrated Products, Inc.
ID_VENDOR_ID=10c4
MAJOR=189
MINOR=42
PRODUCT=10c4/ea60/100
SEQNUM=1690
SUBSYSTEM=usb
TYPE=0/0/0
USEC_INITIALIZED=2246689345478

UDEV  [2246689.454330] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0 (usb)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0
DEVTYPE=usb_interface
ID_MODEL_FROM_DATABASE=CP210x UART Bridge / myAVR mySmartUSB light
ID_VENDOR_FROM_DATABASE=Cygnal Integrated Products, Inc.
INTERFACE=255/0/0
MODALIAS=usb:v10C4pEA60d0100dc00dsc00dp00icFFisc00ip00in00
PRODUCT=10c4/ea60/100
SEQNUM=1691
SUBSYSTEM=usb
TYPE=0/0/0
USEC_INITIALIZED=2246689453644

UDEV  [2246689.457449] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0/ttyUSB1 (usb-serial)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0/ttyUSB1
SEQNUM=1692
SUBSYSTEM=usb-serial
USEC_INITIALIZED=2246689457261

UDEV  [2246689.470734] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0/ttyUSB1/tty/ttyUSB1 (tty)
ID_PORT=0
ACTION=add DEVLINKS=/dev/serial/by-id/usb-Silicon_Labs_CP2102_Arduino_USB-serial_interface_0001-if00-port0 /dev/serial/by-path/platform-3f980000.usb-usb-0:1.3:1.0-port0 /dev/ttyArdu DEVNAME=/dev/ttyUSB1 DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0/ttyUSB1/tty/ttyUSB1 ID_BUS=usb ID_MODEL=CP2102_Arduino_USB-serial_interface ID_MODEL_ENC=CP2102\x20Arduino\x20USB-serial\x20interface ID_MODEL_FROM_DATABASE=CP210x UART Bridge / myAVR mySmartUSB light ID_MODEL_ID=ea60 ID_PATH=platform-3f980000.usb-usb-0:1.3:1.0 ID_PATH_TAG=platform-3f980000_usb-usb-0_1_3_1_0 ID_REVISION=0100 ID_SERIAL=Silicon_Labs_CP2102_Arduino_USB-serial_interface_0001 ID_SERIAL_SHORT=0001 ID_TYPE=generic ID_USB_DRIVER=cp210x ID_USB_INTERFACES=:ff0000: ID_USB_INTERFACE_NUM=00 ID_VENDOR=Silicon_Labs ID_VENDOR_ENC=Silicon\x20Labs ID_VENDOR_FROM_DATABASE=Cygnal Integrated Products, Inc. ID_VENDOR_ID=10c4 MAJOR=188 MINOR=1 SEQNUM=1693 SUBSYSTEM=tty TAGS=:systemd: USEC_INITIALIZED=2246689470110

same with udevadm info

get sys path from dev name:

udevadm info -q path -n /dev/ttyUSB1
/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0/ttyUSB1/tty/ttyUSB1

udevadm info -a -p `udevadm info -q path -n /dev/ttyUSB1`

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0/ttyUSB1/tty/ttyUSB1':
    KERNEL=="ttyUSB1"
    SUBSYSTEM=="tty"
    DRIVER==""

  looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0/ttyUSB1':
    KERNELS=="ttyUSB1"
    SUBSYSTEMS=="usb-serial"
    DRIVERS=="cp210x"
    ATTRS{port_number}=="0"

  looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0':
    KERNELS=="1-1.3:1.0"
    SUBSYSTEMS=="usb"
    DRIVERS=="cp210x"
    ATTRS{authorized}=="1"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bInterfaceClass}=="ff"
    ATTRS{bInterfaceNumber}=="00"
    ATTRS{bInterfaceProtocol}=="00"
    ATTRS{bInterfaceSubClass}=="00"
    ATTRS{bNumEndpoints}=="02"
    ATTRS{interface}=="CP2102 Arduino USB-serial interface"
    ATTRS{supports_autosuspend}=="1"

  looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3':
    KERNELS=="1-1.3"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{authorized}=="1"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bDeviceClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{bMaxPower}=="100mA"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bcdDevice}=="0100"
    ATTRS{bmAttributes}=="80"
    ATTRS{busnum}=="1"
    ATTRS{configuration}==""
    ATTRS{devnum}=="43"
    ATTRS{devpath}=="1.3"
    ATTRS{devspec}=="  (null)"
    ATTRS{idProduct}=="ea60"
    ATTRS{idVendor}=="10c4"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="Silicon Labs"
    ATTRS{maxchild}=="0"
    ATTRS{product}=="CP2102 Arduino USB-serial interface"
    ATTRS{quirks}=="0x0"
    ATTRS{removable}=="removable"
    ATTRS{serial}=="0001"
    ATTRS{speed}=="12"
    ATTRS{urbnum}=="16"
    ATTRS{version}==" 1.10"
...here it stops being so interesting, this is the hub and the controller above, no more the device we play with...

environment in script invoked from rules

ACTION='add'
DEVLINKS='/dev/serial/by-path/platform-3f980000.usb-usb-0:1.5.6.1:1.0-port0 /dev/ttyArdu /dev/serial/by-id/usb-Silicon_Labs_CP2102_Arduino_USB-serial_interface_0001-if00-port0'
DEVNAME='/dev/ttyUSB1'
DEVPATH='/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.5/1-1.5.6/1-1.5.6.1/1-1.5.6.1:1.0/ttyUSB1/tty/ttyUSB1'
ID_BUS='usb'
ID_MODEL='CP2102_Arduino_USB-serial_interface'
ID_MODEL_ENC='CP2102\x20Arduino\x20USB-serial\x20interface'
ID_MODEL_FROM_DATABASE='CP210x UART Bridge / myAVR mySmartUSB light'
ID_MODEL_ID='ea60'
ID_PATH='platform-3f980000.usb-usb-0:1.5.6.1:1.0'
ID_PATH_TAG='platform-3f980000_usb-usb-0_1_5_6_1_1_0'
ID_REVISION='0100'
ID_SERIAL='Silicon_Labs_CP2102_Arduino_USB-serial_interface_0001'
ID_SERIAL_SHORT='0001'
ID_TYPE='generic'
ID_USB_DRIVER='cp210x'
ID_USB_INTERFACES=':ff0000:'
ID_USB_INTERFACE_NUM='00'
ID_VENDOR='Silicon_Labs'
ID_VENDOR_ENC='Silicon\x20Labs'
ID_VENDOR_FROM_DATABASE='Cygnal Integrated Products, Inc.'
ID_VENDOR_ID='10c4'
IFS='
'
MAJOR='188'
MINOR='1'
OPTIND='1'
PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
PPID='31637'
PS1='# '
PS2='> '
PS4='+ '
PWD='/'
SEQNUM='2063'
SUBSYSTEM='tty'
USEC_INITIALIZED='2306412822524'

invoked via /bin/sh; /bin/bash adds a lot of other variables of its own, irrelevant to udev system

udevadm rules

[ref]

here, first the subsystem "tty" and product ID from device upstream sysfs attributes (ATTRS{key}, crawl up until first key match) are matched, then the SYMLINK command is executed

 # arduino interface, /dev/ttyArdu
 # udevadm properties dump above
 SUBSYSTEM=="tty" ATTRS{product}=="CP2102 Arduino USB-serial interface" SYMLINK+="ttyArdu"

 # NFC toy, /dev/ttyNFC
 SUBSYSTEM=="tty" ATTRS{product}=="CP2102 PN532 NFC" SYMLINK+="ttyNFC"

 # Marlin, /dev/ttyMarlin
 # arduino board for 3d printer (name contains attached hardware speed/setting, mode set to allow access to all)
 SUBSYSTEM=="tty" ATTRS{product}=="CP2102 Marlin 250000n8" SYMLINK+="ttyMarlin" MODE:="0666"

 # webcam auto-stream rules
 ACTION=="add", KERNEL=="video[0-9]*" SYMLINK+="webcam%n" ENV{DEVNUM}="%n" TAG+="systemd" ENV{SYSTEMD_WANTS}="webcam@%n.service"
 ACTION=="remove", KERNEL=="video[0-9]*" RUN+="/home/pi/scripts/webcam_server_kill.sh %n"


 # do not forget to reload!
 # udevadm control --reload-rules

webcam systemd start script, %i is the device number passed above via %n, taken by the script as $1; example to add such services to rule-matching serial ports

 # belongs to /etc/systemd/system/webcam@.service
 # called from /etc/udev/rules/webcams.rules
 #
 # do not forget to run systemctl daemon-reload
 [Unit]
 Description=webcam server on /dev/video%i
 [Service]
 User=pi
 Type=forking
 RemainAfterExit=yes
 ExecStart=/home/pi/scripts/webcam_server.sh %i
 ExecStop=/home/pi/scripts/webcam_server_kill.sh %i
 #ExecReload=/home/pi/scripts/webcam_server.sh %i
 [Install]
 WantedBy=multi-user.target


If you have any comments or questions about the topic, please let me know here:
Your name:
Your email:
Spambait
Leave this empty!
Only spambots enter stuff here.
Feedback: