|
|
|
@@ -62,30 +62,28 @@ To find out which version of sinqMotor is needed by a driver, refer to its Makef
|
|
|
|
|
|
|
|
|
|
|
|
### IOC startup script
|
|
|
|
### IOC startup script
|
|
|
|
|
|
|
|
|
|
|
|
An EPICS IOC for motor control at SINQ is started by executing a script with the IOC shell. In its simplest form, an IOC for two controllers is a file looking like this:
|
|
|
|
An EPICS IOC for motor control at SINQ is started by executing a script with the IOC shell. In its simplest form, an IOC for two controllers run by "exampleDriver" is a file looking like this:
|
|
|
|
```
|
|
|
|
```
|
|
|
|
#!/usr/local/bin/iocsh
|
|
|
|
#!/usr/local/bin/iocsh
|
|
|
|
|
|
|
|
|
|
|
|
# Load libraries needed for the IOC
|
|
|
|
# Load libraries needed for the IOC
|
|
|
|
require sinqMotor, 1.0.0
|
|
|
|
require exampleDriver, 1.0.0
|
|
|
|
require actualDriver, 1.2.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Define environment variables used later to parametrize the individual controllers
|
|
|
|
# Define environment variables used later to parametrize the individual controllers
|
|
|
|
epicsEnvSet("TOP","/ioc/sinq-ioc/sinqtest-ioc/")
|
|
|
|
epicsEnvSet("TOP","/ioc/sinq-ioc/sinqtest-ioc/")
|
|
|
|
epicsEnvSet("INSTR","SQ:SINQTEST:")
|
|
|
|
epicsEnvSet("INSTR","SQ:SINQTEST:")
|
|
|
|
|
|
|
|
|
|
|
|
# Include other scripts for the controllers 1 and 2
|
|
|
|
# Include other scripts for the controllers 1 and 2
|
|
|
|
< actualDriver.cmd
|
|
|
|
< exampleDriver1.cmd
|
|
|
|
< actualDriver.cmd
|
|
|
|
< exampleDriver2.cmd
|
|
|
|
|
|
|
|
|
|
|
|
iocInit()
|
|
|
|
iocInit()
|
|
|
|
```
|
|
|
|
```
|
|
|
|
The first line is a so-called shebang which instructs Linux to execute the file with the executable located at the given path - the IOC shell in this case. The controller script "mcu1.cmd" looks like this:
|
|
|
|
The first line is a so-called shebang which instructs Linux to execute the file with the executable located at the given path - the IOC shell in this case. The files `exampleDriver1.cmd` or `exampleDriver2` then look like this:
|
|
|
|
The script for controller 1 ("turboPmac1.cmd") for a Turbo PMAC (see https://git.psi.ch/sinq-epics-modules/turboPmac) has the following structure. The scripts for other controller types can be found in the README.md of their respective repositories.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
```
|
|
|
|
# Define the name of the controller and the corresponding port
|
|
|
|
# Define the name of the controller and the corresponding port
|
|
|
|
epicsEnvSet("DRIVER_PORT","actualDriver1")
|
|
|
|
epicsEnvSet("DRIVER_PORT","exampleDriver1")
|
|
|
|
epicsEnvSet("IP_PORT","p$(DRIVER_PORT)")
|
|
|
|
epicsEnvSet("IP_PORT","p$(DRIVER_PORT)")
|
|
|
|
|
|
|
|
|
|
|
|
# Create the TCP/IP socket used to talk with the controller. The socket can be adressed from within the IOC shell via the port name
|
|
|
|
# Create the TCP/IP socket used to talk with the controller. The socket can be adressed from within the IOC shell via the port name
|
|
|
|
@@ -116,17 +114,17 @@ setForcedFastPolls("$(DRIVER_PORT)", 10);
|
|
|
|
setThresholdComTimeout("$(DRIVER_PORT)", 300, 10);
|
|
|
|
setThresholdComTimeout("$(DRIVER_PORT)", 300, 10);
|
|
|
|
|
|
|
|
|
|
|
|
# Parametrize the EPICS record database with the substitution file named after the motor controller.
|
|
|
|
# Parametrize the EPICS record database with the substitution file named after the motor controller.
|
|
|
|
epicsEnvSet("SINQDBPATH","$(sinqMotor_DB)/sinqMotor.db")
|
|
|
|
epicsEnvSet("SINQDBPATH","$(exampleDriver_DB)/sinqMotor.db")
|
|
|
|
dbLoadTemplate("$(TOP)/$(DRIVER_PORT).substitutions", "INSTR=$(INSTR)$(DRIVER_PORT):,CONTROLLER=$(DRIVER_PORT)")
|
|
|
|
dbLoadTemplate("$(TOP)/$(DRIVER_PORT).substitutions", "INSTR=$(INSTR)$(DRIVER_PORT):,CONTROLLER=$(DRIVER_PORT)")
|
|
|
|
epicsEnvSet("SINQDBPATH","$(actualDriver_DB)/turboPmac.db")
|
|
|
|
epicsEnvSet("SINQDBPATH","$(exampleDriver_DB)/turboPmac.db")
|
|
|
|
dbLoadTemplate("$(TOP)/$(DRIVER_PORT).substitutions", "INSTR=$(INSTR)$(DRIVER_PORT):,CONTROLLER=$(DRIVER_PORT)")
|
|
|
|
dbLoadTemplate("$(TOP)/$(DRIVER_PORT).substitutions", "INSTR=$(INSTR)$(DRIVER_PORT):,CONTROLLER=$(DRIVER_PORT)")
|
|
|
|
dbLoadRecords("$(sinqMotor_DB)/asynRecord.db","P=$(INSTR)$(DRIVER_PORT),PORT=$(IP_PORT)")
|
|
|
|
dbLoadRecords("$(exampleDriver_DB)/asynRecord.db","P=$(INSTR)$(DRIVER_PORT),PORT=$(IP_PORT)")
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Substitution file
|
|
|
|
### Substitution file
|
|
|
|
|
|
|
|
|
|
|
|
The substitution file is a table containing axis-specific information which is used to create the axis-specific PVs.
|
|
|
|
The substitution file is a table containing axis-specific information which is used to create the axis-specific PVs.
|
|
|
|
To work with sinqMotor, "mcu1.substitutions" needs to look like this (the order of columns does not matter):
|
|
|
|
To work with sinqMotor, `exampleDriver1.substitutions` needs to look like this (the order of columns does not matter):
|
|
|
|
```
|
|
|
|
```
|
|
|
|
file "$(SINQDBPATH)"
|
|
|
|
file "$(SINQDBPATH)"
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@@ -208,7 +206,9 @@ transferred to (motor_record_pv_name).MRES or to
|
|
|
|
|
|
|
|
|
|
|
|
### Base classes
|
|
|
|
### Base classes
|
|
|
|
|
|
|
|
|
|
|
|
sinqMotor offers a variety of additional methods for children classes to standardize certain patterns (e.g. writing messages to the IOC shell and the motor message PV). For a detailed description, please see the respective function documentation in the .h-files. All of these functions can be overwritten manually if e.g. a completely different implementation of `poll` is required. Some functions are marked as virtual, because they are called from other functions of sinqMotor and therefore need runtime polymorphism. Functions without that marker are not called anywhere in sinqMotor.
|
|
|
|
sinqMotor offers a variety of additional methods for children classes to standardize certain patterns (e.g. writing messages to the IOC shell and the motor message PV). For a detailed description, please see the respective function documentation in the .h-files. All of these functions can be overwritten manually if e.g. a completely different implementation of `poll` is required. Some functions are marked as virtual, because they are called from other functions of sinqMotor and therefore need runtime polymorphism. Functions without that marker are not called anywhere in sinqMotor (except for `forcedPoll`, which is called in `poll`).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Adding new virtual methods breaks the ABI and therefore warrants a new major version number!
|
|
|
|
|
|
|
|
|
|
|
|
#### sinqController.h
|
|
|
|
#### sinqController.h
|
|
|
|
- `couldNotParseResponse`: Write a standardized message if parsing a device response failed.
|
|
|
|
- `couldNotParseResponse`: Write a standardized message if parsing a device response failed.
|
|
|
|
@@ -310,3 +310,15 @@ If your driver uses another driver as a static dependency via git submodule whic
|
|
|
|
- `git submodule update --init --recursive`
|
|
|
|
- `git submodule update --init --recursive`
|
|
|
|
|
|
|
|
|
|
|
|
This will update sinqMotor to the version specified in the 1.0 commit of turboPmac.
|
|
|
|
This will update sinqMotor to the version specified in the 1.0 commit of turboPmac.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Exporting symbols
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
By default, the symbols of classes and functions are hidden to avoid symbol clashes when loading
|
|
|
|
|
|
|
|
multiple shared libraries which use `sinqMotor`. In order to compile this library with exported
|
|
|
|
|
|
|
|
symbols, specifiy `-DHIDDEN= ` as a compiler flag (if using the given Makefile, this
|
|
|
|
|
|
|
|
needs to be added to the `USR_CFLAGS`).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Derived libraries can use the same mechanism via the macro `HIDDEN` (defined in `msgPrintControl.h`):
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
class HIDDEN turboPmacController : public sinqController
|
|
|
|
|
|
|
|
```
|
|
|
|
|