commit 75cef49f2a08dfb4c66350af15f3a83163f1f021
Author: Tom Mullins <tmullins@andrew.cmu.edu>
Date:   Mon Mar 11 21:42:06 2013 -0400

    Added query_add_event to mainbox code

diff --git a/mainbox/Makefile b/mainbox/Makefile
index 66fb67a..c78785e 100644
--- a/mainbox/Makefile
+++ b/mainbox/Makefile
@@ -1,5 +1,5 @@
-SRC=main.c tool.c query.c
-HDR=tool.h query.h ../tooltron_mb.h
+SRC=main.c tool.c query.c event.c
+HDR=tool.h query.h event.h ../tooltron_mb.h
 
 FLAGS=-O2 -g -Wall -I.. `pkg-config --cflags --libs libmodbus libcurl`
 
diff --git a/mainbox/event.c b/mainbox/event.c
new file mode 100644
index 0000000..a7284f1
--- /dev/null
+++ b/mainbox/event.c
@@ -0,0 +1,30 @@
+#include "event.h"
+#include "query.h"
+#include <stdlib.h>
+
+struct event_t *head, *tail;
+
+struct event_t *event_alloc() {
+  return malloc(sizeof(struct event_t));
+}
+
+void event_free(struct event_t *event) {
+  free(event);
+}
+
+void event_q_push(struct event_t *event) {
+  if (tail)
+    tail->next = event;
+  else
+    head = event;
+  tail = event;
+}
+
+void event_q_process() {
+  struct event_t *old;
+  if (head && query_add_event(head) == 0) {
+    old = head;
+    head = head->next;
+    event_free(old);
+  }
+}
diff --git a/mainbox/event.h b/mainbox/event.h
new file mode 100644
index 0000000..ba95949
--- /dev/null
+++ b/mainbox/event.h
@@ -0,0 +1,19 @@
+#ifndef EVENT_H
+#define EVENT_H
+
+#include <time.h>
+
+struct event_t {
+  unsigned int user;
+  int tool_id;
+  time_t tstart;
+  time_t tend;
+  struct event_t *next;
+};
+
+struct event_t *event_alloc();
+void event_free(struct event_t *event);
+void event_q_push(struct event_t *event);
+void event_q_process();
+
+#endif
diff --git a/mainbox/main.c b/mainbox/main.c
index 3b3cb4b..4857df7 100644
--- a/mainbox/main.c
+++ b/mainbox/main.c
@@ -5,11 +5,18 @@
 #include <strings.h>
 #include <stdio.h>
 
-#define SLEEP_MS 250
+#define SLEEP_MS 10//250
 
 static struct tool_t tools[] = {
-  TOOL_DECL("testa", 4),
-  TOOL_DECL("testb", 5)
+  TOOL_DECL("test1", 1),
+  TOOL_DECL("test2", 2),
+  TOOL_DECL("test3", 3),
+  TOOL_DECL("test4", 4),
+  TOOL_DECL("test5", 5),
+  TOOL_DECL("test6", 6),
+  TOOL_DECL("test7", 7),
+  TOOL_DECL("test8", 8),
+  TOOL_DECL("test9", 9)
 };
 
 #define N_TOOLS (sizeof(tools)/sizeof(struct tool_t))
@@ -74,6 +81,7 @@ int main(int argc, char **argv) {
   i = 0;
   while (run) {
     tool_poll(&tools[i]);
+    event_q_process();
     usleep(SLEEP_MS * (useconds_t)1000);
     i = (i+1) % N_TOOLS;
   }
diff --git a/mainbox/query.c b/mainbox/query.c
index 65ad8de..8f52197 100644
--- a/mainbox/query.c
+++ b/mainbox/query.c
@@ -1,4 +1,5 @@
 #include "query.h"
+#include "event.h"
 #include <stdio.h>
 #include <curl/curl.h>
 
@@ -20,7 +21,7 @@ void query_cleanup() {
   curl_global_cleanup();
 }
 
-static size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp) {
+static size_t write_bool(void *buffer, size_t size, size_t nmemb, void *userp) {
   int *resultp = userp;
   char *str = buffer;
 
@@ -32,7 +33,13 @@ static size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp) {
   return nmemb;
 }
 
-int query_user_permission(int tool_id, int user_id) {
+/*
+ * query_user_permission
+ *
+ * Makes an HTTP request to the CRM server to see if user_id has access to
+ * tool_id. Returns 1 if the server replies with '1' or 0 otherwise.
+ */
+int query_user_permission(int tool_id, unsigned int user_id) {
   CURL* handle;
   CURLcode error_code;
   char url[1024];
@@ -47,7 +54,7 @@ int query_user_permission(int tool_id, int user_id) {
   error_code = curl_easy_setopt(handle, CURLOPT_URL, url);
   if (error_code) goto error;
 
-  error_code = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data);
+  error_code = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_bool);
   if (error_code) goto error;
 
   error_code = curl_easy_setopt(handle, CURLOPT_WRITEDATA, &result);
@@ -73,3 +80,83 @@ error:
   curl_easy_cleanup(handle);
   return 0;
 }
+
+/*
+ * query_add_event
+ *
+ * Makes an HTTPS POST request to add an event to the CRM server, including
+ * user, tool, start time, and stop time. Reads the password from password.txt.
+ * Returns 0 if successful, or 1 if there was an error and the caller should
+ * try the same event again later.
+ *
+ * Times are represented as strftime's "%F %T", which is like "YYYY-MM-DD
+ * HH:MM:SS" with 24-hour time
+ */
+int query_add_event(struct event_t *event) {
+  CURL* handle;
+  CURLcode error_code;
+  struct curl_httppost *formpost = NULL, *lastptr = NULL;
+  char buf[1024];
+  struct tm *timeinfo;
+  long response = 0;
+
+  handle = curl_easy_init();
+  if (handle == NULL)
+    return 1;
+
+  curl_formadd(&formpost, &lastptr,
+      CURLFORM_COPYNAME, "type",
+      CURLFORM_COPYCONTENTS, "usage",
+      CURLFORM_END);
+
+  timeinfo = localtime(&event->tstart);
+  strftime(buf, sizeof(buf), "%F %T", timeinfo);
+  curl_formadd(&formpost, &lastptr,
+      CURLFORM_COPYNAME, "tstart",
+      CURLFORM_COPYCONTENTS, buf,
+      CURLFORM_END);
+
+  timeinfo = localtime(&event->tend);
+  strftime(buf, sizeof(buf), "%F %T", timeinfo);
+  curl_formadd(&formpost, &lastptr,
+      CURLFORM_COPYNAME, "tend",
+      CURLFORM_COPYCONTENTS, buf,
+      CURLFORM_END);
+
+  sprintf(buf, "%08x", event->user);
+  curl_formadd(&formpost, &lastptr,
+      CURLFORM_COPYNAME, "user",
+      CURLFORM_COPYCONTENTS, buf,
+      CURLFORM_END);
+
+  sprintf(buf, "%d", event->tool_id);
+  curl_formadd(&formpost, &lastptr,
+      CURLFORM_COPYNAME, "machine",
+      CURLFORM_COPYCONTENTS, buf,
+      CURLFORM_END);
+
+  sprintf(buf, "https://%s/add_event/", server);
+  error_code = curl_easy_setopt(handle, CURLOPT_URL, buf);
+  if (error_code) goto error;
+
+  error_code = curl_easy_setopt(handle, CURLOPT_HTTPPOST, formpost);
+  if (error_code) goto error;
+
+  error_code = curl_easy_perform(handle);
+  if (error_code) goto error;
+
+  error_code = curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &response);
+  if (error_code) goto error;
+  if (response >= 400)
+    fprintf(stderr, "Error %ld from %s\n", response, buf);
+  else if (response > 200)
+    fprintf(stderr, "Warning: response %ld from %s\n", response, buf);
+
+  curl_easy_cleanup(handle);
+  return response >= 300;
+
+error:
+  fprintf(stderr, "curl: %s\n", curl_easy_strerror(error_code));
+  curl_easy_cleanup(handle);
+  return 1;
+}
diff --git a/mainbox/query.h b/mainbox/query.h
index 7cd1e41..47d2734 100644
--- a/mainbox/query.h
+++ b/mainbox/query.h
@@ -1,8 +1,11 @@
 #ifndef QUERY_H
 #define QUERY_H
 
+#include "event.h"
+
 int query_init();
 void query_cleanup();
-int query_user_permission(int tool_id, int user_id);
+int query_user_permission(int tool_id, unsigned int user_id);
+int query_add_event(struct event_t *event);
 
 #endif
diff --git a/mainbox/tool.c b/mainbox/tool.c
index c6309d8..6442a96 100644
--- a/mainbox/tool.c
+++ b/mainbox/tool.c
@@ -1,5 +1,6 @@
 #include "tool.h"
 #include "query.h"
+#include "event.h"
 #include "tooltron_mb.h"
 #include <modbus.h>
 #include <stdio.h>
@@ -60,6 +61,10 @@ static void tool_grant_access(struct tool_t *tool) {
       tool->address);
   tool_write_coil(MB_COIL_EN, 1);
   tool->state = TS_ON;
+  tool->event = event_alloc();
+  tool->event->user = tool->user;
+  tool->event->tool_id = tool->address;
+  tool->event->tstart = time(NULL);
 }
 
 static void tool_deny_access(struct tool_t *tool) {
@@ -69,6 +74,13 @@ static void tool_deny_access(struct tool_t *tool) {
   tool->state = TS_OFF;
 }
 
+static void tool_off(struct tool_t *tool) {
+  tool->state = TS_OFF;
+  tool->event->tend = time(NULL);
+  event_q_push(tool->event);
+  tool->event = NULL;
+}
+
 void tool_request_disable(struct tool_t *tool) {
   printf("Requesting disable on %s (%d)\n", tool->name, tool->address);
   tool_write_coil(MB_COIL_REQ_DIS, 1);
@@ -130,7 +142,7 @@ void tool_poll(struct tool_t *tool) {
     case TS_ON:
       if (!status[MB_COIL_EN]) {
         printf("Tool %s (%d) is off\n", tool->name, tool->address);
-        tool->state = TS_OFF;
+        tool_off(tool);
       }
       break;
 
@@ -138,7 +150,7 @@ void tool_poll(struct tool_t *tool) {
       if (!status[MB_COIL_EN]) {
         printf("Tool %s (%d) is off after requested disable\n", tool->name,
             tool->address);
-        tool->state = TS_OFF;
+        tool_off(tool);
       }
       break;
 
diff --git a/mainbox/tool.h b/mainbox/tool.h
index fa62f91..50d0da8 100644
--- a/mainbox/tool.h
+++ b/mainbox/tool.h
@@ -14,9 +14,10 @@ struct tool_t {
   int connected;
   enum toolstate_t state;
   unsigned int user;
+  struct event_t *event;
 };
 
-#define TOOL_DECL(name, addr) {name, addr, 1, TS_INIT, 0}
+#define TOOL_DECL(name, addr) {name, addr, 1, TS_INIT, 0, NULL}
 
 int tool_init_mb(const char *device);
 void tool_close_mb();
