diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..131d9b6cc8e86bfbe3b9e8199a1d2823df569bde --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +**/env +**/__pycache__ +**/*.pyc diff --git a/README.md b/README.md index fa336c344a5eb3393c7f466c7826394cc856f7e2..afb32b2b2ad7924a923fd8cb301722bba3b9553f 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,66 @@ Python OPC-UA server to control the I2C devices in the LTS. + opcuserv.py: OPC-UA server that expose (visible) variables and methods. -# LTS structure: +# Prerequisites + +## Requirements + +This Python3 code uses other Python3 modules: + +- opcua +- pyyaml +- numpy + +We recommend to install a virtual environment and then install the dependencies there. For convenience we have added the relevant modules to the file `requirements.txt` that can be used to install them with pip3: `python3 -m pip install -r requirements.txt` + +Below are step-by-step instructions that show how to install the dependencies neatly in a Python3 virtual environment. + +```bash +# Create a Python3 virtual environment with the name "env" +python3 -m venv env +# Activate the virtual environment +. env/bin/activate +# Update the already installed modules in the virtual environment since they are usually outdated +python3 -m pip install --upgrade pip wheel +# Deactivate the virtual environment and start it again +deactivate +. env/bin/activate +# And finally install the module dependencies +python3 -m pip install -r requirements.txt +``` + +# Execute it + +The software can be simply executed with Python3: `python3 opcuaserv.py` + +Optional parameters are explained when the `-h` or `--help` parameter is supplied: + +```bash +python3 opcuaserv.py --help +cryptography is not installed, use of crypto disabled +cryptography is not installed, use of crypto disabled +usage: opcuaserv.py [-h] [-s] [--no-lib-hack] [-p PORT] + +optional arguments: + -h, --help show this help message and exit + -s, --simulator Do not connect to I2c, but simulate behaviour. + --no-lib-hack Do not require a hacked opcua library. Breaks behaviour. + -p PORT, --port PORT Port number to listen on [4842]. +``` + +# LTS structure Raspberry pi (LTS_pypcc.yaml -> I2C controller on raspberry pi) + > Control PCB (LTS_switch.yaml -> I2C switch) ->> RCU2 PCB (LTS_RCUx.yaml -> I2C devices) ->>> RCU2 Dither source (LTS_RCU2_dither.yaml -> I2C bitbang) ->> ->>> ADC (LTS_RCU2_ADC.yaml -> SPI bitbang2) ->> ->> Clock PCB (LTS_clk.yaml -> I2C device) ->>> PLL (LTS_clkPLL.yaml -> SPI bitbang1) +> +> > RCU2 PCB (LTS_RCUx.yaml -> I2C devices) +> > +> > > RCU2 Dither source (LTS_RCU2_dither.yaml -> I2C bitbang) +> > +> > > ADC (LTS_RCU2_ADC.yaml -> SPI bitbang2) +> > +> > Clock PCB (LTS_clk.yaml -> I2C device) +> > +> > > PLL (LTS_clkPLL.yaml -> SPI bitbang1) + diff --git a/yaml/LTS_RCU2L.yaml b/YAML/LTS_RCU2L.yaml similarity index 100% rename from yaml/LTS_RCU2L.yaml rename to YAML/LTS_RCU2L.yaml diff --git a/yaml/LTS_RCU2_ADC.yaml b/YAML/LTS_RCU2_ADC.yaml similarity index 100% rename from yaml/LTS_RCU2_ADC.yaml rename to YAML/LTS_RCU2_ADC.yaml diff --git a/yaml/LTS_RCU2_dither.yaml b/YAML/LTS_RCU2_dither.yaml similarity index 100% rename from yaml/LTS_RCU2_dither.yaml rename to YAML/LTS_RCU2_dither.yaml diff --git a/yaml/LTS_RCU2dig.yaml b/YAML/LTS_RCU2dig.yaml similarity index 100% rename from yaml/LTS_RCU2dig.yaml rename to YAML/LTS_RCU2dig.yaml diff --git a/yaml/LTS_clk.yaml b/YAML/LTS_clk.yaml similarity index 100% rename from yaml/LTS_clk.yaml rename to YAML/LTS_clk.yaml diff --git a/yaml/LTS_clkPLL.yaml b/YAML/LTS_clkPLL.yaml similarity index 100% rename from yaml/LTS_clkPLL.yaml rename to YAML/LTS_clkPLL.yaml diff --git a/yaml/LTS_pypcc.yaml b/YAML/LTS_pypcc.yaml similarity index 100% rename from yaml/LTS_pypcc.yaml rename to YAML/LTS_pypcc.yaml diff --git a/yaml/LTS_switch.yaml b/YAML/LTS_switch.yaml similarity index 100% rename from yaml/LTS_switch.yaml rename to YAML/LTS_switch.yaml diff --git a/hwdev.py b/hwdev.py index 78305f67473abb9805771afb2237b4bdba3534a8..30362bc8e82d62e05c22321f6ce21488028948ad 100644 --- a/hwdev.py +++ b/hwdev.py @@ -1,7 +1,7 @@ import yaml; import importlib import sys, inspect -YAMLDIR='yaml/' +YAMLDIR='YAML/' class hwdev: def __init__(self,configfile): print("Loading:",configfile) @@ -36,7 +36,7 @@ class hwdev: def GetVarValue(self,name,value,I2Ccallback): return False - + def SetVarValue(self,name,value,I2Ccallback): return False @@ -58,4 +58,4 @@ def Find(L,name,value): for x in L: if x[name]==value: return x; - return False; \ No newline at end of file + return False; diff --git a/opcuaserv.py b/opcuaserv.py index 9c243fe88f465876c92fdf1a43da0064fd1508ed..103493bdb4ef71ce63c3f437cb3cb28433047af9 100644 --- a/opcuaserv.py +++ b/opcuaserv.py @@ -5,17 +5,25 @@ sys.path.insert(0, "..") import time from opcua import ua, Server from datetime import datetime; +import argparse +parser = argparse.ArgumentParser() +parser.add_argument("-s", "--simulator", help="Do not connect to I2c, but simulate behaviour.", action="store_true") +parser.add_argument("--no-lib-hack", help="Do not require a hacked opcua library. Breaks behaviour.", action="store_true") +parser.add_argument("-p", "--port", help="Port number to listen on [%(default)s].", type=int, default=4842) +args = parser.parse_args() -import pypcc; -#import pypcc_test as pypcc; -P1=pypcc.pypcc("LTS_pypcc.yaml") +if args.simulator: + import pypcc_test as pypcc +else: + import pypcc +P1=pypcc.pypcc("LTS_pypcc.yaml") if True: # setup our server server = Server() - server.set_endpoint("opc.tcp://0.0.0.0:4842/PCC/") + server.set_endpoint("opc.tcp://0.0.0.0:{}/PCC/".format(args.port)) idx = server.register_namespace("http://lofar.eu") # uri = "http://examples.freeopcua.github.io" @@ -77,8 +85,12 @@ class SubHandler(object): # print(Vars_R,Vars_R.values()) for vname2,myvar2,oldvalue in Vars_R.values(): if vname2==vname: - res=P1.GetVarValue(vname,val) - print("Read callback",vname,": Result:",res,oldvalue) + if args.simulator: + res=True + print("Simulating fallthrough _RW->_R for",vname,": Result:",res,oldvalue) + else: + res=P1.GetVarValue(vname,val) + print("Read callback",vname,": Result:",res,oldvalue) if res: myvar2.Value.Value=(val[0] if len(val)==1 else val) myvar2.SourceTimestamp = datetime.utcnow() @@ -113,7 +125,8 @@ def AddVar(name,dtype=0,RW=0,cnt=1): Vars_R[myvar.nodeid.Identifier]=[name,myvar.get_data_value(),varvalue2] ValCallback(myvar.nodeid,force=True) # print(myvar.get_value()) - server.set_attribute_callback(myvar.nodeid, ValCallback) + if not args.no_lib_hack: + server.set_attribute_callback(myvar.nodeid, ValCallback) # varvalue=myvar.get_data_value().Value # Vars_R[myvar.nodeid.Identifier][2]=varvalue # print(varvalue2,varvalue) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..a0a74090325423b55cce129fd7d729190c3cedbb --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +opcua +pyyaml +numpy diff --git a/test/test_ADCs.py b/test/test_ADCs.py index b0c18ee84b543a7cc85afa692d4a3a92dfed3f63..3be2fa979f976cb867efa14f351deaaeae88914e 100644 --- a/test/test_ADCs.py +++ b/test/test_ADCs.py @@ -1,5 +1,5 @@ -#import pypcc; -import pypcc_test as pypcc; +import pypcc; +#import pypcc_test as pypcc; P1=pypcc.pypcc("LTS_pypcc.yaml") @@ -9,8 +9,10 @@ def AddMethod(name): P1.GetMethodNames("",AddMethod); ##Print all the visible variables -def AddVar(name,dtype=0,RW=0): - print("Var:",name,dtype,RW) +def AddVar(name,dtype=0,RW=3,cnt=1): + Types={0:'int',1:'float'} + RWs={0:'hidden',1:'RO',2:'WO',3:'RW'} + print("Var:",name,Types[dtype],RWs[RW],cnt) P1.GetVarNames("",AddVar); a=[0] diff --git a/test/test_clk.py b/test/test_clk.py index 04c59107e635cc4e95178449e619eef4b614d7c4..da3e84bb7e72045d7ad03530f7438515958298eb 100644 --- a/test/test_clk.py +++ b/test/test_clk.py @@ -17,10 +17,11 @@ def AddMethod(name): print("Method:",name) P1.GetMethodNames("",AddMethod); -def AddVar(name,dtype=0,RW=3): +def AddVar(name,dtype=0,RW=3,cnt=1): Types={0:'int',1:'float'} RWs={0:'hidden',1:'RO',2:'WO',3:'RW'} - print("Var:",name,Types[dtype],RWs[RW]) + print("Var:",name,Types[dtype],RWs[RW],cnt) + P1.GetVarNames("",AddVar); #exit() #P1.CallMethod("RCU01_RCU_on",None) diff --git a/test_ADCs.py b/test_ADCs.py deleted file mode 100644 index 94c874699db3677108165e4fd01ef0a087fb66a3..0000000000000000000000000000000000000000 --- a/test_ADCs.py +++ /dev/null @@ -1,45 +0,0 @@ -import pypcc; -#import pypcc_test as pypcc; - -P1=pypcc.pypcc("LTS_pypcc.yaml") - -##Print all the visible methods -def AddMethod(name): - print("Method:",name) -P1.GetMethodNames("",AddMethod); - -##Print all the visible variables -def AddVar(name,dtype=0,RW=0,dim=1): - print("Var:",name,dtype,RW,dim) -P1.GetVarNames("",AddVar); - -a=[0] -##Setup ADC RCU1 -P1.CallMethod("RCU01_RCU_off",None) -P1.CallMethod("RCU01_RCU_on",None) -#P1.GetVarValue("RCU01_ADC1_locked",a);print(a[0]); -P1.GetVarValue("RCU01_ADC1_SYNC",a);print(a[0]); -P1.GetVarValue("RCU01_ADC1_CML",a);print(a[0]); -P1.GetVarValue("RCU01_ADC1_JESD",a);print(a[0]); -P1.GetVarValue("RCU01_ADC2_SYNC",a);print(a[0]); -P1.GetVarValue("RCU01_ADC2_CML",a);print(a[0]); -P1.GetVarValue("RCU01_ADC2_JESD",a);print(a[0]); -P1.GetVarValue("RCU01_ADC3_SYNC",a);print(a[0]); -P1.GetVarValue("RCU01_ADC3_CML",a);print(a[0]); -P1.GetVarValue("RCU01_ADC3_JESD",a);print(a[0]); -#P1.GetVarValue("RCU01_ADC1_JESD_control1",a);print(a[0]); -#P1.GetVarValue("RCU01_ADC1_CML_level",a);print(a[0]); -#P1.GetVarValue("RCU01_ADC1_locked",a);print(a[0]); -#P1.GetVarValue("RCU01_ADC1_locked",a);print(a[0]); -# - ADC1.SYNC_control: [1] #Setup ADCs -# - ADC1.JESD_control1: [14] #Setup ADCs -# - ADC1.CML_level: [0x7] -# - ADC1.Update: [1] #Needed to update ADC registers - -exit() -##Setup ADC RCU3 -P1.CallMethod("RCU01_RCU_off",None) -P1.CallMethod("RCU03_RCU_on",None) -P1.GetVarValue("RCU03_ADC1_locked",a);print(a[0]); -P1.GetVarValue("RCU03_ADC2_locked",a);print(a[0]); -P1.GetVarValue("RCU03_ADC3_locked",a);print(a[0]);