Example #1
0
/**
 * Set an Actuator value
 * @param a - The Actuator
 * @param value - The value to set
 */
void Actuator_SetValue(Actuator * a, double value, bool record)
{
	if (a->sanity != NULL && !a->sanity(a->user_id, value))
	{
		//ARE YOU INSANE?
		Log(LOGERR,"Insane value %lf for actuator %s", value, a->name);
		return;
	}
	if (!(a->set(a->user_id, value)))
	{
		Fatal("Failed to set actuator %s to %lf", a->name, value);
	}

	// Set time stamp
	struct timespec t;
	clock_gettime(CLOCK_MONOTONIC, &t);
	DataPoint d = {TIMEVAL_DIFF(t, *Control_GetStartTime()), a->last_setting.value};
	// Record value change
	if (record)
	{	
		d.time_stamp -= 1e-6;
		Data_Save(&(a->data_file), &d, 1);
		d.value = value;
		d.time_stamp += 1e-6;
		Data_Save(&(a->data_file), &d, 1);
	}
	a->last_setting = d;
}
Example #2
0
/**
 * Record data from a single Sensor; to be run in a seperate thread
 * @param arg - Cast to Sensor* - Sensor that the thread will handle
 * @returns NULL (void* required to use the function with pthreads)
 */
void * Sensor_Loop(void * arg)
{
	Sensor * s = (Sensor*)(arg);
	Log(LOGDEBUG, "Sensor %d starts", s->id);

	// Until the sensor is stopped, record data points
	while (s->activated)
	{
		
		bool success = s->read(s->user_id, &(s->current_data.value));

		struct timespec t;
		clock_gettime(CLOCK_MONOTONIC, &t);
		s->current_data.time_stamp = TIMEVAL_DIFF(t, *Control_GetStartTime());	
		
		if (success)
		{
			if (s->sanity != NULL)
			{
				if (!s->sanity(s->user_id, s->current_data.value))
				{
					Fatal("Sensor %s (%d,%d) reads unsafe value", s->name, s->id, s->user_id);
				}
			}
			s->averaged_data.time_stamp += s->current_data.time_stamp;
			s->averaged_data.value = s->current_data.value;
			
			if (++(s->num_read) >= s->averages)
			{
				s->averaged_data.time_stamp /= s->averages;
				s->averaged_data.value /= s->averages;
				Data_Save(&(s->data_file), &(s->averaged_data), 1); // Record it
				s->num_read = 0;
				s->averaged_data.time_stamp = 0;
				s->averaged_data.value = 0;
			}
		}
		else
		{
			// Silence because strain sensors fail ~50% of the time :S
			//Log(LOGWARN, "Failed to read sensor %s (%d,%d)", s->name, s->id,s->user_id);
		}


		clock_nanosleep(CLOCK_MONOTONIC, 0, &(s->sample_time), NULL);
		
	}
	
	// Needed to keep pthreads happy
	Log(LOGDEBUG, "Sensor %s (%d,%d) finished", s->name,s->id,s->user_id);
	return NULL;
}
Example #3
0
/**
 * 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);
}
Example #4
0
/**
 * Handle a request to the sensor module
 * @param context - The context to work in
 * @param params - Parameters passed
 */
void Sensor_Handler(FCGIContext *context, char * params)
{
	struct timespec now;
	clock_gettime(CLOCK_MONOTONIC, &now);
	double current_time = TIMEVAL_DIFF(now, *Control_GetStartTime());
	int id = 0;
	const char * name = "";
	double start_time = 0;
	double end_time = current_time;
	const char * fmt_str;
	double sample_s = 0;

	// key/value pairs
	FCGIValue values[] = {
		{"id", &id, FCGI_INT_T}, 
		{"name", &name, FCGI_STRING_T},
		{"format", &fmt_str, FCGI_STRING_T}, 
		{"start_time", &start_time, FCGI_DOUBLE_T}, 
		{"end_time", &end_time, FCGI_DOUBLE_T},
		{"sample_s", &sample_s, FCGI_DOUBLE_T}
	};

	// enum to avoid the use of magic numbers
	typedef enum {
		ID,
		NAME,
		FORMAT,
		START_TIME,
		END_TIME,
		SAMPLE_S
	} SensorParams;
	
	// Fill values appropriately
	if (!FCGI_ParseRequest(context, params, values, sizeof(values)/sizeof(FCGIValue)))
	{
		// Error occured; FCGI_RejectJSON already called
		return;
	}

	Sensor * s = NULL;
	if (FCGI_RECEIVED(values[NAME].flags))
	{
		if (FCGI_RECEIVED(values[ID].flags))
		{
			FCGI_RejectJSON(context, "Can't supply both sensor id and name");
			return;
		}
		s = Sensor_Identify(name);
		if (s == NULL)
		{
			FCGI_RejectJSON(context, "Unknown sensor name");
			return;
		}
	}
	else if (!FCGI_RECEIVED(values[ID].flags))
	{
		FCGI_RejectJSON(context, "No sensor id or name supplied");
		return;
	}
	else if (id < 0 || id >= g_num_sensors)
	{
		FCGI_RejectJSON(context, "Invalid sensor id");
		return;
	}
	else
	{
		s = &(g_sensors[id]);
	}

	// Adjust sample rate if necessary
	if (FCGI_RECEIVED(values[SAMPLE_S].flags))
	{
		if (sample_s < 0)
		{
			FCGI_RejectJSON(context, "Negative sampling speed!");
			return;
		}		
		DOUBLE_TO_TIMEVAL(sample_s, &(s->sample_time));
	}
	
	
	DataFormat format = Data_GetFormat(&(values[FORMAT]));

	// Begin response
	Sensor_BeginResponse(context, s, format);

	// Print Data
	Data_Handler(&(s->data_file), &(values[START_TIME]), &(values[END_TIME]), format, current_time);
	
	// Finish response
	Sensor_EndResponse(context, s, format);

}