diff --git a/psconfig.cc b/psconfig.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e087d381b5d20a34c265b86c9b4b6b0814c26234
--- /dev/null
+++ b/psconfig.cc
@@ -0,0 +1,149 @@
+#include "PowerSensor.h"
+
+#include <unistd.h>
+
+#include <cstring>
+#include <iostream>
+#include <memory>
+
+
+std::unique_ptr<PowerSensor::PowerSensor> powerSensor;
+int sensor = 0;
+
+
+float convertType(const char *arg)
+{
+  if (strcmp(arg, "ACS712-5") == 0 || strcmp(arg, "acs712-5") == 0)
+    return 0.185;
+  else if (strcmp(arg, "ACS712-20") == 0 || strcmp(arg, "acs712-20") == 0)
+    return 0.1;
+  else if (strcmp(arg, "ACS712-30") == 0 || strcmp(arg, "acs712-30") == 0)
+    return 0.66;
+  else
+    return atof(arg);
+}
+
+
+PowerSensor::PowerSensor *checkPowerSensor()
+{
+  if (powerSensor.get() == nullptr)
+    powerSensor = std::unique_ptr<PowerSensor::PowerSensor>(new PowerSensor::PowerSensor("/dev/ttyACM0"));
+
+  return powerSensor.get();
+}
+
+
+void measureSensors(PowerSensor::State &startState, PowerSensor::State &stopState)
+{
+  startState = powerSensor->read();
+  sleep(2);
+  stopState = powerSensor->read();
+}
+
+
+void autoCalibrate()
+{
+  if (powerSensor->inUse(sensor)) {
+    PowerSensor::State startState, stopState;
+
+    powerSensor->setNullLevel(sensor, 0);
+    measureSensors(startState, stopState);
+    powerSensor->setNullLevel(sensor, PowerSensor::Watt(startState, stopState, sensor));
+  }
+}
+
+
+bool approximates(float a, float b)
+{
+  return a / b > .999999 && a / b < 1.000001;
+}
+
+
+std::string type(unsigned sensor)
+{
+  float voltPerAmpere = powerSensor->getType(sensor);
+
+  if (approximates(voltPerAmpere, .185))
+    return "ACS712-5";
+  else if (approximates(voltPerAmpere, .1))
+    return "ACS712-20";
+  else if (approximates(voltPerAmpere, .66))
+    return "ACS712-30";
+  else
+    return std::to_string(voltPerAmpere) + " V/A";
+}
+
+
+void print()
+{
+  PowerSensor::State startState, stopState;
+
+  measureSensors(startState, stopState);
+
+  for (unsigned sensor = 0; sensor < PowerSensor::MAX_SENSORS; sensor ++)
+    if (powerSensor->inUse(sensor))
+      std::cout << "sensor: " << sensor << ", "
+		   "volt: " << powerSensor->getVolt(sensor) << " V, "
+		   "type: " << type(sensor) << ", "
+		   "null level: " << powerSensor->getNullLevel(sensor) << " W, "
+		   "current usage: " << Watt(startState, stopState, sensor) << " W" << std::endl;
+    else
+      std::cout << "sensor: " << sensor << ", off" << std::endl;
+}
+
+
+void usage(char *argv[])
+{ 
+  std::cerr << "usage: " << argv[0] << " [-d device] [-s sensor] [-t type] [-v volt] [-a | -n nullLevel] [-o] [-p]" << std::endl;
+  std::cerr << "-d selects the device (default: /dev/ttyACM0)" << std::endl;
+  std::cerr << "-s selects the sensor (0-4)" << std::endl;
+  std::cerr << "-t selects the sensor type, (one of ACS712-5, ACS712-20, ACS712-30, or a Volt-Per-Ampere value)" << std::endl;
+  std::cerr << "-v sets the voltage level" << std::endl;
+  std::cerr << "-a auto-calibrates the null level" << std::endl;
+  std::cerr << "-n manually sets the null level (the amount of Watt to be added)" << std::endl;
+  std::cerr << "-o turns off a sensor" << std::endl;
+  std::cerr << "-p prints configured values" << std::endl;
+  std::cerr << "example: " << argv[0] << " -d/dev/ttyACM0 -s0 -tACS712-20 -v12 -a -s1 -tACS712-5 -v3.3 -a -s2 -tACS712-20 -v12 -a -s3 -o -s4 -o -p" << std::endl;
+  exit(1);
+}
+
+
+int main(int argc, char *argv[])
+{
+  for (int opt; (opt = getopt(argc, argv, "ad:n:ops:t:v:")) >= 0;) {
+    switch (opt) {
+      case 'a': checkPowerSensor();
+		autoCalibrate();
+		break;
+
+      case 'd':	powerSensor = std::unique_ptr<PowerSensor::PowerSensor>(new PowerSensor::PowerSensor(optarg));
+		break;
+
+      case 'n': checkPowerSensor()->setNullLevel(sensor, atof(optarg));
+		break;
+
+      case 'o':	checkPowerSensor()->setVolt(sensor, 0);
+		break;
+
+      case 'p': checkPowerSensor();
+		print();
+		break;
+
+      case 's': sensor = atoi(optarg);
+		break;
+
+      case 't': checkPowerSensor()->setType(sensor, convertType(optarg));
+		break;
+
+      case 'v': checkPowerSensor()->setVolt(sensor, atof(optarg));
+		break;
+
+      default:	usage(argv);
+    }
+  }
+
+  if (optind < argc)
+    usage(argv);
+
+  return 0;
+}
diff --git a/psrun.cc b/psrun.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7f3fea3325039b22f99a09632df4a95afc084ffd
--- /dev/null
+++ b/psrun.cc
@@ -0,0 +1,88 @@
+//  Copyright (C) 2016
+//  ASTRON (Netherlands Institute for Radio Astronomy) / John W. Romein
+//  P.O. Box 2, 7990 AA  Dwingeloo, the Netherlands
+
+//  This file is part of PowerSensor.
+
+//  PowerSensor is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+
+//  PowerSensor is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+
+//  You should have received a copy of the GNU General Public License
+//  along with PowerSensor.  If not, see <http://www.gnu.org/licenses/>.
+
+
+#include "PowerSensor.h"
+
+#include <iostream>
+
+#include <inttypes.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+
+void usage(char *argv[])
+{
+  std::cerr << "usage: " << argv[0] << " [-d device] [-f dump_file] [-s sensor] -- command [args]" << std::endl;
+  exit(1);
+}
+
+
+int main(int argc, char *argv[])
+{
+  const char *device = "/dev/ttyACM0", *dumpFileName = 0;
+  int        sensor  = -1;
+
+  for (int opt; (opt = getopt(argc, argv, "d:f:s:")) >= 0;) {
+    switch (opt) {
+      case 'd': device = optarg;
+		break;
+
+      case 'f': dumpFileName = optarg;
+		break;
+
+      case 's': sensor = atoi(optarg);
+		break;
+
+      default:  usage(argv);
+    }
+  }
+
+  if (optind >= argc)
+    usage(argv);
+
+  PowerSensor::PowerSensor powerSensor(device);
+  powerSensor.dump(dumpFileName);
+  PowerSensor::State startState = powerSensor.read();
+  int retval;
+
+  switch (fork()) {
+    case -1: perror("fork");
+	     exit(1);
+
+    case  0: execvp(argv[optind], argv + optind);
+	     perror("execvp");
+	     exit(1);
+
+    default: if (wait(&retval) < 0) {
+	       perror("wait");
+	       exit(1);
+	     }
+  }
+
+  PowerSensor::State stopState = powerSensor.read();
+
+  std::cout <<
+    PowerSensor::seconds(startState, stopState) << " s, " <<
+    PowerSensor::Joules(startState, stopState, sensor) << " J, " <<
+    PowerSensor::Watt(startState, stopState, sensor) << " W" <<
+    std::endl;
+
+  return retval;
+}
diff --git a/pstest.cc b/pstest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c5c2136d0af3d972adee9fdf3accb43b151ce3b7
--- /dev/null
+++ b/pstest.cc
@@ -0,0 +1,79 @@
+//  Copyright (C) 2016
+//  ASTRON (Netherlands Institute for Radio Astronomy) / John W. Romein
+//  P.O. Box 2, 7990 AA  Dwingeloo, the Netherlands
+
+//  This file is part of PowerSensor.
+
+//  PowerSensor is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+
+//  PowerSensor is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+
+//  You should have received a copy of the GNU General Public License
+//  along with PowerSensor.  If not, see <http://www.gnu.org/licenses/>.
+
+
+#include "PowerSensor.h"
+
+#include <iostream>
+
+#include <inttypes.h>
+#include <unistd.h>
+
+#define MAX_MICRO_SECONDS 4000000
+
+
+void usage(char *argv[])
+{
+  std::cerr << "usage: " << argv[0] << " [-d device] [-f dump_file] [-s sensor]" << std::endl;
+  exit(1);
+}
+
+
+int main(int argc, char *argv[])
+{
+  const char *device = "/dev/ttyACM0", *dumpFileName = 0;
+  int        sensor  = -1;
+
+  for (int opt; (opt = getopt(argc, argv, "d:f:s:")) >= 0;) {
+    switch (opt) {
+      case 'd': device = optarg;
+		break;
+
+      case 'f': dumpFileName = optarg;
+		break;
+
+      case 's': sensor = atoi(optarg);
+		break;
+
+      default:	usage(argv);
+    }
+  }
+
+  if (optind < argc)
+    usage(argv);
+
+  PowerSensor::PowerSensor powerSensor(device);
+  powerSensor.dump(dumpFileName);
+
+  PowerSensor::State states[2];
+  states[0] = powerSensor.read();
+
+  for (uint32_t micros = 100, i = 1; micros <= MAX_MICRO_SECONDS; micros *= 2, i ^= 1) {
+    usleep(micros);
+    states[i] = powerSensor.read();
+
+    std::cout << "exp. time: " << micros * 1e-6 << " s, " "measured: " <<
+      PowerSensor::seconds(states[i ^ 1], states[i]) << " s, " <<
+      PowerSensor::Joules(states[i ^ 1], states[i], sensor) << " J, " <<
+      PowerSensor::Watt(states[i ^ 1], states[i], sensor) << " W" <<
+      std::endl;
+  }
+  
+  return 0;
+}