diff --git a/README.md b/README.md
index ee62b1287218b9d46e949b539990b3145be3a0b3..0c0222e37ac637a10bc909f5e33d6579b1161920 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,30 @@
 
 # tl;dr
 
-23/03/2021  
-Use the Scan Operator together with Yarr's devel branch. 
-Edit the module config in `configs/so_modules.json` and choose the scan sequence in `configs/so_yarr`.
+Use the Scan Operator together with Yarr's devel branch and labRemote's master.
+Edit the module config in `configs/so_modules.json`, and the scan sequence in `configs/so_yarr`.
 
 # Introduction
-The Scan Operator (SO) is an integration tool for scan data and DCS data, which is meant to be used during the QC procedure of the Rd53a modules. It uses multiple localDB scripts as well as some integrated tools to achieve these features:
+The Scan Operator (SO) is an integration tool for scan data and DCS data, which is meant to be used during the QC procedure of the Rd53a/Rd53b modules. It uses multiple localDB scripts as well as some integrated tools to achieve these features:
 
-  - Calls Yarr repeatedly to **run a sequence of scans on Rd53a**.
+  - Calls Yarr repeatedly to **run a sequence of scans on the chip**.
+  - Makes very easy to edit chip-by-chip config parameters (trims, chip name, rx and tx, ...)
   - Registers a module in LocalDB if it's not already there
   - **Monitors the Power Supply** (PS) powering the ASIC and storing the DCS data in **InfluxDB**
   - Synchronizes the DCS data and the scan data in **LocalDB**.
-  - Makes very easy to edit chip-by-chip config parameters (trims, chip name, rx and tx, ...)
-  - Checks that temperature and humidity are within a safe range before proceeding to the scans
-  - Performs IV/VI scans on the Sensor / Module
 
-All the DCS-related functionality is optional. The SO provides a script based on labRemote (LR) to monitor DCS in real time, but any other external tool can also be used as long as it is capable of uploading the DCS data to InfluxDB.
+All the DCS-related functionality is optional. The SO provides scripts based on labRemote (LR) to monitor DCS in real time, but any other external tool can also be used as long as it is capable of uploading the DCS data to InfluxDB.
+
+
+# Other independent tools included in the SO
+
+This repository includes the following independent tools:
+
+  - `libDCS/iviscan.py`: safely performs sensor IV and module VI scans
+  - `libDCS/psOperator.py`: Controls and monitors a power supply. Optionally uploads PS data to influxDB until killed
+  - `libDCS/parameterOptimizer.py`: Performs trim scans, tap scans, etc on a selected chip to find its best configuration.
+
+More on this tools [here](#useful-independent-tools).
 
 # Quick Tutorial
 
@@ -29,7 +37,7 @@ To run the Scan Operator, you need *at least*:
 
 
 ## 1. Get the code
-If you want to use the SO's DCS integrated tool, start by cloning and building labRemote. *You don't need to do it in another case*.  
+If you want to use any PS-related functionality, start by cloning and building labRemote. *You don't need to do it in another case*.  
 
 Make sure to enable the Python bindings using cmake's `-DUSE_PYTHON=on` flag. For a detailed installation guide, follow [labRemote's readme](https://gitlab.cern.ch/berkeleylab/labRemote/).
 
@@ -43,37 +51,20 @@ yum install python3-devel
 cmake3 -DUSE_PYTHON=on .. && make -j6
 ```
 
-labRemote's commit [24e7a55b](https://gitlab.cern.ch/berkeleylab/labRemote/-/commit/24e7a55b5e943db7fb6c6252c610b40d9eb8cf62) has been confirmed to work with no problems together with the Scan Operator. We recommend using the latest version and switching to this one only in case of LR-related errors.
-
 **Clone also somewhere the Scan Operator**
 ```bash
 git clone --recursive https://gitlab.cern.ch/YARR/utilities/scan-operator.git
 ```
 
-**Use the appropriate version of Yarr**
-Yarr's devel is OK. Use Master if devel gives any problem.
-
-
 ## 3. Run the Scan Operator
 
-The Scan Operator uses many configuration files, all of them located by default under `$SOBASE/configs`. Most of them are intuitive and the SO will tell you when you need to modify them.
+The Scan Operator uses many configuration files, all of them located by default under `./configs`. Most of them are intuitive and the SO will tell you when you need to modify them.
 
+Start from `./ScanOperator.sh` to see a complete list of options.
 
-```
-$ ./ScanOperator.sh
-Help:
-  -m [str]   : Serial number of the module
-  -W         : upload Yarr's results to localDB (scanConsole's -W)
-  -o         : turn on / off the output of the PS before and after all the scans
-  -e         : Check if T and H are within a setting range before running each scan
-  -d         : Monitor the PS and upload the DCS data to influxDB.
-  -t         : Move DCS data from InfluxDB to LocalDB after each scan.
-  -c         : Create / override Yarr's config files for your chip.
-  -q         : "quiet" mode (cleaner output).
-```
 
 ### List of arguments
-*Read this section only if the output of `$ ./ScanOperator.sh` is not clear enough.*
+*(a more detailed explanation of the output of `./ScanOperator.sh`)*
 
 #### Required
 
@@ -81,11 +72,15 @@ Help:
 
 #### Optional
 
-- `-c:` Create Yarr config files. Necessary files such as the `controller` or `connectivity` will be created / overwritten** if `-c` is used. Use this option after making any change in the config files, or if you are using the software for the first time. All the files are created in the Scan Operator folder, so everything you have under Yarr's one remains untouched. Summarizing, "-c" does the following.
+- `-c:` Create / overwritte Yarr config files (`controller`, `connectivity` and chip cfg files). Use this option if you are using a module for the first time or you want to regenerate its config from scratch. Summarizing, "-c" does the following.
   - Retrieves the files from localDB if the module is already registered and the connection is good. Creates them offline otherwise.
   - Edits them based on `so_modules.json`
-  - if -W is used, reuploads them to localDB, associated with every scan.  
+
+The cfg files are created in the Scan Operator's folder, so everything you have under Yarr's one remains untouched
   
+- `-s:` Doesn't look for changes in the config. Can be useful when runing the SO without having modified `so_modules.json`. Saves some time.
+- `-j:` Just updates the module configs according to `so_modules.json`, and exits before interacting with the module or the PS at all.
+
 - `-W:` This one is equivalent to the `-W` option used when calling Yarr's ScanConsole  
 - `-Q:` This one is equivalent to the `-Q` option you use when calling Yarr's ScanConsole
 
@@ -93,7 +88,7 @@ Help:
 
 #### DCS related
 
-- `-o:` **Turns on the output of the `channels_to_be_used_by_the_scanoperator`** specified in `lr_powersupply.json` before running the sequence of scans. **Turns the output off again** after running all the scans.
+- `-o:` **Turns on the output of the `channels_to_be_used_by_the_scanoperator`** specified in `lr_powersupply.json` before running the sequence of scans. **Turns the output off again** after running all the scans. Not very reccomended, specially when working at low temperatures.
 
 - `-d:` Monitor the PS and store **real-time DCS data in InfluxDB**.
 
@@ -108,14 +103,14 @@ Here are some example use cases of the Scan Operator.
 #### *Hello world*
 
 ```bash
-./ScanOperator.sh -m module_id -c
+./ScanOperator.sh -m module_id
 ```
 
-You should start from here before going any further. This will just run in series the scans you specified in `scan_list` (in `so_modules.json`). All the DCS / LocalDB / InfluxDB functionality is disabled here.
+You should start from here before going any further. This will just run in series the scans you specified in `scan_list` (in `so_yarr.json`). All the DCS / LocalDB / InfluxDB functionality is disabled.
 
 #### *QC procedure*
 
-If you are using the Scan Operator during the QC procedure of any of your modules, you should call it by enabling all the QC / LocalDB Features. (`-Q` and `-W` respectively). You don't need to monitor any DCS data.
+If you are using the Scan Operator during the QC procedure of any of your modules, you should call it by enabling all the QC / LocalDB Features. (`-Q` and `-W` respectively).
 
 ```bash
 ./ScanOperator.sh -m module_id -c -Q -W
@@ -128,17 +123,18 @@ To manually sync DCS in localDB after running this, refer to [the following sect
 If you want to use the SO to monitor DCS (`-d`) and synchronize the DCS data and the scan data in localDB after each scan (`-t`), use
 
 ```bash
-./ScanOperator.sh -m module_id -d configs/m_powersupply.json -W -t
+./ScanOperator.sh -m module_id -d configs/m_powersupply.json -W -d -t
 ```
 #### *Monitoring DCS with an external tool*
 
-Say you are using your own tool to upload DCS data to InfluxDB, while using the SO to run all the scans.
-  
+Say you are using your own tool (e.g. `libDCS/psOperator.py`) to constantly upload DCS data to InfluxDB, while using the SO to run all the scans.
+
+Then you can omit -d
 ```bash
-./ScanOperator.sh -m module_id configs/m_powersupply.json -W
+./ScanOperator.sh -m module_id configs/m_powersupply.json -W -t
 ```
 
-So you will see this before the SO finishes running.
+If it doesn' work in real time, use just -W and you will see this message once the SO finishes each scan:
 ```
 [ info ][so] If you want to upload to localDB the DCS data associated
              to all the scans you have just run (assuming you have it
@@ -147,7 +143,7 @@ So you will see this before the SO finishes running.
                  bash /home/mario/work/scan-operator/data/201214_051/moveDCStoLocalDB.sh path/to/idb_to_ldb.json
 ```
 
-Refer to the following section if you need any help filling the config file.
+Refer to the following section if you need any help filling the config files.
 
 
 ### The SO configuration files
@@ -164,28 +160,32 @@ This file contains the properties of all of your modules (SCCs, quads, ...) you
 Most of the items are self-explanatory. Here are the ones that may require some indications to fill.
 
 
-
   - **`.modules`**: Write here the configs for as many modules as you want. The file comes with an example for a SCC and an example for a quad. You will choose between the modules you have defined here in the command line. Notes:
-    - The name of each module (e.g. `moduleid_quad`) should match the Serial Number of the module.
+    - The name of each module (e.g. `moduleid_quad`) should (but doesn't have to) match the Serial Number of the module.
     - For each chip:
       - For any key written in `"GlobalConfig"`, the Scan Operator will:
-        - Look for it in Yarr's general chip config file (e.g. `rd53a_test.json`) under `.RD53A.GlobalConfig`. 
+        - Look for it in Yarr's chip config file (in `configs/rd53x`) under `.RD53A.GlobalConfig`. 
         - If found, change the value to the one specified by the user.
         - If not found, create it and continue.
       - The same goes for the `"connectivity"` and the `"Parameter"` section.  
 
 #### Yarr's general configuration file (so_yarr.json)
 
-  - **`.YARR.scan_list`**: Place here the sequence of scans that you want to run. For a threshold / tot tuning, the second argument in the bracket represents the target threshold / tot (e.g. `["diff_retune_pixelthreshold", 1000]` will retune the pixel threshold of the differential FE to 1000 e), whilst `["diff_tune_globalpreamp", 7]` will tune the ToT to 7). The target charge for ToT tuning / scan is specified under `.YARR.scan` and it's assumed to be the same for all the ToT-related scans.  
+  - **`.scan_list`**: Place here the sequence of scans that you want to run.
+ 
+    - For a threshold / tot tuning, the second argument in the bracket represents the target threshold / tot (e.g. `["diff_retune_pixelthreshold", 1000]` will retune the pixel threshold of the differential FE to 1000 e), whilst `["diff_tune_globalpreamp", 7]` will tune the ToT to 7). The target charge for ToT tuning / scan is specified under `.YARR.scan` and it's assumed to be the same for all the ToT-related scans.  
+  
+    - For the rest of the scans, the second argument is Yarr's mask option (Yarr's `-m`), either 1, 0 or nothing (Yarr's default).
+  - **`.common_config.max_trials_in_case_of_failure`**: Sometimes, you might get a segfault from Yarr comming from corrupted data. Normally just resumming the scan sequence from where you left it does the job. This option does it for you.
 
 
 #### Powersupply configuration file (lr_powersupply.json)
 
-Contains the actual information to establish communication with the PS as well as the definition of the channels. Amongst all the channels you have defined, select the ones you want to use in "channels_to_be_used_by_the_scanoperator". The SO will ignore any channel not appearing there. 
+Contains the information to establish communication with the PS as well as the definition of the channels. Amongst all the channels you have defined, select the ones you want to use in "channels_to_be_used_by_the_scanoperator". The SO will ignore any channel not appearing there. 
 
-- **`.devices`**: Write here the PS / PSs you want to use. A list of supported "`hw-model`" and "`protocol`" is available in [labRemote's README.md](https://gitlab.cern.ch/berkeleylab/labRemote#python-bindings). To find the port your PS is connected to, look at the output of `ls -l /dev/serial/by-id/`.
+- **`.devices`**: Write here the PS / PSs you want to use. A list of supported "`hw-model`" and "`protocol`" is available in labRemote's docs. To find the port your PS is connected to, look at the output of `ls -l /dev/serial/by-id/`.
   
-- **`.channels`**: You can have here as many channels as you want, but only the ones appearing in `so_modules.json` will be used. Under `.channels`, `"device"` should be one of the ones in the upper section, and `"channel"` is the actual output channel number of the PS (e.g. from 1 to 4 for the R&S HMP4040).
+- **`.channels`**: You can have here as many channels as you want, but only the ones appearing in `channels_to_be_used_by_the_scanoperator` will be used. Under `.channels`, `"device"` should be one of the ones in the upper section, and `"channel"` is the actual output channel number of the PS (e.g. from 1 to 4 for the R&S HMP4040).
   
 
 
@@ -202,7 +202,7 @@ Contains the actual information to establish communication with the PS as well a
 
 #### InfluxDB to LocalDB configuration file (idb_to_ldb.json)
 
-    Used when associating any DCS/ENV data to the scans in LocalDB
+  Used when associating any DCS/ENV data to the scans in LocalDB
 
   - `.influxdb_cfg`: Which DB you want to take the data from.
 
@@ -217,7 +217,7 @@ Contains the actual information to establish communication with the PS as well a
     - `X`: `V` or `I`
     - `C`: PS Channel, as you named it in the main config file. 
     E.g. `measV_LV` will contain the sense values of V read on the channel named "LV".
-  - `.environments.dcslist[i].setting`: Setting value. It is not used by the Scan Operator, but it's uploaded to localDB for reference.
+  - `.environments.dcslist[i].setting_column_name`: Column name in influxDB storing the setting value of each `"key"`. It is not used by the Scan Operator, but it's uploaded to localDB for reference.
 
 #### LocalDB "site" and "user" configuration files (ldb_site.json and ldb_user.json)
 
@@ -242,12 +242,54 @@ This one is autogenerated. Don't worry about it.
 
 
 
-
 ## 4. View the results offline
 
 The SO puts all the scan data under the `data/` folder. There, the data is organized in folders named `YYMMDD_(RUN_COUNTER)`. Each of them contains Yarr's output for all the scans performed under the same call to the SO.
 
 
+
+# Useful Independent tools
+
+## IV / VI scan script (./libDCS/iviscan.json)
+
+- Run `python3 libDCS/iviscan.py -h` for a list of options
+- Edit all the scan parameters in `configs/lr_iviscan.json`
+
+You can specify the number of measurements per step and the sleeping time between measurements. Moving to the initial point, and going back to the initial state after finishing scan is done ramping amoothly. The measured values per step, as well as their standard deviation is displayed in the terminal in real time.
+
+## PS Controller / monitor tool
+
+- `python3 libDCS/psOperator.py -h` for a complete set of options.
+
+This script can be used to remotely control a power supply. (set/get-voltage, power on/off, etc). It can also be left running in the background (e.g. in a `screen`) constantly monitoring a single channel and uploading the data to influxDB.
+
+- ## Parameter Optimizer
+
+- `python3 libDCS/parameterOptimizer.py -h` for usage information
+
+Used to quickly find the best config values for a single chip. Can be used to scan trim values, tap values or any other config value. Builds a 2D matrix with all the value combinations and fills it in real-time on the terminal. A sample output for a trim scan made with this too is the following:
+
+```
+haxis: CmlTapBias1; vaxis: CmlTapBias0
+
+  #      0     100  200   300      400
+ 300  76800.0  0.0  8.0   -1.0     -1.0
+ 400   258.0   0.0  0.0  1971.0    -1.0
+ 500    0.0    0.0  0.0   0.0    54638.0
+ 600    0.0    0.0  0.0   0.0    27142.0
+ 700    0.0    0.0  0.0   0.0     3513.0
+ 800    0.0    0.0  0.0   0.0      0.0
+ 900    0.0    0.0  0.0   0.0      0.0
+```
+
+The numbers in the matrix indicate the number of failing pixels (0's in the enMask) from a digital.
+
+The default config file for this script is `so_optimizer.json`. There, the target chip number starts from 1. 1 is the first chip, 2 is the 2nd, ... as you have them ordered in your SO config. To check the order you can also look at the connectivity file displayed on the terminal when calling `./ScanOperator.sh -m your_module -j`.
+
+The script tries to look for the best region by itself. Once found, you can wait for the whole matrix to get filled, or just kill the script at any stage. After using this script run the SO once, just to reset the configuration to its original state.
+
+
+
 # FAQs
 
 These are a few issues you might encounter when using this software.
diff --git a/ScanOperator.sh b/ScanOperator.sh
index ededc67b380a28af42d1d31ca8eb26efff002016..37a80e1e5ad3d4ad80fdd827170bf17f7e465f5e 100755
--- a/ScanOperator.sh
+++ b/ScanOperator.sh
@@ -1,11 +1,13 @@
-
+#!/bin/sh
 
 original_tty_state=$(stty -g)
 dcsOnOff=0      # Turns the DCS on (off) before (after) running all the scans
-quietMode=0         # Trims the output to the DB-related info + the scan results
+quietMode=0     # Trims the output to the DB-related info + the scan results
 createConfig=0  # Creates / overwrites Yarr config files based on config.json
-dcsMonitor=0       # 
-envMonitor=0       # 
+justConfigure=0 # Update config and exit
+skipCfgCheck=0  # Skips checking for cfg updates (saving time)
+dcsMonitor=0    # 
+envMonitor=0    # 
 
 # A few colors for echoing
 function darkblue(){
@@ -63,6 +65,8 @@ Help:
   -d         : Monitor the PS and upload the DCS data to influxDB.
   -t         : Move DCS data from InfluxDB to LocalDB after each scan.
   -c         : Create / override Yarr's config files for your chip.
+  -s         : Don't look for updates in the config (saves time)
+  -j         : Just update the configs, and exit before running any scan
   -q         : "quiet" mode (cleaner output).
 EOF
     exit 1
@@ -75,7 +79,7 @@ then
     exit
 fi
 
-while getopts m:q:docteWQ OPT
+while getopts m:q:docstejWQ OPT
 do
     case $OPT in
         m) module_id=$OPTARG ;;
@@ -85,6 +89,8 @@ do
         o) dcsOnOff=1 ;;
         d) dcsMonitor=1 ;;
         c) createConfig=1 ;;
+        s) skipCfgCheck=1 ;;
+        j) justConfigure=1 ;;
         W) localdbOpt="-W" ;;
         Q) qcOpt="-Q" ;;
         *) usage ;;
@@ -183,7 +189,7 @@ then
     
     # Perform a first DCS Measurement to check for possible authentication
     while true; do 
-        python3 $SOBASE/libDCS/qaqc.py -e $PSCFG -c $chn -d $INFLUXDBDCSCFG measure
+        python3 $SOBASE/libDCS/psOperator.py -e $PSCFG -c $chn -d $INFLUXDBDCSCFG measure
         rv=$?
         if [ $rv -eq 0 ]; then 
             # No authentication / No errors
@@ -231,7 +237,7 @@ fi
 
 nChips="$(jq -j --arg b ${module_id} '.modules."\($b)".chips | length' $MODULECFG)"
 cfgdir=$SOBASE/configs/rd53a/$module_id
-
+CNCT_FILE=$cfgdir/connectivity.json
 
 if [ $createConfig == 1 ] ; then
     rm -rf $cfgdir
@@ -359,27 +365,49 @@ if [ $createConfig == 1 ] ; then
     fi
 
 
-
-    
+    # Generate chip cfg files
     for (( i=0; i<$nChips; i++ ))
     do
-
-        CNCT_FILE=$cfgdir/connectivity.json
-
         echo ""
         echo "------------------------"
         # create default chipConfig.json
         chipName="$(jq -j --argjson a ${i} --arg b ${module_id} '.modules."\($b)".chips[$a].connectivity.name' $MODULECFG)"
         echo -e "[ info ][so] Creating config file for chip \"$(green $chipName)\": $cfgdir/$chipName.json"
         $YARRBASE/bin/createConfig -t RD53A -n $chipName -o $cfgdir/$chipName.json #> /dev/null
+    done
+
+
+    # Generate controller cfg file
+    CRTL_FILE=$cfgdir/controller.json 
+    cp $YARRBASE/configs/controller/specCfg-rd53a.json $CRTL_FILE 
+    specNum=$(jq -j --arg b ${module_id} '.modules."\($b)".specNum' $MODULECFG)
+    if [ "$specNum" != "null" ]; then
+        jq --argjson v $specNum '.ctrlCfg.cfg.specNum = $v' $CRTL_FILE > currentValue && mv currentValue $CRTL_FILE
+    fi
+
+fi
+
+
+# Check that cfg files are there
+if [[ ! -d "$cfgdir" ]]
+then
+    echo -e "[ error ][so] Couldn't find config files for module \"$module_id\".\n"\
+             "             Please run the S.O. again with '-c' to create them"
+    exit
+fi
 
 
-        # Modify retrieved Yarr config files according to config.json
+echo ""
+# Modify config files according to config.json
+if [ $skipCfgCheck != 1 ] ; then
+    for (( i=0; i<$nChips; i++ ))
+    do
 
         # Chip config file 
+        chipName="$(jq -j --argjson a ${i} --arg b ${module_id} '.modules."\($b)".chips[$a].connectivity.name' $MODULECFG)"
         JSON_FILE=$cfgdir/$chipName.json
 
-        echo ""
+        echo -e "[ info ][so] Looking for cfg updates in chip $(( i+1 ))'s configs..."
         jq -r --argjson a ${i} --arg b ${module_id} '.modules."\($b)".chips[$a].GlobalConfig | keys[] as $k | "\($k) \(.[$k])"' $MODULECFG |
         while IFS=" " read -r -a value; do
             key=${value[0]}
@@ -420,16 +448,13 @@ if [ $createConfig == 1 ] ; then
                 else
                     jq --argjson v $val --arg k $key '.RD53A.Parameter."\($k)" = $v' $JSON_FILE > currentValue && mv currentValue $JSON_FILE
                 fi
-                
+
                 echo -e "[ info ][so] Changed $(darkblue \"$key\") from $(darkblue \"$currentValue\") to $(darkblue \"$val\") in the chip config file (Parameter section)"
             fi
         done
 
         # Connectivity file:
-        echo ""
-        echo -e "[ info ][so] Linking chip cfg file in the connectivity file (chip $i)"
         jq -e --argjson a ${i} --arg v $JSON_FILE '.chips[$a].config = "\($v)"' $CNCT_FILE > currentValue && mv currentValue $CNCT_FILE
-
         jq -r --argjson a ${i} --arg b ${module_id} '.modules."\($b)".chips[$a].connectivity | keys[] as $k | "\($k) \(.[$k])"' $MODULECFG |
         while IFS=" " read -r -a value; do
             key=${value[0]}
@@ -441,6 +466,7 @@ if [ $createConfig == 1 ] ; then
             then
                 jq --argjson a ${i} --argjson v $val --arg k $key '.chips[$a]."\($k)" = $v' $CNCT_FILE > currentValue && mv currentValue $CNCT_FILE
                 echo -e "[ warn ][so] Added key $(darkblue \"$key\") with value $(darkblue \"$val\") in the connectivity file (chip $i)"
+
             elif [ "$currentValue" != "$val" ];
             then
                 if ! [[ "$val" =~ ^[0-9]+$ ]] ; then
@@ -453,38 +479,25 @@ if [ $createConfig == 1 ] ; then
             fi
         done
 
-        
-
-
-
         # Create an entry with the module serial number (to associate the config
         # files to in localdb)
         jq '. += {"module"}' $CNCT_FILE > sotmp && mv sotmp $CNCT_FILE
         jq --arg a ${module_id} '.module += {"serialNumber": "\($a)"}' $CNCT_FILE > sotmp && mv sotmp $CNCT_FILE
         jq '.module += {"componentType": "module"}' $CNCT_FILE > sotmp && mv sotmp $CNCT_FILE
-        
+        echo ""
     done
+fi
 
-    # Controller file
-    CRTL_FILE=$cfgdir/controller.json 
-    cp $YARRBASE/configs/controller/specCfg-rd53a.json $CRTL_FILE 
-    specNum=$(jq -j --arg b ${module_id} '.modules."\($b)".specNum' $MODULECFG)
-    if [ "$specNum" != "null" ]; then
-        jq --argjson v $specNum '.ctrlCfg.cfg.specNum = $v' $CRTL_FILE > currentValue && mv currentValue $CRTL_FILE
-    fi
 
-    echo "------------------------"
-    cat $cfgdir/connectivity.json | jq .
-    echo "------------------------"
-    echo "[ warn ][so] Are these settings correct?"
-    unset answer
-    while [ -z "${answer}" ]; do
-        read -p "[y/n]: " answer
-    done
-    if [[ ${answer} != "y" ]]; then
-        echo "[ error ][so] Please modify the configuration in $MODULECFG and try again."
-        exit
-    fi
+echo "[ info ][so] Current connectivity config:"
+echo "------------------------"
+cat $cfgdir/connectivity.json | jq .
+echo "------------------------"
+
+
+if [ $justConfigure == 1 ] ;then
+    echo -e "[ info ][so] Configuration updated."
+    exit 0
 fi
 
 if [ $dcsOnOff == 1 ] ;then
@@ -494,18 +507,11 @@ if [ $dcsOnOff == 1 ] ;then
     for (( i=0; i<$nChannels; i++ ))
     do
         chn="$(jq -j ".channels_to_be_used_by_the_scanoperator[$i].name" $PSCFG)"
-        python3 $SOBASE/libDCS/qaqc.py -e $PSCFG -c $chn -d $INFLUXDBDCSCFG power-on
+        python3 $SOBASE/libDCS/psOperator.py -e $PSCFG -c $chn -d $INFLUXDBDCSCFG power-on
         if [ $? -ne 0 ]; then exit 1; fi
     done
 fi
 
-if [[ ! -d "$cfgdir" ]]
-then
-    echo -e "[ error ][so] Couldn't find config files for module \"$module_id\".\n"\
-             "             Please run the S.O. again with '-c' to create them"
-    exit
-fi
-
 
 echo -e "\n[ info ][so] Running the sequence of scans"
 
@@ -532,7 +538,7 @@ for i in $(seq 1 $nScans); do
     obj="$(echo -e "${obj}" | tr -d '[:space:]')"
     
     comm="$SOBASE/scanLauncher.sh -m ${module_id} -s $obj ${dcsOpt} ${localdbOpt} ${qcOpt} ${syncOption}"
-    echo $comm
+    echo "$comm"
     echo -e "[ info ] |\n[ info ] | - $(echo $obj | jq -r '.[0]')\n[ info ] |"
     if [ $quietMode -gt 0 ];
     then
@@ -562,7 +568,7 @@ if [ $dcsOnOff == 1 ]; then
     for (( i=0; i<$nChannels; i++ ))
     do
         chn="$(jq -j ".channels_to_be_used_by_the_scanoperator[$i].name" $PSCFG)"
-        python3 $SOBASE/libDCS/qaqc.py -e $PSCFG -c $chn -d $INFLUXDBDCSCFG power-off
+        python3 $SOBASE/libDCS/psOperator.py -e $PSCFG -c $chn -d $INFLUXDBDCSCFG power-off
         if [ $? -ne 0 ]; then exit 1; fi
     done
 fi
diff --git a/configs/lr_iviscan.json b/configs/lr_iviscan.json
index 637179bbe96583d4049ab027fa9678fa6221e143..6c1a3759dc2b33e33fd6324820bb0e42f5c568cb 100644
--- a/configs/lr_iviscan.json
+++ b/configs/lr_iviscan.json
@@ -5,10 +5,10 @@
         {
             "name": "HV",
             "initial_voltage": 0,
-            "final_voltage": -150,
+            "final_voltage": -200,
             "step_size": -5,
-            "measurements_per_step": 3,
-            "sleeping_time_per_step_s": 10,
+            "measurements_per_step": 10,
+            "sleeping_time_per_step_s": 2,
             "current_protection": 0.0001
         },
         "passive_channels":
@@ -34,4 +34,4 @@
         [
         ]
     }
-}
\ No newline at end of file
+}
diff --git a/configs/so_modules.json b/configs/so_modules.json
index a0ef867217ac3090c695021098ca6f6ae8f1de8b..b39c2530ef88016f259a5151a167e3460b5cfbaa 100644
--- a/configs/so_modules.json
+++ b/configs/so_modules.json
@@ -26,7 +26,7 @@
                 }
             ]
         },
-        "KEKQ-05":{
+        "my_quad_id":{
             "specNum": 0,
             "chipType": "RD53A",
             "chips":[
@@ -36,14 +36,13 @@
                         "tx": 0,
                         "rx": 0,
                         "enable": 1,
-                        "name": "KEKQ-05-1"
+                        "name": "chip1"
                     },
                     "GlobalConfig":
                     {
-                        "AdcRefTrim": 12,
                         "SldoAnalogTrim": 22,
                         "SldoDigitalTrim": 22,
-                        "OutputActiveLanes": 1,
+                        "OutputActiveLanes": 7,
                         "CmlEn": 7,
                         "CmlEnTap": 1,
                         "CmlInvTap": 1,
@@ -52,11 +51,10 @@
                         "CdrSelSerClk": 1,
                         "DiffLcc": 400,
                         "DiffLccEn": 1
-
                     },
                     "Parameter":
                     {
-                        "Name": "KEKQ-05-1",
+                        "Name": "chip1",
                         "ChipId": 1
                     }
                 },
@@ -65,15 +63,14 @@
                     {
                         "tx": 0,
                         "rx": 1,
-                        "enable": 0,
-                        "name": "KEKQ-05-2"
+                        "enable": 1,
+                        "name": "chip2"
                     },
                     "GlobalConfig":
                     {
-                        "AdcRefTrim": 12,
                         "SldoAnalogTrim": 22,
                         "SldoDigitalTrim": 22,
-                        "OutputActiveLanes": 1,
+                        "OutputActiveLanes": 7,
                         "CmlEn": 7,
                         "CmlEnTap": 1,
                         "CmlInvTap": 1,
@@ -85,7 +82,7 @@
                     },
                     "Parameter":
                     {
-                        "Name": "KEKQ-05-2",
+                        "Name": "chip2",
                         "ChipId": 2
                     }
                 },
@@ -94,15 +91,14 @@
                     {
                         "tx": 0,
                         "rx": 2,
-                        "enable": 0,
-                        "name": "KEKQ-05-3"
+                        "enable": 1,
+                        "name": "chip3"
                     },
                     "GlobalConfig":
                     {
-                        "AdcRefTrim": 12,
                         "SldoAnalogTrim": 22,
                         "SldoDigitalTrim": 22,
-                        "OutputActiveLanes": 1,
+                        "OutputActiveLanes": 7,
                         "CmlEn": 7,
                         "CmlEnTap": 1,
                         "CmlInvTap": 1,
@@ -114,7 +110,7 @@
                     },
                     "Parameter":
                     {
-                        "Name": "KEKQ-05-3",
+                        "Name": "chip3",
                         "ChipId": 3
                     }
                 },
@@ -124,14 +120,13 @@
                         "tx": 0,
                         "rx": 3,
                         "enable": 1,
-                        "name": "KEKQ-05-4"
+                        "name": "chip4"
                     },
                     "GlobalConfig":
                     {
-                        "AdcRefTrim": 12,
                         "SldoAnalogTrim": 22,
                         "SldoDigitalTrim": 22,
-                        "OutputActiveLanes": 1,
+                        "OutputActiveLanes": 7,
                         "CmlEn": 7,
                         "CmlEnTap": 1,
                         "CmlInvTap": 1,
@@ -143,7 +138,7 @@
                     },
                     "Parameter":
                     {
-                        "Name": "KEKQ-05-4",
+                        "Name": "chip4",
                         "ChipId": 4
                     }
                 }
diff --git a/configs/so_optimizer.json b/configs/so_optimizer.json
new file mode 100644
index 0000000000000000000000000000000000000000..31e18f432e0d37ebb3847962e66df678dc69cd42
--- /dev/null
+++ b/configs/so_optimizer.json
@@ -0,0 +1,58 @@
+{
+    "targetChipNumber": 1,
+    "repetitions": 2,
+    "parameters":
+    [
+        {
+            "name": "CmlTapBias0",
+            "min": 300,
+            "max": 900,
+            "step": 100
+        },
+        {
+            "name": "CmlTapBias1",
+            "min": 0,
+            "max": 400,
+            "step": 100
+        }
+    ],
+    "examples":
+    [
+        {
+            "name": "CmlTapBias0",
+            "min": 300,
+            "max": 900,
+            "step": 100
+        },
+        {
+            "name": "CmlTapBias1",
+            "min": 0,
+            "max": 400,
+            "step": 100
+        },
+        {
+            "name": "SldoAnalogTrim",
+            "min": 20,
+            "max": 26,
+            "step": 1
+        },
+        {
+            "name": "SldoDigitalTrim",
+            "min": 20,
+            "max": 26,
+            "step": 1
+        },
+        {
+            "name": "OutputActiveLanes",
+            "min": 1,
+            "max": 15,
+            "step": 1
+        },
+        {
+            "name": "CmlEn",
+            "min": 1,
+            "max": 7,
+            "step": 6
+        }
+    ]
+}
diff --git a/configs/so_yarr.json b/configs/so_yarr.json
index a4b44b91a49037d7e20e0c6a63e6ea7b85ef3e32..6fc5fcc32b84fad02b50baaa973b43e874a490a2 100644
--- a/configs/so_yarr.json
+++ b/configs/so_yarr.json
@@ -3,33 +3,32 @@
     "common_config":
     {
         "max_trials_in_case_of_failure": 3,
-        "target_preamp": 10000,
-        "reset_pixel_masks": 0
+        "target_preamp": 10000
     },
     "scan_list":
     [
-        ["std_digitalscan"],
-        ["std_analogscan"],
+        ["std_digitalscan", 1],
+        ["std_analogscan", 0],
         ["std_thresholdscan"],
-        ["diff_tune_globalthreshold", 3000],
-        ["diff_tune_pixelthreshold", 3000],
+        ["diff_tune_globalthreshold", 2000],
+        ["diff_tune_pixelthreshold", 2000],
         ["diff_tune_globalpreamp", 7],
-        ["diff_retune_globalthreshold", 3000],
-        ["diff_retune_pixelthreshold", 3000],
+        ["diff_retune_globalthreshold", 2000],
+        ["diff_retune_pixelthreshold", 2000],
         ["diff_thresholdscan"],
         ["diff_totscan"],
         ["lin_tune_globalthreshold", 2000],
         ["lin_tune_pixelthreshold", 2000],
-        ["lin_retune_globalthreshold", 3000],
-        ["lin_retune_pixelthreshold", 3000],
+        ["lin_retune_globalthreshold", 2000],
+        ["lin_retune_pixelthreshold", 2000],
         ["lin_tune_globalpreamp", 7],
-        ["lin_retune_globalthreshold", 3000],
-        ["lin_retune_pixelthreshold", 3000],
+        ["lin_retune_globalthreshold", 2000],
+        ["lin_retune_pixelthreshold", 2000],
         ["lin_thresholdscan"],
         ["lin_totscan"],
-        ["syn_tune_globalthreshold", 3000],
+        ["syn_tune_globalthreshold", 2000],
         ["syn_tune_globalpreamp", 7],
-        ["syn_tune_globalthreshold", 3000],
+        ["syn_tune_globalthreshold", 2000],
         ["syn_thresholdscan"],
         ["syn_totscan"]
     ]
diff --git a/libDCS/__init__.py b/libDCS/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/libDCS/iviscan.py b/libDCS/iviscan.py
index e68434045f6454e84829066ed03ae0e7929a02bd..6a5ff4eff69d50ea0a13eb5b3a7fc10f28292e0f 100644
--- a/libDCS/iviscan.py
+++ b/libDCS/iviscan.py
@@ -6,6 +6,7 @@ import numpy as np
 import time
 import getpass
 from influxdb import InfluxDBClient, exceptions
+import logging, coloredlogs, verboselogs
 
 # LR stuff
 LABREMOTE = 1
@@ -18,31 +19,14 @@ except:
         LABREMOTE = 0
 
 
-
 def sigint_handler(sig, frame):
-    print('[ info ][ ivi ] Received SIGINT. Exiting!')
+    logger.info('Received SIGINT. Exiting!')
     sys.exit(0)
 
 
 signal.signal(signal.SIGINT, sigint_handler)
 
 
-def meas_voltage(hw, ps, args):
-    return ps.measureVoltage()
-
-def power_on(hw, ps, args):
-    if args.voltage_level and args.current_protect:
-        ps.setVoltageLevel(args.voltage_level)
-        ps.setCurrentProtect(args.current_protect)
-    ps.turnOn()
-    return 0
-
-
-def power_off(hw, ps, args):
-    ps.turnOff()
-    return 0
-
-
 def powerPassiveChannels(config, key, what):
     
     if what == "turnOn":
@@ -51,8 +35,7 @@ def powerPassiveChannels(config, key, what):
 
                 ps = hw.getPowerSupplyChannel(elem["name"])
 
-                print()
-                print("setting I to %2g A and V to %2g V on channel %s" % (elem["current"], elem["voltage"], elem["name"]))
+                logger.info("setting I to %2g A and V to %2g V on channel %s" % (elem["current"], elem["voltage"], elem["name"]))
                 ps.setVoltageLevel(elem["voltage"])
                 ps.setCurrentLevel(elem["current"])
 
@@ -65,6 +48,70 @@ def powerPassiveChannels(config, key, what):
                 ps.turnOn()
 
 
+def ramp(varName, pschannel, target, step = None, tsleep = None):
+
+    if varName == "voltage":
+
+        xVarName = "voltage" ; xUnit = "V"
+        yVarName = "current" ; yUnit = "A"
+        measXvar = pschannel.measureVoltage
+        setXvar = pschannel.setVoltageLevel
+        measYvar = pschannel.measureCurrent
+        tolerance = 1 # V
+        if step   is None: step = 5 # V
+        if tsleep is None: tsleep = 1 # s
+
+    elif varName == "current":
+        
+        xVarName = "current" ; xUnit = "A"
+        yVarName = "voltage" ; yUnit = "V"
+        measXvar = pschannel.measureCurrent
+        setXvar = pschannel.setCurrentLevel
+        measYvar = pschannel.measureVoltage
+        tolerance = 0.02 # A
+        if step   is None: step = 0.1 # A
+        if tsleep is None: tsleep = 0.5 # s
+
+    else:
+        logger.error("'varName' can only be 'voltage' or 'current'")
+
+
+    # Get current values of V and I
+    xmeas = measXvar()
+    ymeas = measYvar()
+    #isOn = pschannel.getPowerSupply().isOn(pschannel.getChannel())
+    isOn = (measXvar() != 0 or measYvar() != 0)
+    
+    diff = target - xmeas
+    logging.debug(varName + " difference (target - meas): " + str(diff) + " " + xUnit)
+
+    # Decide whether ramping is finished or not
+    if abs(diff) <= tolerance / 2:
+        logger.info("ramping finished")
+        return xmeas
+
+
+    # determine direction of ramp
+    if diff < 0 and step > 0 or diff > 0 and step < 0 :
+        step = -step
+
+    logger.info("ramping from %.2g %s to %.2g %s in steps of %.2g %s" % (xmeas, xUnit, target, xUnit, step, xUnit))
+
+    while abs(xmeas) >= abs(target)+abs(step) or abs(xmeas) <= abs(target)-abs(step):
+        setXvar(xmeas+step)
+        time.sleep(tsleep)
+        xmeas = measXvar()
+        ymeas = measYvar()
+        logger.debug("PSU is on? " + str(isOn) + "; " + xVarName + ": " + str(xmeas) + " " + xUnit + "; " + yVarName + ": " + str(ymeas) + " " + yUnit)
+    
+    diff = target - xmeas
+    
+    if abs(diff) < abs(step):
+        logging.debug("--------------------")
+        logger.info("[%s, %s] = [%.2g %s, %.2g %s] " % (xVarName, yVarName, xmeas, xUnit, ymeas, yUnit))
+        ramp(xVarName, pschannel, target, step/5.)    
+
+
 def doivi(config, w, dbSink=""):
 
     if w == "iv":
@@ -83,7 +130,7 @@ def doivi(config, w, dbSink=""):
     ch = config[key]["target_channel"]
     ps = hw.getPowerSupplyChannel(ch["name"])
     if ps == None:
-        print("[ error ][ ivi ] change the config and try again!")
+        logger.error("change the config and try again!")
         exit(1)
 
     if w == "iv":
@@ -97,7 +144,7 @@ def doivi(config, w, dbSink=""):
         measYvar = ps.measureVoltage
 
 
-    print("Starting the %s scan..." % w)
+    logger.info("Starting the %s scan..." % w)
 
     if w == "iv": 
         ps.setCurrentProtect(ch["current_protection"])
@@ -127,30 +174,34 @@ def doivi(config, w, dbSink=""):
     data[yKeyOutUnit+"_Compliance"] = config[key]["target_channel"][yVarName+"_protection"]
 
     data[outputKey] = []
-    # < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < 
 
-    # Output to the terminal
-    # > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > 
-    colWidths = "{0:8}{1:17}{2:20}{3:20}{4:20}{5:20}"
-    print(colWidths.format("# time", xVarName + "_Level", xVarName + "_SenseMean", xVarName + "_SenseStd", yVarName + "_SenseMean", yVarName + "_SenseStd"))
-    # < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < 
 
     xVar = ch["initial_" + xVarName]
     step = ch["step_size"]
 
     startX = measXvar()
+    #wasOn = ps.isOn()
+    wasOn = (measXvar() != 0 or measYvar() != 0)
 
-    # Go to the starting point
-    steps = np.linspace(startX, xVar, 10)
-    for e in steps:
-        setXvar(e)
-        time.sleep(1)
 
+    # Ramp to the starting point if PSU is already on
+    if wasOn:
+        ramp(xVarName, ps, xVar)#, 5, 1)
+    else:
+        setXvar(xVar)
+        ps.turnOn()
+
+    # Output to the terminal
+    # > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > 
+    colWidths = "{0:8}{1:17}{2:20}{3:20}{4:20}{5:20}"
+    print(colWidths.format("# time", xVarName + "_Level", xVarName + "_SenseMean", xVarName + "_SenseStd", yVarName + "_SenseMean", yVarName + "_SenseStd"))
+    # < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < 
 
     while (xVar - ch["final_" + xVarName])* step/abs(step) <= 0:
 
         setXvar(xVar)
-        ps.turnOn()
+        if w == "vi":
+            ps.turnOn()
         
         time.sleep(ch["sleeping_time_per_step_s"])
 
@@ -166,7 +217,7 @@ def doivi(config, w, dbSink=""):
             yVarPerStep.append(measY)
 
             if measY > ch[yVarName + "_protection"]:
-                print("Reached " + yVarName + " protection value")
+                logger.warning("Reached " + yVarName + " protection value")
                 break
         else:
 
@@ -208,22 +259,25 @@ def doivi(config, w, dbSink=""):
             xVar += step
 
             # turn everything off (power-cycle the PS)
-            #ps.turnOff()
+            if w == "vi":
+                ps.turnOff()
+
             continue
         break
 
-
-    # Go back to the point before the scans
-    steps = np.linspace(measXvar(), startX, 10)
-    for e in steps:
-        setXvar(e)
-        time.sleep(1)
-
+    with open(args.outfile+"_"+w+".json", "w") as f:
+        json.dump(data, f, indent=4)
+        
+    if w == "iv":
+        # ramp HV outside of IV curve according to module testing document
+        # 2V/s for 3D, 5V/s for planar
+        ramp(xVarName, ps, startX)#, 5, 1)
+        if not wasOn:
+            ps.turnOff()
 
     powerPassiveChannels(config, key, "turnOff")
 
-    with open("output_"+w+".json", "w") as f:
-        json.dump(data, f, indent=4)
+
 
     
 
@@ -255,14 +309,14 @@ def toInfluxDB(points, dbSink, host='localhost', port=8086):
 
         # If auth is enabled, ask the user for his/her password
         if "authorization failed" in str(e):
-            print("[ warn ] Input the password for user \"{}\" in InfluxDB.\n" 
+            logger.warning("Input the password for user \"{}\" in InfluxDB.\n" 
                   "         If you don\'t want to input the password in the future until\n"
                   "         you close your current bash session use \n"
                   "                  \"export INFLUXDBPWD=yourPassword\".".format(usr))
             try:
                 pwd = getpass.getpass()
-            except:
-                print()
+            except Exception as e:
+                logger.error(e)
                 sys.exit(1)
 
     # And connect again.
@@ -279,8 +333,8 @@ def toInfluxDB(points, dbSink, host='localhost', port=8086):
     except exceptions.InfluxDBClientError as e:
 
         # If not, let the user know what's happening and exit.
-        print("[ error ] Received error from InfluxDB: {}".format(e))
-        print("[ info ] Please specify the db connectivity parameters "
+        logger.error("Received error from InfluxDB: {}".format(e))
+        logger.info("Please specify the db connectivity parameters "
                 "\"database\", and also \"username\", " 
                 "\"host\" and \"port\" in the .\"influxdb_cfg\" section in" 
                 "the provided DCS config file. Make sure the provided username and password are correct.\n")
@@ -290,11 +344,15 @@ def toInfluxDB(points, dbSink, host='localhost', port=8086):
     try:
         client.write_points(points)
     except exceptions.InfluxDBClientError as e:
-        print("[ error ] Received error from InfluxDB: {}".format(e))
+        logger.error("Received error from InfluxDB: {}".format(e))
         sys.exit(1)
 
 
 if __name__ == "__main__":
+    
+    coloredlogs.install(level="INFO") ### controls availability of colored logs
+    logger = verboselogs.VerboseLogger('ivi')
+
 
     parser = argparse.ArgumentParser()
     parser.add_argument(
@@ -306,8 +364,9 @@ if __name__ == "__main__":
     parser.add_argument(
         "-j",
         "--json",
-        required=True,
-        help="path to iviscan.json",
+        required=False,
+        default="configs/lr_iviscan.json",
+        help="path to iviscan.json. Default is \"configs/lr_iviscan.json\"",
     )
     parser.add_argument(
         "-e",
@@ -315,8 +374,23 @@ if __name__ == "__main__":
         required=True,
         help="powersupply.json Configuration file with the power supply definition",
     )
-
+    parser.add_argument(
+        "-o",
+        "--outfile",
+        required=False,
+        default="output",
+        help="output file name without file extension. Will be saved in .json format. Default is \"output\"",
+    )
+    parser.add_argument(
+        "-u",
+        "--upload",
+        required=False,
+        action="store_true",
+        help="If set will upload data to influxDB. \"influxdb_cfg\" required in powersupply.json",
+    )
+    
     args = parser.parse_args()
+    logger.debug(args)
 
     # - - - - - - - - - -
     with open(args.json) as f:
@@ -339,20 +413,16 @@ if __name__ == "__main__":
             try:
                 import _labRemote as labRemote
             except:
-                print("Couldn't find the labRemote Python libraries. Make sure to add them to your $PYTHONPATH first by either doing")
-                print()
-                print("     export PYTHONPATH=/path/to/labRemote/build/lib:$PYTHONPATH")
-                print()
-                print("  or writing \"/path/to/labRemote/build/lib\" in \"" + args.equip + "\"")
-                print()
-                print("And make sure also that you have previously built labRemote enabling the Python bindings (cmake3 -DUSE_PYTHON=on)")
+                logger.error("Couldn't find the labRemote Python libraries")
+                logger.info("Make sure to add them to your $PYTHONPATH first by either doing")
+                logger.info("    export PYTHONPATH=/path/to/labRemote/build/lib:$PYTHONPATH")
+                logger.info("    or writing \"/path/to/labRemote/build/lib\" in \"" + args.equip + "\"")
+                logger.info("Also make sure labRemote is built with Python bindings (cmake3 -DUSE_PYTHON=on)")
                 exit(1)
 
-
-
-    uploadToInflux = False
-    if uploadToInflux:
-        #dbSink = psConfig["influxdb_cfg"]
+    
+    if args.upload:
+        dbSink = psConfig["influxdb_cfg"]
         pass
     else:
         dbSink = ""
diff --git a/libDCS/parameterOptimizer.py b/libDCS/parameterOptimizer.py
new file mode 100644
index 0000000000000000000000000000000000000000..975ce2a049852a6b9aaa6f6616a7c1e5bb6ce009
--- /dev/null
+++ b/libDCS/parameterOptimizer.py
@@ -0,0 +1,370 @@
+import numpy as np
+from random import randint
+from prettytable import PrettyTable
+from time import sleep
+import json
+import argparse
+import subprocess
+import sys, os
+import signal
+
+
+def signal_handler(sig, frame):
+    """Capture SIGINT (ctrl C)"""
+
+    print('done')
+    sys.exit(0)
+signal.signal(signal.SIGINT, signal_handler)
+
+
+def count0(enMaskPath):
+    """Counts disabled pixels in EnMask
+
+    Args:
+        enMaskPath (str): path to enMask
+
+    Returns:
+        int: number of bad pixels (-1 if scan failed)
+    """
+
+    badPixels = 0
+
+    try:
+        with open(enMaskPath) as file1:
+
+            data = json.load(file1)
+            for y in data["Data"]:
+                badPixels += y.count(0)
+            
+
+
+        return float(badPixels)
+    except:
+        return -1
+
+
+def whereToGoNext(x, y, M):
+    candidateX = []
+    candidateY = []
+
+    #print(x, y, M[x][y])
+    radius = 1
+    while candidateX == []:
+        for a in range(-radius, radius):
+            for b in range(-radius, radius):
+                if x + a > -1 and y + b > -1:
+                    try:
+                        if M[x + a][y + b] == ' ':
+                            candidateX.append(x + a)
+                            candidateY.append(y + b)
+                    except:
+                        pass
+
+        if radius > max(len(M), len(M[0])): 
+            print("scan finished")
+            return None, None
+        radius += 1
+
+    i = randint(0, len(candidateX) -1)
+    return candidateX[i], candidateY[i]
+
+
+def updatecfg(args, chipName, name_v1, name_v2, v1range, v2range, xtest, ytest):
+    """Modifies name_v1 and name_v2 in Yarr's cfg"""
+
+    chipCfg = args.basepath + "/configs/rd53a/" + args.module + "/" + chipName + ".json"
+    with open(chipCfg, 'r') as f:
+        cfg = json.load(f)
+        cfg["RD53A"]["GlobalConfig"][name_v1] = v1range[xtest]
+        cfg["RD53A"]["GlobalConfig"][name_v2] = v2range[ytest]
+
+    with open(chipCfg, 'w') as f:
+        json.dump(cfg, f, indent=4)
+
+
+def find(args):
+    """Finds a minimum amongst some setting parameters"""
+
+    print("[ info ][po] Making sure the initial chip config is consistent with the SO's one..." ) 
+    cmd = args.basepath + "/ScanOperator.sh -m " + args.module + " -j"
+    process = subprocess.Popen(cmd.split())
+    output, error = process.communicate()
+
+    optCfg = args.json
+
+    # Read CL arguments
+    with open(optCfg) as f:
+        cfg = json.load(f)
+
+        targetChipNumber = cfg["targetChipNumber"]
+        nReps = cfg["repetitions"]
+
+        # var 1
+        name_v1 = cfg["parameters"][0]["name"]
+        min_v1 = int(cfg["parameters"][0]["min"])
+        max_v1 = int(cfg["parameters"][0]["max"])
+        stp_v1 = int(cfg["parameters"][0]["step"])
+
+        # var 2
+        name_v2 = cfg["parameters"][1]["name"]
+        min_v2 = int(cfg["parameters"][1]["min"])
+        max_v2 = int(cfg["parameters"][1]["max"])
+        stp_v2 = int(cfg["parameters"][1]["step"])
+    
+    # Build matrix
+    v1range = [int(x) for x in range(min_v1, max_v1+1, stp_v1)]
+    v2range = [int(y) for y in range(min_v2, max_v2+1, stp_v2)]
+
+    results = [[' ' for a in range(len(v2range))] for b in range(len(v1range))]
+
+    # Randomly decide the three first testing points
+    xtest0 = []
+    ytest0 = []
+
+    for i in range(3):
+        xtest0.append(randint(0, len(v1range) - 1))
+        ytest0.append(randint(0, len(v2range) - 1))
+
+    # get path to so_modules.json
+    cfgIndex = args.basepath + "/configs/so_index.json"
+    with open(cfgIndex) as f:
+        cfg = json.load(f)
+        soCfgPath = cfg["module_config"]
+
+    # Get chip Name
+    with open(soCfgPath) as f:
+        cfg = json.load(f)
+        chipName = cfg["modules"][args.module]["chips"][targetChipNumber-1]["Parameter"]["Name"]
+    
+    # Enable only target chip in yarr's connect. config
+    print("\n[ info ][po] Selecting target chip...")
+    connCfg = args.basepath + "/configs/rd53a/" + args.module + "/connectivity.json"
+    with open(connCfg, 'r') as f:
+        cfg = json.load(f)
+        for i in range(len(cfg["chips"])):
+            if i == targetChipNumber - 1:
+                cfg["chips"][i]["enable"] = 1
+                print("[ info ][po]   Enabled  chip " + str(i)) 
+
+            else:
+                cfg["chips"][i]["enable"] = 0
+                print("[ info ][po]   Disabled chip " + str(i))
+
+    with open(connCfg, 'w') as f:
+        json.dump(cfg, f, indent=4)
+
+
+    # Create some environmental variables
+    os.environ['SCANCFG'] = args.basepath + "/configs/so_yarr.json"
+
+    with open(args.basepath + "/configs/so_yarr.json") as f:
+        cfg = json.load(f)
+        yarrBase =cfg["YARR_directory"]
+
+    os.environ['YARRBASE'] = yarrBase
+    os.environ['SOBASE'] = args.basepath
+    os.environ['SO_RUNNUMBER'] = "optimizer"
+    os.environ['TIMEFILE'] = "/dev/null"
+
+
+    # Run first 3 digital scans
+    for i in range(3):
+        
+        # power cycle
+        if args.powercycle:
+            os.system("python3 libDCS/psOperator.py -e " + args.equip + " -c " + args.channel + " power-off")
+            os.system("python3 libDCS/psOperator.py -e " + args.equip + " -c " + args.channel + " power-on")
+        
+        # change yarr chip cfg
+        updatecfg(args, chipName, name_v1, name_v2, v1range, v2range, xtest0[i], ytest0[i])
+
+        print()
+
+        cmd = args.basepath + "/scanLauncher.sh -m " + args.module + " -s [\"std_digitalscan\",1]"
+
+        # run first digitalScan
+        total = 0
+        for j in range(nReps):
+            print("[ info ][po] Running a digital scan at %i %i...  " % (v1range[xtest0[i]], v2range[ytest0[i]]))
+            process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            output, error = process.communicate()
+            enMaskPath = args.basepath + "/data/optimizer/last_scan/" + chipName + "_EnMask.json"
+
+            count = count0(enMaskPath)
+            print("     -> Counted %i" % count)
+
+            total += count
+
+            if count < 0:
+                total = -1; nReps = 1
+                break
+
+        # Fill the result matrix
+        results[xtest0[i]][ytest0[i]] = total / nReps
+
+
+        # prepare table
+        t = PrettyTable([' '] + [k for k in v2range])
+        for i in range(len(results)):
+            t.add_row([v1range[i]] + results[i])
+
+        t.border = False
+
+        print("")
+        print(t)
+
+    # Three previous points 
+    # TODO: Make this a single 2d array?
+    prev3x = [xtest0[-3], xtest0[-2], xtest0[-1]]
+    prev3y = [ytest0[-3], ytest0[-2], ytest0[-1]]
+    
+    # Update values
+    prev3validY = [prev3x[k] for k in range(len(prev3x)) if results[prev3x[k]][prev3y[k]] > -1]
+    prev3validX = [prev3y[k] for k in range(len(prev3y)) if results[prev3x[k]][prev3y[k]] > -1]
+    lookaround_x = min(prev3validX) if prev3validX != [] else randint(0, len(v1range) - 1)
+    lookaround_y = min(prev3validY) if prev3validY != [] else randint(0, len(v2range) - 1)
+    xtest1, ytest1 = whereToGoNext(lookaround_x, lookaround_y, results)
+
+
+    print("[ info ][po] Entering the loop...")
+    while True:
+
+        updatecfg(args, chipName, name_v1, name_v2, v1range, v2range, xtest1, ytest1)
+
+        # power cycle
+        if args.powercycle:
+            os.system("python3 libDCS/psOperator.py -e " + args.equip + " -c " + args.channel + " power-off")
+            os.system("python3 libDCS/psOperator.py -e " + args.equip + " -c " + args.channel + " power-on")
+
+        print()
+
+        # If we have already tested this point
+        if results[xtest1][ytest1] != ' ':
+
+            # Find another one random
+            xtest1 = randint(0, len(v1range))
+            ytest1 = randint(0, len(v2range))
+
+            continue
+
+
+
+        # Run digitalScan
+        total = 0
+        for j in range(nReps):
+            print("[ info ][po] Testing %i %i..." % (v1range[xtest1], v2range[ytest1]))
+            process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            output, error = process.communicate()
+            enMaskPath = args.basepath + "/data/optimizer/last_scan/" + chipName + "_EnMask.json"
+
+            count = count0(enMaskPath)
+            print("     -> Counted %i" % count)
+
+            total += count
+
+            if count < 0:
+                total = -1; nReps = 1
+                break
+
+        # Fill the result matrix
+        results[xtest1][ytest1] = total / nReps
+
+
+        # Update list of previous 3 tested points
+        prev3x = [prev3x[-2], prev3x[-1], xtest1]
+        prev3y = [prev3y[-2], prev3y[-1], ytest1]
+
+
+        # Decide where to go next
+        prev3validY = [prev3x[k] for k in range(len(prev3x)) if results[prev3x[k]][prev3y[k]] > -1]
+        prev3validX = [prev3y[k] for k in range(len(prev3y)) if results[prev3x[k]][prev3y[k]] > -1]
+        xtest1, ytest1 = whereToGoNext(lookaround_x, lookaround_y, results)
+
+
+        # prepare table
+        print("haxis: %s; vaxis: %s" % (name_v2, name_v1))
+
+        t = PrettyTable(['#'] + [k for k in v2range])
+        for i in range(len(results)):
+            t.add_row([v1range[i]] + results[i])
+
+        t.border = False
+
+        print("")
+        print(t)
+
+        # If the matrix is filled
+        if xtest1 == None:
+            print()
+            print("[ info ][po] Resetting the chip configs to their original value...") 
+            cmd = args.basepath + "/ScanOperator.sh -m " + args.module + " -j"
+            process = subprocess.Popen(cmd.split())
+            output, error = process.communicate()
+            return
+
+
+
+
+
+if __name__ == "__main__":
+
+    parser = argparse.ArgumentParser()
+
+    parser.add_argument(
+        "-b",
+        "--basepath",
+        default=".",
+        help="Path to the SO",
+    )
+    parser.add_argument(
+        "-e",
+        "--equip",
+        help="Configuration file with the power supply definition",
+    )
+    parser.add_argument(
+        "-c",
+        "--channel",
+        help="channel name"
+    )
+    parser.add_argument(
+        "-j",
+        "--json",
+        help="path to so_optimizer.json"
+    )
+    parser.add_argument(
+        "-m",
+        "--module",
+        help="module name"
+    )
+    parser.add_argument(
+        "-p",
+        "--powercycle",
+        action='store_true',
+        help="powercycle"
+    )
+
+    args = parser.parse_args()
+
+    if not args.json:
+        print("option '-j' is mandatory")
+        parser.print_help()
+        sys.exit(1)
+
+    if not args.json:
+        print("option '-c' is mandatory")
+        parser.print_help()
+        sys.exit(1)
+
+    if not args.module:
+        print("option '-m' is mandatory")
+        parser.print_help()
+        sys.exit(1)
+
+    if args.powercycle:
+        if not args.equip or not args.channel:
+            print("options '-e' and '-c' are mandatory when using '-p'")
+            parser.print_help()
+            sys.exit(1)           
+
+
+    find(args)
\ No newline at end of file
diff --git a/libDCS/qaqc.py b/libDCS/psOperator.py
similarity index 99%
rename from libDCS/qaqc.py
rename to libDCS/psOperator.py
index 808dadb970acbae357141c2087d843c2ac98f9de..a9442dc7e58205f3d107484a0d4747c8bd66e86a 100644
--- a/libDCS/qaqc.py
+++ b/libDCS/psOperator.py
@@ -39,7 +39,7 @@ dpColumnName = "Dew Point (ch.Carrier in) [C]"
 # e.g. calls
 
 # M the PS until killed (use with screen, etc)
-#    python3 libDCS/qaqc_dev.py -e configs/lr_powersupply.json -c LV -d configs/idb_dcs.json -i measure
+#    python3 libDCS/psOperator.py -e configs/lr_powersupply.json -c LV -d configs/idb_dcs.json -i measure
 
 
 
diff --git a/libDCS/read_dcs_background.sh b/libDCS/read_dcs_background.sh
index 75fe0dd5cd3feecd5449eda5fe13f41dccc9e444..c625ee9e717d546a35c4351d4835d0a993ac3702 100755
--- a/libDCS/read_dcs_background.sh
+++ b/libDCS/read_dcs_background.sh
@@ -18,7 +18,7 @@ nMeasurements=0
 while [ "$(<$SOBASE/.counters/dcsStat)" == "1" ]
 do
     
-    python3 $SOBASE/libDCS/qaqc.py -e $1 -c $chn -d $2 measure
+    python3 $SOBASE/libDCS/psOperator.py -e $1 -c $chn -d $2 measure
     echo "[ info ][dm] DCS measurement performed"
     ((nMeasurements=nMeasurements+1))
 
diff --git a/libYarr/call_dbAccessor.sh b/libYarr/call_dbAccessor.sh
deleted file mode 100755
index 1409cbd4d8a0583b26a20471293284075aca8172..0000000000000000000000000000000000000000
--- a/libYarr/call_dbAccessor.sh
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/bin/bash
-
-tmp=$(cd $(dirname $0);cd ..; pwd)
-source $tmp/script/setup.sh
-source $tmp/lib/func.sh
-
-function usage(){
-    cat <<EOF                                                                                                                                                                                     
-Help:
-  -c <path> : YARR connectivity file
-  -s <path> : scan log file
-  -C <path> : connectivity file for InfluxDB
-EOF
-    exit
-}
-
-while getopts c:s:C: OPT
-do
-    case $OPT in
-        c) yarr_connectivity=$OPTARG ;;
-        s) scanlog=$OPTARG;;
-        C) influx_connectivity=$OPTARG ;;
-        *) usage ;;
-    esac
-done
-if [ "$yarr_connectivity" == "" ];then
-    usage;
-fi
-if [ "$scanlog" == "" ];then
-    usage;
-else
-    scanlog_dir=$(dirname $scanlog)
-    if [ -L $scanlog_dir ];then
-	scanlog_filename=${scanlog##*/}
-	scanlog=$(readlink -f $scanlog_dir)"/${scanlog_filename}"
-    fi
-fi
-#if [ "$influx_connectivity" == "" ];then
-#    usage;
-#fi
-item_list=("$yarr_connectivity" "$scanlog")
-for item in ${item_list[@]}
-do
-    if [ ! -e $item ]; then
-	echo $item
-        usage;
-    fi
-done
-
-i=0;
-connectivity=""
-#influx_connectivity_seed="${tmp}/configs/influxDB/connectivity_chipID"
-influx_connectivity="${tmp}/configs/influxDB/connectivity.json"
-
-#$YARR_DIR/bin/dbAccessor -F $influx_connectivity -n "OU078B_chip1" -s $scanlog
-
-while [ $i -eq 0 ] || [ ! "$connectivity" == "" ]
-do 
-    connectivity=$(get_json_item $yarr_connectivity .chips[$i])
-    if [ ! "$connectivity" == "" ];then
-	chipname=$(get_json_item $yarr_connectivity .chips[$i].serialNumber)
-	chipID=$(get_json_item $yarr_connectivity .chips[$i].chipId)
-	#influx_connectivity=${influx_connectivity_seed}"${chipID}.json"
-
-	echo "$YARR_DIR/bin/dbAccessor -F $influx_connectivity -n $chipname -s $scanlog"
-	$YARR_DIR/bin/dbAccessor -F $influx_connectivity -n $chipname -s $scanlog
-    fi
-    i=$((i+1))
-done
-
diff --git a/libYarr/createDefaultConfig.sh b/libYarr/createDefaultConfig.sh
deleted file mode 100755
index 6e93ea9287709c2df6c4898b23d975ac0ca4bcd4..0000000000000000000000000000000000000000
--- a/libYarr/createDefaultConfig.sh
+++ /dev/null
@@ -1,202 +0,0 @@
-#!/bin/bash
-#################################
-# Contacts: Eunchong Kim, Arisa Kubota
-# Email: eunchong.kim at cern.ch, arisa.kubota at cern.ch
-# Date: April 2019
-# Project: Local Database for Yarr
-# Description: Create config file 
-# Usage: ./createConfig.sh [-a <rd53a/fei4b>*] [-m <SerialNumber>*] [-c <ChipNum>] [-r <ControllerCfg>] [-d] [-R]
-################################
-### setting YARR ###############                                                                                
-
-
-cd $YARR_DIR/configs
-mkdir -p chipConfigs
-################################         
-
-# Change fixed tx channel and rx start channel
-tx_fix=0
-rx_start=0
-
-# default parameters
-reset=false
-account=false
-now=`date +"%y%m%d%H%M"`
-
-# Usage
-function usage {
-    cat <<EOF
-
-Usage:
-    ./$(basename ${0}) [-a <rd53a/fei4b>*] [-m SN*] [-c Chips] [-r Controller] [-d] [-R]
-
-Options:
-    -a <rd53a/fei4b>  asic type (*req.)
-    -m <str>          serial number (*req.)
-    -c <int>          number of chips (req. in first creation)
-    -r <path>         controller config file   default: ./controller/specCfg.json
-    -d                upload into databse
-    -R                reset all config files
-
-EOF
-}
-
-while getopts a:m:c:r:dRI: OPT
-do
-    case ${OPT} in
-        a ) asic=${OPTARG} ;;
-        m ) sn=${OPTARG} ;;
-        c ) chips=${OPTARG} ;;
-        r ) controller=${OPTARG} ;;
-        d ) account=true ;;
-        R ) reset=true ;;
-        * ) usage
-            exit ;;
-    esac
-done
-
-# asic type
-if [ -z ${asic} ]; then
-    echo "Please give \"rd53a\" or \"fei4b\" with '-a'."
-    usage
-    exit
-elif [ ${asic} == "rd53a" ]; then
-    chiptype="RD53A"
-    chipid="ChipId"
-    name="Name"
-    john="JohnDoe_0"
-elif [ ${asic} == "fei4b" ]; then
-    chiptype="FEI4B"
-    chipid="chipId"
-    name="name"
-    john="JohnDoe"
-else
-    echo "Please give \"rd53a\" or \"fei4b\" with '-a'."
-    usage
-    exit
-fi
-
-# serial number
-if [ -z ${sn} ]; then
-    echo "Please give serial number with '-m'."
-    usage
-    exit
-fi
-
-# Make directory for module data in ScanOperator
-
-mkdir -p $SOBASE/configs/${asic}/${sn}
-echo -e "Created dir: $SOBASE/configs/${asic}/${sn}"
-
-# Make directory for config file
-#if [ -f $YARR_DIR/configs/connectivity/connectivity.json ]; then
-
-# chips
-if [ -z ${chips} ]; then
-    echo "Please give the number of chips with '-c'."
-    usage
-    exit
-fi
-echo ${chips} | grep [^0-9] > /dev/null 2>&1
-if [ $? -eq 0 ]; then
-    echo "Please give an integral as number of chips with '-c'. "
-    usage
-    exit
-fi
-
-# controller config
-if [ -z ${controller} ]; then
-    controller=controller/specCfg.json
-fi
-if [ ! -f ${controller} ]; then
-    echo "Not exist controller \"${controller}\"."
-    usage
-    exit
-fi
-
-cnt=0
-chipIds=()
-chipNames=()
-while [ ${cnt} -lt ${chips} ]; do
-    chipName="${sn}_chip${cnt}"
-    echo "Create ${YARR_DIR}/configs/chipConfigs/${chipName}.json"
-    chipNames+=( ${chipName} )
-    #echo "Set chipId for chip${cnt}... [#(chipId)] "
-    #read answer
-    #unset id
-    id=$(jq -j '.modules.'"${sn}.chips[$cnt].id" $CFGFILE)
-    cnt=$(( cnt + 1 ))
-    chipIds+=( ${id} )
-done
-echo "---------------------"
-
-# Confirmation
-cnt=0
-echo " "
-echo "serial number:     ${sn}"
-echo "controller config: ${controller}"
-echo "number of chips:   ${chips}"
-while [ ${cnt} -lt ${chips} ]; do
-    cnt=$(( cnt + 1 ))
-    echo "** ${sn}_chip${cnt}"
-    echo "    chip serial number: ${chipNames[$((cnt-1))]}"
-    echo "    chipId: ${chipIds[$((cnt-1))]}"
-done
-echo " "
-read -n 1 -s -r -p "Press any key to continue"
-echo ""
-
-# Make controller for this module
-if [ ${controller} != $SOBASE/configs/${asic}/${sn}/controller.json ]; then
-    echo "Created ${YARR_DIR}/configs/controller/${sn}_controller.json"
-    #cp ${controller} ${YARR_DIR}/configs/controller/${sn}_controller.json
-    #ln -s ${YARR_DIR}/configs/controller/${sn}_controller.json $SOBASE/configs/${asic}/${sn}/controller.json
-    cp ${controller} $SOBASE/configs/${asic}/${sn}/controller.json
-fi
-
-# Make connectivity.json
-echo "Created $SOBASE/configs/$asic/$sn/connectivity.json"
-echo "{" > $SOBASE/configs/$asic/$sn/connectivity.json
-echo "    \"stage\": \"Testing\"," >> $SOBASE/configs/$asic/$sn/connectivity.json
-echo "    \"module\": {" >> $SOBASE/configs/$asic/$sn/connectivity.json
-echo "        \"serialNumber\": \"${sn}\"," >> $SOBASE/configs/$asic/$sn/connectivity.json
-echo "        \"componentType\": \"Module\"" >> $SOBASE/configs/$asic/$sn/connectivity.json
-echo "    }," >> $SOBASE/configs/$asic/$sn/connectivity.json
-echo "    \"chipType\" : \"${chiptype}\"," >> $SOBASE/configs/$asic/$sn/connectivity.json
-
-cnt=0
-echo "    \"chips\" : [" >> $SOBASE/configs/$asic/$sn/connectivity.json
-while [ ${cnt} -lt ${chips} ]; do
-    cnt=$(( cnt + 1 ))
-    echo "Created ${sn}_chip${cnt}.json"
-
-    cp defaults/default_${asic}.json $SOBASE/configs/${asic}/${sn}/${sn}_chip${cnt}.json
-    sed -i "/${chipid}/s/0/${chipIds[$((cnt-1))]}/g" $SOBASE/configs/${asic}/${sn}/${sn}_chip${cnt}.json
-    sed -i "/${name}/s/JohnDoe_0/${chipNames[$((cnt-1))]}/g" $SOBASE/configs/${asic}/${sn}/${sn}_chip${cnt}.json
-
-    rx_ch=$(( cnt - 1 + rx_start ))
-    echo "        {" >> $SOBASE/configs/$asic/$sn/connectivity.json
-    echo "            \"serialNumber\": \"${chipNames[$((cnt-1))]}\"," >> $SOBASE/configs/$asic/$sn/connectivity.json
-    echo "            \"componentType\": \"Front-end Chip\"," >> $SOBASE/configs/$asic/$sn/connectivity.json
-    echo "            \"chipId\": ${chipIds[$((cnt-1))]}," >> $SOBASE/configs/$asic/$sn/connectivity.json
-    echo "            \"config\" : \"$SOBASE/configs/${asic}/${sn}/${sn}_chip${cnt}.json\"," >> $SOBASE/configs/$asic/$sn/connectivity.json
-    echo "            \"tx\" : ${tx_fix}," >> $SOBASE/configs/$asic/$sn/connectivity.json
-    echo "            \"rx\" : ${rx_ch}" >> $SOBASE/configs/$asic/$sn/connectivity.json
-    
-    if [ ${cnt} -ne ${chips} ]; then
-        echo "        }," >> $SOBASE/configs/$asic/$sn/connectivity.json
-    else
-        echo "        }" >> $SOBASE/configs/$asic/$sn/connectivity.json
-    fi
-done
-echo "    ]" >> $SOBASE/configs/$asic/$sn/connectivity.json
-echo "}" >> $SOBASE/configs/$asic/$sn/connectivity.json
-
-
-cd ../
-
-# Register module and chips component to DB
-if [ ! -z ${account} ]; then
-    echo "./bin/dbAccessor -C -c $SOBASE/configs/$asic/$sn/connectivity.json"
-    ./bin/dbAccessor -C -c $SOBASE/configs/$asic/$sn/connectivity.json 
-fi
diff --git a/scanLauncher.sh b/scanLauncher.sh
index 452b363f80afa945f0a2216f08e51df2baba8794..570dd02af838ff36178b7247c4de06314f54203e 100755
--- a/scanLauncher.sh
+++ b/scanLauncher.sh
@@ -104,7 +104,14 @@ else
         targetAmpOrCharge=""
     fi
 fi
+# Build Yarr's "-m" option (reset px masks, default -1 (same as in Yarr))
+reset_masks=-1
+if echo "${scanName}" | grep "digital\|analog\|noise" >>/dev/null; then
+    if [[ $(echo $scan | jq '. | length') == 2 ]]; then
+        reset_masks=$(echo $scan | jq -r '.[1]')
+    fi
 
+fi
 ###### Log file  ######################
 RunNumber=$(cat $HOME/.yarr/runCounter)
 RunNumber=$(( RunNumber +  1))
@@ -127,22 +134,20 @@ if [[ $dcsMonitor == 1 ]] ;then
     done
     chn="${chn::-1}"
     
-    python3 $SOBASE/libDCS/qaqc.py -e $PSCFG -c $chn -d $INFLUXDBDCSCFG measure
+    python3 $SOBASE/libDCS/psOperator.py -e $PSCFG -c $chn -d $INFLUXDBDCSCFG measure
     # Tell read_dcs_background.sh that we're performing a scan
     echo "1" > $SOBASE/.counters/dcsStat
 
     $SOBASE/libDCS/read_dcs_background.sh $PSCFG $INFLUXDBDCSCFG &
 fi
-targetCharge=$(jq -j '.scan.target_charge' $SCANCFG)
 
-# Mask option (Yarr's -m)
-reset_masks=$(jq -j '.common_config.reset_pixel_masks' $SCANCFG)
+targetCharge=$(jq -j '.scan.target_charge' $SCANCFG)
 
 ctrlFile="$SOBASE/configs/rd53a/$module_id/controller.json"
 cnctFile="$SOBASE/configs/rd53a/$module_id/connectivity.json"
 
 #ctrlFile="/home/mario/work/yr/configs/controller/emuCfg.json"
-comm="$YARRBASE/bin/scanConsole -r $ctrlFile -c $cnctFile -p -t ${targetAmpOrCharge} ${targetToT} -s ${scanPath} -m $reset_masks $localdbOpt $qcOpt -o $SOBASE/data/$SO_RUNNUMBER" #> /dev/null 2>1
+comm="$YARRBASE/bin/scanConsole -r $ctrlFile -c $cnctFile -p -t ${targetAmpOrCharge} ${targetToT} -s ${scanPath} -m $reset_masks -o $SOBASE/data/$SO_RUNNUMBER $localdbOpt $qcOpt" #> /dev/null 2>1
 echo "[ info ][sl] Calling Yarr's scanConsole"
 echo "[ info ][sl] $comm"
 
@@ -163,7 +168,7 @@ while [ true ]; do
     fi
 
     if [ $retval -ne 0 ] && [ $reps -ge $max_reps ]; then 
-        echo "[ warn ][sl] After $max_reps attempts, couldn't succesfully finish $scanName."
+        echo "[ warn ][sl] After $max_reps attempts, couldn't successfully finish $scanName."
         exit $retval
 
     elif [ $retval -ne 0 ]; then
@@ -178,7 +183,6 @@ echo -ne "$scanName     $elp\n" >> $TIMEFILE
 
 
 
-
 # stop taking data
 if [[ $dcsMonitor == 1 ]] ;then
     echo "[ info ][sl] Stopping data taking"