Ejemplo n.º 1
0
/**
 * Actuator control thread
 * @param arg - Cast to an Actuator*
 * @returns NULL to keep pthreads happy
 */
void * Actuator_Loop(void * arg)
{
	Actuator * a = (Actuator*)(arg);
	
	// Loop until stopped
	while (a->activated)
	{
		pthread_mutex_lock(&(a->mutex));
		while (!a->control_changed)
		{
			pthread_cond_wait(&(a->cond), &(a->mutex));
		}
		a->control_changed = false;
		pthread_mutex_unlock(&(a->mutex));
		if (!a->activated)
			break;

		Actuator_SetValue(a, a->control.start, true);
		// Currently does discrete steps after specified time intervals

		struct timespec wait;
		DOUBLE_TO_TIMEVAL(a->control.stepsize, &wait);
		while (!a->control_changed && a->control.steps > 0 && a->activated)
		{
			clock_nanosleep(CLOCK_MONOTONIC, 0, &wait, NULL);
			a->control.start += a->control.stepsize;
			Actuator_SetValue(a, a->control.start, true);
			
			a->control.steps--;
		}
		if (a->control_changed)
			continue;
		clock_nanosleep(CLOCK_MONOTONIC, 0, &wait, NULL);

		//TODO:
		// Note that although this loop has a sleep in it which would seem to make it hard to enforce urgent shutdowns,
		//	You can call the Actuator's cleanup function immediately (and this loop should later just exit)
		//	tl;dr This function isn't/shouldn't be responsible for the emergency Actuator stuff
		// (That should be handled by the Fatal function... at some point)
	}

	//TODO: Cleanup?
	
	// Keep pthreads happy
	return NULL;
}
Ejemplo n.º 2
0
/** 
 * Add and initialise a Sensor
 * @param name - Human readable name of the sensor
 * @param user_id - User identifier
 * @param read - Function to call whenever the sensor should be read
 * @param init - Function to call to initialise the sensor (may be NULL)
 * @param max_error - Maximum error threshold; program will exit if this is exceeded for the sensor reading
 * @param min_error - Minimum error threshold; program will exit if the sensor reading falls below this value
 * @param max_warn - Maximum warning threshold; program will log warnings if the value exceeds this threshold
 * @param min_warn - Minimum warning threshold; program will log warnings if the value falls below this threshold
 * @returns Number of actuators added so far
 */
int Sensor_Add(const char * name, int user_id, ReadFn read, InitFn init, CleanFn cleanup, SanityFn sanity)
{
	if (++g_num_sensors > SENSORS_MAX)
	{
		Fatal("Too many sensors; Increase SENSORS_MAX from %d in sensor.h and recompile", SENSORS_MAX);
		// We could design the program to use realloc(3)
		// But since someone who adds a new sensor has to recompile the program anyway...
	}
	Sensor * s = &(g_sensors[g_num_sensors-1]);

	s->id = g_num_sensors-1;
	s->user_id = user_id;
	Data_Init(&(s->data_file));
	s->name = name;
	s->read = read; // Set read function
	s->init = init; // Set init function

	// Start by averaging values taken over a second
	DOUBLE_TO_TIMEVAL(1, &(s->sample_time));
	s->averages = 1;
	s->num_read = 0;

	// Set sanity function
	s->sanity = sanity;

	if (init != NULL)
	{
		if (!init(name, user_id))
			Fatal("Couldn't init sensor %s", name);
	}

	s->current_data.time_stamp = 0;
	s->current_data.value = 0;
	s->averaged_data.time_stamp = 0;
	s->averaged_data.value = 0;
	return g_num_sensors;
}
Ejemplo n.º 3
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);

}