diff --git a/PositionGaugeServer.ino b/PositionGaugeServer/PositionGaugeServer.ino
similarity index 85%
rename from PositionGaugeServer.ino
rename to PositionGaugeServer/PositionGaugeServer.ino
index fb427b3c701077f431d88075a84f6fa60ba3e2f1..4cf1e6640b23ed6983446e1f02446d580a732cb8 100644
--- a/PositionGaugeServer.ino
+++ b/PositionGaugeServer/PositionGaugeServer.ino
@@ -2,6 +2,13 @@
  * Server for transmitting multiple Mitutoyo position gauge measurements over ethernet.
  * Access via HTTP on TCP port 80, or very simple text protocol (telnet-like), one port per device.
  * 
+ * Example for accessing over text interface (best for machine clients):
+ *  nc 192.168.1.31 21
+ * or
+ *  nc 192.168.1.31 22
+ * Netcat (nc) is the best client: it is a clean TCP client,
+ * which makes no attempts to negotiate anything.
+ *  
  * Kyrre Ness Sjobak, 15 Feb 2021
  * University of Oslo / CERN
  * 
@@ -18,54 +25,13 @@
 #include <SPI.h>
 #include <Ethernet.h>
 
-// ***** Mitutoyo instrument configuration *****
-
-const uint8_t numCh = 2; //How many instruments connected
-                         // Instruments are configured by arrays
-                         // pinREQ / pinDAT / pinCLK / srvTXT_port / srvTXT
-                         // Remember to update if changing the config!
-//Arduino pins
-// Used for Ethernet shield -- AVOID:
-// 4/10/11/12/13 (UNO)
-// 50/51/52/10/4 (Mega)
-const uint8_t pinREQ[numCh] = {5,7};
-const uint8_t pinDAT[numCh] = {2,8};
-const uint8_t pinCLK[numCh] = {3,9};
-
-//Uncomment this to enable the "dummy reader" code instead of the SPC protocol interface
-// This disables the actual reading of the instrument,
-// however pins are still configured on start
-// This enables debugging of the network code if no Mitutoyo instrument is connected.
-//#define DUMMY_READER
-
-// ***** NETWORK CONFIG ************************
-// *** MAC ADDRESS FOR THE ARDUINO ON THE PLASMA-LENS ***
-//byte mac[] = {0xA8, 0x61, 0x0A, 0xAE, 0x84, 0xED};
-
-// *** MAC ADDRESS FOR THE ARDUINO ON THE CLIC STRUCTURE ***
-byte mac[] = {0xA8, 0x61, 0x0A, 0xAE, 0x84, 0xEE};
-
-//To use DHCP or not to use DHCP, that's the question.
-#define USE_DHCP
-
-#ifndef USE_DHCP
-IPAddress ip(192, 168, 1, 177);
-IPAddress myDns(192, 168, 1, 1);
-IPAddress gateway(192, 168, 1, 1);
-IPAddress subnet(255, 255, 0, 0);
-#endif
-
-// ***** OTHER CONFIG ***************************
-const unsigned long update_interval     = 1000; //[ms] How often to loop
-                                                // (poll sensors, check for new network clients,
-                                                //  feed data to network clients, DHCP housekeeping)
-const unsigned long WEB_update_interval = 5;    //[s]  WEB requests are heavy, not too often is good.
-const unsigned long SPC_timeout         = 200;  //[ms] Experimentally verified to be OK.
-const unsigned long WEB_timeout         = 700;  //[ms] Max time allowed waiting for web client
+//This file holds all the configurations
+// to be modified for deployment
+#include "PositionGaugeServer_config.h"
 
 // ***** GLOBAL VARIABLES ***********************
 
-unsigned long prevUpdateTime;
+unsigned long prevUpdateTime = 0;
 
 float measData[numCh];
 bool  measDataFresh[numCh];
@@ -83,16 +49,9 @@ EthernetServer srvTXT[numCh] = {
 EthernetClient clients[MAX_SOCK_NUM];
 uint8_t        clients_ch[MAX_SOCK_NUM]; //which channel does a particular client belong to?
 
+unsigned long srvTXT_prevUpdateTime[numCh];
 
-
-
-
-
-
-
-
-
-// ***** CODE -- DO NOT CHANGE *******************
+// ***** CODE ************************************
 
 void setup() {
 
@@ -178,6 +137,7 @@ void setup() {
   srvWEB.begin();
   for (uint8_t ch = 0; ch<numCh; ch++) {
     srvTXT[ch].begin();
+    srvTXT_prevUpdateTime[ch] = 0;
   }
   
   //General
@@ -192,7 +152,8 @@ void setup() {
   }
 
   
-  Serial.print("Update interval  "); Serial.print(update_interval); Serial.println(" [ms]");
+  Serial.print("Poll interval  "); Serial.print(update_interval); Serial.println(" [ms]");
+  Serial.print("Max. interval  "); Serial.print(srvTXT_max_interval); Serial.println(" [ms]");
   Serial.println();
 }
 
@@ -453,8 +414,9 @@ void HTTPserver () {
         client.println("<p>");
         client.print("IP address:         "); client.print(Ethernet.localIP()); client.println("<br>");
         client.print("No. channels:       "); client.print(numCh); client.println("<br>");
-        client.print("Update interval     "); client.print(update_interval); client.println(" [ms]<br>");
-        client.print("WEB update interval "); client.print(WEB_update_interval); client.println(" [s]<br>");
+        client.print("Poll interval:      "); client.print(update_interval); client.println(" [ms]<br>");
+        client.print("WEB update interval:"); client.print(WEB_update_interval); client.println(" [s]<br>");
+        client.print("Max. interval:      "); client.print(srvTXT_max_interval); client.println(" [ms]");
         client.print("Internal time:      "); client.print(millis()); client.println(" [ms]<br>");
 
         client.println("</p>");
@@ -557,6 +519,10 @@ void TXTserver (uint8_t ch) {
           //clients[i].println(ch);
   
           //Feed the new client some data right away
+          if(measData[ch] >= 0) {
+            //Add the '+' so that the string is always the same length
+            clients[i].print('+');
+          }
           clients[i].print(measData[ch],3);
           if (measDataIsValid[ch]) {
             if (measDataIsMm[ch]) {
@@ -591,10 +557,16 @@ void TXTserver (uint8_t ch) {
     }
   }
   
-  //3. If fresh data is available, send it!
-  if (measDataFresh[ch]) {
+  //3. If fresh data is available or too long since last update, send it!
+  unsigned long timeSinceLastUpdate = millis() - srvTXT_prevUpdateTime[ch];
+  if (measDataFresh[ch] or (timeSinceLastUpdate >= srvTXT_max_interval)) {
+    srvTXT_prevUpdateTime[ch] = millis();
     for (byte i = 0; i < MAX_SOCK_NUM; i++) {
       if (clients[i] && (clients_ch[i]==ch)) {
+        if(measData[ch] >= 0) {
+          //Add the '+' so that the string is always the same length
+          clients[i].print('+');
+        }
         clients[i].print(measData[ch],3);
         if (measDataIsValid[ch]) {
           if (measDataIsMm[ch]) {
@@ -615,12 +587,11 @@ void TXTserver (uint8_t ch) {
   for (byte i = 0; i < MAX_SOCK_NUM; i++) { 
     if ( clients[i] && (clients_ch[i]==ch) && !clients[i].connected() ) {
       clients[i].stop();
-      clients_ch[i]=0;
 
-        Serial.print("Closed connection for ch=");
-        Serial.print(ch);
-        Serial.print(" slot ");
-        Serial.println(i);
+      Serial.print("Closed connection for ch=");
+      Serial.print(ch);
+      Serial.print(" slot ");
+      Serial.println(i);
     }
   }
 }
@@ -669,4 +640,3 @@ void DHCPhousekeeping() {
   }
 }
 #endif
-
diff --git a/PositionGaugeServer/PositionGaugeServer_config.h b/PositionGaugeServer/PositionGaugeServer_config.h
new file mode 100644
index 0000000000000000000000000000000000000000..9472e2a2a49a2a0781477e0bd53da621ffa73728
--- /dev/null
+++ b/PositionGaugeServer/PositionGaugeServer_config.h
@@ -0,0 +1,56 @@
+#ifndef __PositionGaugeServer_config_h__
+#define __PositionGaugeServer_config_h__
+
+// ***** Mitutoyo instrument configuration *****
+
+//Uncomment this to enable the "dummy reader" code instead of the SPC protocol interface
+// This disables the actual reading of the instrument,
+// however pins are still configured on start
+// This enables debugging of the network code if no Mitutoyo instrument is connected.
+//#define DUMMY_READER
+
+const uint8_t numCh = 2; //How many instruments connected
+                         // Instruments are configured by arrays
+                         // pinREQ / pinDAT / pinCLK / srvTXT_port / srvTXT
+                         // Remember to update if changing the config!
+//Arduino pins
+// Used for Ethernet shield -- AVOID:
+// 4/10/11/12/13 (UNO)
+// 50/51/52/10/4; 53 unused but MUST be output (Mega)
+const uint8_t pinREQ[numCh] = {5,7};
+const uint8_t pinDAT[numCh] = {2,8};
+const uint8_t pinCLK[numCh] = {3,9};
+
+// ***** NETWORK CONFIG ************************
+// MAC address for the Arduino on the plasma lens
+//byte mac[] = {0xA8, 0x61, 0x0A, 0xAE, 0x84, 0xED};
+
+// MAC address for the Arduino on the CLIC structure
+//byte mac[] = {0xA8, 0x61, 0x0A, 0xAE, 0x84, 0xEE};
+
+// MAC address for Kyrre's test board
+byte mac[] = {0xA8, 0x61, 0x0A, 0xAE, 0x72, 0xF7};
+
+//To use DHCP or not to use DHCP, that's the question.
+// Comment out to use static IP configuration
+#define USE_DHCP
+
+#ifndef USE_DHCP
+IPAddress ip(192, 168, 1, 177);
+IPAddress myDns(192, 168, 1, 1);
+IPAddress gateway(192, 168, 1, 1);
+IPAddress subnet(255, 255, 0, 0);
+#endif
+
+// ***** OTHER CONFIG ***************************
+const unsigned long update_interval     = 1000; //[ms] How often to loop
+                                                // (poll sensors, check for new network clients,
+                                                //  feed data to network clients, DHCP housekeeping)
+const unsigned long WEB_update_interval = 5;    //[s]  WEB requests are heavy, not too often is good.
+const unsigned long SPC_timeout         = 200;  //[ms] Experimentally verified to be OK.
+const unsigned long WEB_timeout         = 700;  //[ms] Max time allowed waiting for web client
+
+const unsigned long srvTXT_max_interval = 10000;//[ms] At least try to give an update this often
+
+
+#endif
diff --git a/epicsIOC/db/positionGauge.db b/epicsIOC/db/positionGauge.db
new file mode 100644
index 0000000000000000000000000000000000000000..0605e57f47ad213bfea58425b2b78c290d02132e
--- /dev/null
+++ b/epicsIOC/db/positionGauge.db
@@ -0,0 +1,26 @@
+#record (stringin, "$(SYSDEV)MSG")
+#{
+#}
+
+record (ai, "$(SYSDEV):POS")
+{
+    field(DESC, "Gauge position")
+    field(DTYP, "stream")
+    field( INP, "@positionGauge.proto read_pos $(PORT)")
+    field(PREC, ".001") #display precision
+    field( EGU, "mm")
+#TODO: This one is the value, and :UNIT is the unit.
+#      If unit is XX, then the value may be stale
+#      (indicates an unsuccessful instrument read)
+#    field(EGU , $(SYSDEV):UNIT)
+    field(SCAN, "I/O Intr")
+}
+record (stringin, "$(SYSDEV):UNIT")
+{
+    field(DESC, "Gauge position")
+    field(DTYP, "stream")
+    field( INP, "@positionGauge.proto read_unit $(PORT)")
+#    field( EGU, "")
+    field(SCAN, "I/O Intr")
+}
+
diff --git a/epicsIOC/db/positionGauge.proto b/epicsIOC/db/positionGauge.proto
new file mode 100644
index 0000000000000000000000000000000000000000..49be664b381c7f7fae5baf941ef19c56573e8ab5
--- /dev/null
+++ b/epicsIOC/db/positionGauge.proto
@@ -0,0 +1,24 @@
+# EPICS StreamDevice driver for
+# CLEAR's positionGaugeServer
+# https://gitlab.cern.ch/CLEAR/arduino-positiongaugeserver/
+# Developed using ESS E3 EPICS
+#
+# Kyrre Sjobak, May 2021
+#
+# Ouput format:
+# I.e. 
+# '+0.000XX\r\n'
+#
+Terminator   = CR LF;
+ReplyTimeout = 15000;
+ReadTimeout  = 300;
+
+read_pos
+{
+    in "%!6f%*2s";
+}
+
+read_unit
+{
+    in "%!*6f%2s";
+}
diff --git a/epicsIOC/st.cmd b/epicsIOC/st.cmd
new file mode 100644
index 0000000000000000000000000000000000000000..a3158e3b36d567c0bde9b61917400f0f7d70c28a
--- /dev/null
+++ b/epicsIOC/st.cmd
@@ -0,0 +1,21 @@
+require stream
+#require iocstats
+
+epicsEnvSet("TOP" "$(E3_CMD_TOP)")
+epicsEnvSet("STREAM_PROTOCOL_PATH", ".:$(TOP)/db")
+
+#CONNECTION CONFIGURATION
+epicsEnvSet("IOCNAME", "TESTGAUGES")
+epicsEnvSet("ARDUINO_IP", "192.168.1.31")
+epicsEnvSet("PORT_X", "21")
+epicsEnvSet("PORT_Y", "22")
+
+drvAsynIPPortConfigure("CONN_X", "$(ARDUINO_IP):$(PORT_X)", 0, 0, 0)
+drvAsynIPPortConfigure("CONN_Y", "$(ARDUINO_IP):$(PORT_Y)", 0, 0, 0)
+
+dbLoadRecords("$(TOP)/db/positionGauge.db", "SYSDEV=$(IOCNAME):X,PORT=CONN_X")
+dbLoadRecords("$(TOP)/db/positionGauge.db", "SYSDEV=$(IOCNAME):Y,PORT=CONN_Y")
+
+dbLoadRecords("iocAdminSoft.db","IOC=$(IOCNAME):IocStat")
+
+iocInit()
diff --git a/readme.md b/readme.md
index bc3b4e32b7111e40062532e8745fd95e531eb147..7ab25a3e0596e6b61c8f9bf2ac97dee789ccee5b 100644
--- a/readme.md
+++ b/readme.md
@@ -1,16 +1,29 @@
 # Arduino Position gauge server
 
-By K.Sjobak, A.Gilardi, P.Korysko, and W.Farabolini
+By K. Sjobak, A. Gilardi, P. Korysko, and W. Farabolini
 
 This code allows connecting multiple Mitutoyo position gauges to an Ethernet IP network, and transmit new readings to the connected clients.
 The transmission is done over one TCP channel pr. gauge, per default running on port 21 and 22.
 Additionally, a simple web/HTTP server is provided in order to check the status of the system.
 
-The code is fully contained in the file `PositionGaugeServer.ino`.
-It depends on only the standard Arduino libraries and the Ethernet library in order to support the Ethernet shield .
-It is tested and deployed with an Arduino Uno and a Ethernet Shield v2, connected to two gauges (model nr?).
-The code can be configured to support a variable number of gauges, network configurations, Arduino pinouts, and update intervals and timeouts by editing the **top** part of `PositionGaugeServer.ino`; the bottom part will reconfigure automatically.
-Note that for any deployment you **must** set the correct MAC address in the code file.
+To connect to standard readout method, use netcat as follows (assuming the IP address is `192.168.1.31`; hostname can also be used here):
+* `nc 192.168.1.31 21` For the horizontal channel
+* `nc 192.168.1.31 22` For the vertical channel
+
+To connect to web interface, point your web browser at (note http, not https):
+* `http://192.168.1.31/`
+
+The code logic and global variable definition is contained in the file `PositionGaugeServer.ino`.
+The configuration which must be changed by the user needs for each deployment is contained in the header file `PostionGaugeServer_config.h`, both in the `PositionGaugeServer` folder, and includes:
+* Ethernet MAC address (**must** be set differently for each deployment)
+* DHCP or fixed IP configuration
+* Refresh intervals
+* Timeouts
+* Number of gauges to connect
+* Pins to use for communication with gauges
+
+The project only depends on the standard Arduino libraries and the Ethernet library in order to support the Ethernet shield .
+It is tested and deployed with an Arduino Uno and a Ethernet Shield v2, connected to two gauges, as shown in the picture below.
 
 The schematic for the connection to the gauge (provided by Roger Cheng) looks like:
 ![Simple schematic](/schematic.png)