FCGI_RejectJSON now requires a description message.
#define _BSD_SOURCE
#define _XOPEN_SOURCE 600
+/** The current API version **/
+#define API_VERSION 0
+
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
const char * g_actuator_names[NUMACTUATORS] = {
"Pressure regulator", "Solenoid 1"
-};
+};
/**
* Handles control of the actuators.
FCGI_JSONValue("\"Solenoid 1 turned %s!\"", state);
FCGI_EndJSON();
} else {
- FCGI_RejectJSON(context);
+ FCGI_RejectJSON(context, "Invalid actuator value specified");
}
} break;
default:
}
if (action == NULL) { //Must have an action
- FCGI_RejectJSON(context);
+ FCGI_RejectJSON(context, "No action specified");
} else if (!strcmp(action, "start")) {
FCGI_BeginControl(context, force);
} else if (!strcmp(action, "stop")) { //Don't require control key to stop...
/** List of actuator ids (should be of size NUMACTUATORS) **/
typedef enum ActuatorId {
- ACT_PRESSURE = 0,
+ ACT_PRESSURE,
ACT_SOLENOID1
} ActuatorId;
};
/**
- * Identifies current version info. Useful for testing that the API is running.
- * TODO - Consider adding info about available sensors and actuators (eg capabilities)?
+ * Identifies build information and the current API version to the user.
+ * Also useful for testing that the API is running and identifying the
+ * sensors and actuators present.
+ * @param context The context to work in
+ * @param params User specified paramters: [actuators, sensors]
*/
static void IdentifyHandler(FCGIContext *context, char *params) {
bool identSensors = false, identActuators = false;
FCGI_BeginJSON(context, STATUS_OK);
FCGI_JSONPair("description", "MCTX3420 Server API (2013)");
FCGI_JSONPair("build_date", __DATE__ " " __TIME__);
+ FCGI_JSONLong("api_version", API_VERSION);
if (identSensors) {
FCGI_JSONKey("sensors");
FCGI_JSONValue("{\n\t\t");
FCGI_JSONDouble("start_time", start_time);
FCGI_JSONDouble("current_time", current_time);
FCGI_JSONDouble("running_time", current_time - start_time);
-
}
/**
printf("\r\n}\r\n");
}
-/**
- * To be used when the input parameters are invalid. The return data will
- * have a status of STATUS_ERROR, along with other debugging information.
- * @param context The context to work in
- */
-void FCGI_RejectJSON(FCGIContext *context)
-{
- FCGI_RejectJSONEx(context, STATUS_ERROR, "Invalid request");
-}
-
/**
* To be used when the input parameters are rejected. The return data
* will also have debugging information provided.
size_t lastchar = strlen(module) - 1;
if (lastchar > 0 && module[lastchar] == '/')
module[lastchar] = 0;
+
+ //Default to the 'identify' module if none specified
+ if (!*module)
+ strcpy(module, "identify");
- if (!*module || !strcmp("identify", module)) {
+ if (!strcmp("identify", module)) {
module_handler = IdentifyHandler;
} else if (!strcmp("control", module)) {
module_handler = Control_Handler;
if (module_handler) {
module_handler(&context, params);
} else {
- strncat(module, " (unhandled)", BUFSIZ);
- FCGI_RejectJSON(&context);
+ FCGI_RejectJSON(&context, "Unhandled module");
}
context.response_number++;
extern void FCGI_JSONKey(const char *key);
extern void FCGI_PrintRaw(const char *format, ...);
extern void FCGI_EndJSON();
-extern void FCGI_RejectJSON(FCGIContext *context);
extern void FCGI_RejectJSONEx(FCGIContext *context, StatusCodes status, const char *description);
-extern void * FCGI_RequestLoop (void *data);
+extern void *FCGI_RequestLoop (void *data);
+
+/**
+ * Shortcut to calling FCGI_RejectJSONEx. Sets the error code
+ * to STATUS_ERROR.
+ * @param context The context to work in
+ * @param description A short description of why the request was rejected.
+ * @see FCGI_RejectJSONEx
+ */
+#define FCGI_RejectJSON(context, description) FCGI_RejectJSONEx(context, STATUS_ERROR, description)
/**
* Custom formatting function for the JSON value. To be used in
* conjunction with FCGI_JSONKey. Care should be taken to ensure
* that valid JSON is produced.
- *
* @see FCGI_PrintRaw for calling syntax
*/
#define FCGI_JSONValue FCGI_PrintRaw
+++ /dev/null
-<!DOCTYPE html>
-<html>
- <head>
- <meta charset="utf-8">
- <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
- <title>FastCGI API Test</title>
- <style>
- body {
- font-family: "Trebuchet MS", "Verdana", "Arial", "Sans";
- font-size: 12px;
- margin: 1em;
- }
- h2 {
- border-bottom: 1px solid gray;
- }
- .io {
- border: 1px solid gray;
- padding: 0.5em;
- margin: 1em;
- min-height: 5em;
- background-color: GhostWhite;
- }
- </style>
-
- <script>
- $(document).ready(function()
- {
- $('#inputquery').submit(function ()
- {
- $('#output').text("Submitting query...");
- var query = $('#inputquery').find('input[name="query"]').val();
-
- var d = new Date();
- var start = d.getMilliseconds();
- var domain = document.domain == "mctx.us.to" ? "mctx.us.to:8080" : document.domain;
- $.getJSON('http://'+domain+'/api/'+query, function(data) {
- var items = [];
- var timeDiff = d.getMilliseconds() - start; //Not precise at all, use web console
-
- $.each(data, function(key, val) {
- items.push('<li>"' + key + '" : "' + val + '"</li>');
- });
-
-
- $('#output').html("Response ok (" + timeDiff + "ms)! Output:<br>");
- $('<ul/>', {
- html: items.join("\n")
- }).appendTo('#output');
-
- }).fail(function(jqXHR) {
- $('#output').text("Query failed with response code: " + jqXHR.status);
- });
- return false;
- });
- });
- </script>
- </head>
-
- <body>
- <h1>FastCGI API Test</h1>
- The API is located at: <a href="http://mctx.us.to:8080/api/">http://mctx.us.to:8080/api/</a><br>
- <h2>Input</h2>
- Place a query string here. Examples include:<br>
- <ul>
- <li><pre>sensors?key=value&key2</pre></li>
- <li><pre>doesntexist?f</pre></li>
- </ul>
- Response times are inaccurate via JavaScript. Use the web console of
- your browser to determine how long the query takes.<br>
- Hopefully this doesn't break!
- <div class="io">
- <form id="inputquery" name="input" action="#">
- Query string: <input type="text" name="query"><br>
- <input type="submit" value="Submit">
- </form>
- </div>
-
- <h2>Output</h2>
- <div id="output" class="io">
- </div>
- </body>
-</html>
if (status == STATUS_ERROR)
{
- FCGI_RejectJSON(context);
+ FCGI_RejectJSON(context, "Invalid input parameters");
return;
}
}
}
- while (amount_read == SENSOR_QUERYBUFSIZ);
+ while (amount_read > 0);
pthread_mutex_unlock(&(sensor->mutex));
// end critical section
break;
/** Number of data points to keep in sensor buffers **/
#define SENSOR_DATABUFSIZ 10
-
+/** Size of the query buffer. @see Sensor_Handler **/
#define SENSOR_QUERYBUFSIZ 10
/** Number of sensors **/
#define NUMSENSORS 4
-typedef enum SensorId{
+typedef enum SensorId {
ANALOG_TEST0,
ANALOG_TEST1,
DIGITAL_TEST0,
DIGITAL_TEST1
} SensorId;
+/** Human readable names for the sensors **/
extern const char * g_sensor_names[NUMSENSORS];
/** Structure to represent data recorded by a sensor at an instant in time **/
extern void Sensor_Handler(FCGIContext *context, char * params);
-
#endif //_SENSOR_H