/** * Helper: Begin Actuator response in a given format * @param context - the FCGIContext * @param format - Format * @param id - ID of Actuator */ void Actuator_BeginResponse(FCGIContext * context, Actuator * a, DataFormat format) { // Begin response switch (format) { case JSON: FCGI_BeginJSON(context, STATUS_OK); FCGI_JSONLong("id", a->id); FCGI_JSONLong("user_id", a->user_id); //TODO: Don't need to show this? FCGI_JSONPair("name", a->name); break; default: FCGI_PrintRaw("Content-type: text/plain\r\n\r\n"); break; } }
/** * Helper: Begin sensor response in a given format * @param context - the FCGIContext * @param id - ID of sensor * @param format - Format */ void Sensor_BeginResponse(FCGIContext * context, Sensor * s, DataFormat format) { // Begin response switch (format) { case JSON: FCGI_BeginJSON(context, STATUS_OK); FCGI_JSONLong("id", s->id); FCGI_JSONLong("user_id", s->user_id); //NOTE: Might not want to expose this? FCGI_JSONPair("name", s->name); break; default: FCGI_PrintRaw("Content-type: text/plain\r\n\r\n"); break; } }
/** * Handle a request for an Actuator * @param context - FCGI context * @param params - Parameters passed */ void Actuator_Handler(FCGIContext * context, char * params) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); double current_time = TIMEVAL_DIFF(now, *Control_GetStartTime()); int id = 0; char * name = ""; char * set = ""; double start_time = 0; double end_time = current_time; char * fmt_str; // key/value pairs FCGIValue values[] = { {"id", &id, FCGI_INT_T}, {"name", &name, FCGI_STRING_T}, {"set", &set, FCGI_STRING_T}, {"start_time", &start_time, FCGI_DOUBLE_T}, {"end_time", &end_time, FCGI_DOUBLE_T}, {"format", &fmt_str, FCGI_STRING_T} }; // enum to avoid the use of magic numbers typedef enum { ID, NAME, SET, START_TIME, END_TIME, FORMAT } ActuatorParams; // Fill values appropriately if (!FCGI_ParseRequest(context, params, values, sizeof(values)/sizeof(FCGIValue))) { // Error occured; FCGI_RejectJSON already called return; } // Get the Actuator identified Actuator * a = NULL; if (FCGI_RECEIVED(values[NAME].flags)) { if (FCGI_RECEIVED(values[ID].flags)) { FCGI_RejectJSON(context, "Can't supply both id and name"); return; } a = Actuator_Identify(name); if (a == NULL) { FCGI_RejectJSON(context, "Unknown actuator name"); return; } } else if (!FCGI_RECEIVED(values[ID].flags)) { FCGI_RejectJSON(context, "No id or name supplied"); return; } else if (id < 0 || id >= g_num_actuators) { FCGI_RejectJSON(context, "Invalid Actuator id"); return; } else { a = &(g_actuators[id]); } DataFormat format = Data_GetFormat(&(values[FORMAT])); if (FCGI_RECEIVED(values[SET].flags)) { ActuatorControl c = {0.0, 0.0, 0.0, 0}; // Need to set default values (since we don't require them all) // sscanf returns the number of fields successfully read... int n = sscanf(set, "%lf,%lf,%lf,%d", &(c.start), &(c.stepwait), &(c.stepsize), &(c.steps)); // Set provided values in order if (n != 4) { // If the user doesn't provide all 4 values, the Actuator will get set *once* using the first of the provided values // (see Actuator_Loop) // Not really a problem if n = 1, but maybe generate a warning for 2 <= n < 4 ? Log(LOGDEBUG, "Only provided %d values (expect %d) for Actuator setting", n, 4); } // SANITY CHECKS if (c.stepwait < 0 || c.steps < 0 || (a->sanity != NULL && !a->sanity(a->user_id, c.start))) { FCGI_RejectJSON(context, "Bad Actuator setting"); return; } Actuator_SetControl(a, &c); } // Begin response Actuator_BeginResponse(context, a, format); if (format == JSON) FCGI_JSONPair("set", set); // Print Data Data_Handler(&(a->data_file), &(values[START_TIME]), &(values[END_TIME]), format, current_time); // Finish response Actuator_EndResponse(context, a, format); }