commit 7bdb98c5c7f6b44c764f8dd3620f7da270cfd830
Author: Tom Mullins <tmullins@andrew.cmu.edu>
Date:   Tue Nov 13 18:35:46 2012 -0500

    Initial commit of mainbox code.

diff --git a/mainbox/Makefile b/mainbox/Makefile
new file mode 100644
index 0000000..5ff5605
--- /dev/null
+++ b/mainbox/Makefile
@@ -0,0 +1,15 @@
+SRC=main.c tool.c
+HDR=tool.h
+
+FLAGS=-O2 -g -Wall -I.. `pkg-config --cflags --libs libmodbus`
+
+all: tooltron
+
+tooltron: $(SRC) $(HDR)
+	gcc $(SRC) $(FLAGS) -o $@
+
+install: tooltron
+	cp tooltron /usr/local/bin
+
+clean:
+	rm -f *.o tooltron
diff --git a/mainbox/main.c b/mainbox/main.c
new file mode 100644
index 0000000..b7a08d8
--- /dev/null
+++ b/mainbox/main.c
@@ -0,0 +1,57 @@
+#include "tool.h"
+#include <unistd.h>
+#include <signal.h>
+#include <strings.h>
+#include <stdio.h>
+
+#define SLEEP_MS 250
+
+struct tool_t tools[] = {
+  {4, "test", TS_INIT}
+};
+
+#define N_TOOLS (sizeof(tools)/sizeof(struct tool_t))
+
+volatile int run = 1;
+
+void sigint(int sig) {
+  run = 0;
+}
+
+int main(int argc, char **argv) {
+  int i;
+  struct sigaction sigact;
+  const char *device = "/dev/ttyUSB0";
+
+  // TODO getopts to get device name
+
+  bzero(&sigact, sizeof(sigact));
+  sigact.sa_handler = sigint;
+  sigact.sa_flags = SA_RESTART;
+  sigemptyset(&sigact.sa_mask);
+  sigaction(SIGINT, &sigact, NULL);
+
+  if (tool_init_mb(device)) {
+    return 1;
+  }
+
+  printf("Modbus initialized; polling tools...\n");
+
+  i = 0;
+  while (run) {
+    tool_poll(&tools[i]);
+    usleep(SLEEP_MS * (useconds_t)1000);
+    i = (i+1) % N_TOOLS;
+  }
+
+  printf("\nDisabling tools\n");
+  for (i = 0; i < N_TOOLS; i++) {
+    tool_request_disable(&tools[i]);
+  }
+
+  printf("Closing modbus connection\n");
+  tool_close_mb();
+
+  printf("Exiting\n");
+  return 0;
+}
diff --git a/mainbox/tool.c b/mainbox/tool.c
new file mode 100644
index 0000000..72cd479
--- /dev/null
+++ b/mainbox/tool.c
@@ -0,0 +1,118 @@
+#include "tool.h"
+#include "tooltron_mb.h"
+#include <modbus.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h> // TODO temporary
+
+modbus_t *ctx;
+
+int tool_init_mb(const char *device) {
+  ctx = modbus_new_rtu(device, MB_BAUD, 'N', 8, 1);
+  if (ctx == NULL) {
+    fprintf(stderr, "modbus_new_rtu: %s\n", modbus_strerror(errno));
+    return 1;
+  }
+
+  if (modbus_connect(ctx) == -1) {
+    fprintf(stderr, "modbus_connect: %s\n", modbus_strerror(errno));
+    modbus_free(ctx);
+    return 1;
+  }
+
+  return 0;
+}
+
+void tool_close_mb() {
+  modbus_close(ctx);
+  modbus_free(ctx);
+}
+
+static void tool_write_coil(int addr, int bit) {
+  if (modbus_write_bit(ctx, addr, bit) == -1) {
+    fprintf(stderr, "modbus_write_bit: %s\n", modbus_strerror(errno));
+  }
+}
+
+static void tool_init(struct tool_t *tool) {
+  // TODO write current limit values
+  tool_write_coil(MB_COIL_INIT, 1);
+  tool->state = TS_OFF;
+}
+
+static void tool_get_user(struct tool_t *tool) {
+  unsigned short serno[2];
+  if (modbus_read_registers(ctx, MB_INP_SERNOL, 2, serno) == -1) {
+    fprintf(stderr, "modbus_read_registers: %s\n", modbus_strerror(errno));
+    tool->user = 0;
+  } else {
+    tool->user = MODBUS_GET_INT32_FROM_INT16(serno, 0);
+  }
+}
+
+static void tool_grant_access(struct tool_t *tool) {
+  printf("Granting access to %08x on %s\n", tool->user, tool->name);
+  tool_write_coil(MB_COIL_EN, 1);
+}
+
+static void tool_deny_access(struct tool_t *tool) {
+  printf("Denying access to %08x on %s\n", tool->user, tool->name);
+  tool_write_coil(MB_COIL_EN, 0);
+}
+
+void tool_request_disable(struct tool_t *tool) {
+  printf("Requesting disable on %s\n", tool->name);
+  tool_write_coil(MB_COIL_REQ_DIS, 1);
+}
+
+void tool_poll(struct tool_t *tool) {
+  unsigned char status[N_COILS];
+
+  if (modbus_set_slave(ctx, SLAVE_ADDR) == -1) {
+    fprintf(stderr, "modbus_set_slave: %s\n", modbus_strerror(errno));
+  }
+
+  if (modbus_read_bits(ctx, 0, N_COILS, status) == -1) {
+    fprintf(stderr, "modbus_read_bits: %s\n", modbus_strerror(errno));
+    return;
+  }
+
+  if (!status[MB_COIL_INIT]) {
+    tool->state = TS_INIT;
+  }
+
+  switch (tool->state) {
+
+    case TS_INIT:
+      tool_init(tool);
+      break;
+
+    case TS_OFF:
+      if (status[MB_COIL_NEW]) {
+        tool_get_user(tool);
+        // TODO check actual credentials
+        if (rand() & 1) {
+          tool_grant_access(tool);
+        } else {
+          tool_deny_access(tool);
+        }
+      }
+      break;
+
+    case TS_ON:
+      if (!status[MB_COIL_EN]) {
+        printf("Tool %s is off\n", tool->name);
+        tool->state = TS_OFF;
+      }
+      break;
+
+    case TS_REQ_DIS:
+      if (!status[MB_COIL_EN]) {
+        printf("Tool %s is off after requested disable\n", tool->name);
+        tool->state = TS_OFF;
+      }
+      break;
+
+  }
+
+}
diff --git a/mainbox/tool.h b/mainbox/tool.h
new file mode 100644
index 0000000..705c086
--- /dev/null
+++ b/mainbox/tool.h
@@ -0,0 +1,23 @@
+#ifndef TOOL_H
+#define TOOL_H
+
+enum toolstate_t {
+  TS_INIT,
+  TS_OFF,
+  TS_REQ_DIS,
+  TS_ON
+};
+
+struct tool_t {
+  int address;
+  const char *name;
+  enum toolstate_t state;
+  unsigned int user;
+};
+
+int tool_init_mb(const char *device);
+void tool_close_mb();
+void tool_request_disable(struct tool_t *tool);
+void tool_poll(struct tool_t *tool);
+
+#endif
diff --git a/tooltron_mb.h b/tooltron_mb.h
index b37944e..2ad1ca8 100644
--- a/tooltron_mb.h
+++ b/tooltron_mb.h
@@ -16,12 +16,13 @@
  * Coils, 1 bit read/write
  */
 
-/* When 1, there is a new rfid tag in the tool. The main box should either
- * write 1 to MB_COIL_EN, which automatically clears MB_COIL_NEW, or it should
- * write 0 directly to MB_COIL_NEW which denies the request */
+/* When 1, there is a new rfid tag in the tool. Automatically cleared when the
+ * main box writes to MB_COIL_EN */
 #define MB_COIL_NEW     0
 
-/* When 1, tool can be turned on. Write 0 to immediately shut off tool */
+/* When 1, the tool receives power. Write 1 or 0 to grant or deny an access
+ * request, respectively. If the tool is running, write 0 to immediately shut
+ * off the tool */
 #define MB_COIL_EN      1
 
 /* Write 1 to request that the tool is disabled soon (what that means will be
@@ -33,6 +34,9 @@
  * later) */
 #define MB_COIL_INIT    3
 
+/* Number of coils */
+#define N_COILS 4
+
 /*
  * Other things
  */
