238 lines
5.0 KiB
C
Executable File
238 lines
5.0 KiB
C
Executable File
// Wrapper for libComedi Elevator control.
|
|
// These functions provides an interface to the elevators in the real time lab
|
|
//
|
|
// 2006, Martin Korsgaard
|
|
#define _XOPEN_SOURCE 500
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
|
|
#include "channels.h"
|
|
#include "elev.h"
|
|
#include "io.h"
|
|
|
|
#define POLLING_INTERVAL 50000
|
|
|
|
// Number of signals and lamps per floor (signals includes stop, obstr)
|
|
#define N_SIGNALS 6
|
|
#define N_LAMPS 3
|
|
|
|
|
|
// Array of callback associations.
|
|
static void (*callbacks_g[N_SIGNALS])(int, int);
|
|
|
|
|
|
|
|
// Matrix of lamp channels indexed by floor and lamp type.
|
|
static const int lamp_channel_matrix[N_FLOORS][N_LAMPS] = {
|
|
{LIGHT_UP1, LIGHT_DOWN1, LIGHT_COMMAND1},
|
|
{LIGHT_UP2, LIGHT_DOWN2, LIGHT_COMMAND2},
|
|
{LIGHT_UP3, LIGHT_DOWN3, LIGHT_COMMAND3},
|
|
{LIGHT_UP4, LIGHT_DOWN4, LIGHT_COMMAND4}};
|
|
|
|
|
|
|
|
// Matrix of elevator signals channels indexed by floor and signal type.
|
|
static const int signal_channel_matrix[N_FLOORS][N_SIGNALS] = {
|
|
{FLOOR_UP1, FLOOR_DOWN1, FLOOR_COMMAND1, SENSOR1, STOP, OBSTRUCTION},
|
|
{FLOOR_UP2, FLOOR_DOWN2, FLOOR_COMMAND2, SENSOR2, STOP, OBSTRUCTION},
|
|
{FLOOR_UP3, FLOOR_DOWN3, FLOOR_COMMAND3, SENSOR3, STOP, OBSTRUCTION},
|
|
{FLOOR_UP4, FLOOR_DOWN4, FLOOR_COMMAND4, SENSOR4, STOP, OBSTRUCTION}};
|
|
|
|
|
|
|
|
void elev_set_speed(int speed)
|
|
{
|
|
// In order to sharply stop the elevator, the direction bit is toggled
|
|
// before setting speed to zero.
|
|
static int last_speed = 0;
|
|
|
|
// If to start (speed > 0)
|
|
if (speed > 0)
|
|
io_clear_bit(MOTORDIR);
|
|
else if (speed < 0)
|
|
io_set_bit(MOTORDIR);
|
|
|
|
// If to stop (speed == 0)
|
|
else if (last_speed < 0)
|
|
io_clear_bit(MOTORDIR);
|
|
else if (last_speed > 0)
|
|
io_set_bit(MOTORDIR);
|
|
|
|
last_speed = speed ;
|
|
|
|
// Write new setting to motor.
|
|
io_write_analog(MOTOR, 2048 + 2*abs(speed));
|
|
|
|
//printf(__FILE__ ": Speed set to %d\n", speed);
|
|
}
|
|
|
|
|
|
|
|
void elev_set_door_open_lamp(int value)
|
|
{
|
|
if (value)
|
|
io_set_bit(DOOR_OPEN);
|
|
else
|
|
io_clear_bit(DOOR_OPEN);
|
|
}
|
|
|
|
|
|
|
|
void elev_set_stop_lamp(int value)
|
|
{
|
|
if (value)
|
|
io_set_bit(LIGHT_STOP);
|
|
else
|
|
io_clear_bit(LIGHT_STOP);
|
|
}
|
|
|
|
|
|
|
|
|
|
void elev_set_floor_indicator(int floor)
|
|
{
|
|
assert(floor >= 0);
|
|
assert(floor < N_FLOORS);
|
|
|
|
if (floor & 0x02)
|
|
io_set_bit(FLOOR_IND1);
|
|
else
|
|
io_clear_bit(FLOOR_IND1);
|
|
|
|
if (floor & 0x01)
|
|
io_set_bit(FLOOR_IND2);
|
|
else
|
|
io_clear_bit(FLOOR_IND2);
|
|
}
|
|
|
|
|
|
|
|
void elev_set_button_lamp(elev_direction_t lamp, int floor, int value)
|
|
{
|
|
assert(floor >= 0);
|
|
assert(floor < N_FLOORS);
|
|
|
|
if (value == 1)
|
|
io_set_bit(lamp_channel_matrix[floor][lamp]);
|
|
else
|
|
io_clear_bit(lamp_channel_matrix[floor][lamp]);
|
|
}
|
|
|
|
|
|
|
|
void elev_unregister_callback(elev_signal_t type)
|
|
{
|
|
callbacks_g[type] = NULL;
|
|
}
|
|
|
|
|
|
|
|
void elev_register_callback(elev_signal_t type, void (*callback)(int, int))
|
|
{
|
|
callbacks_g[type] = callback;
|
|
}
|
|
|
|
|
|
|
|
void elev_disable_callbacks(int thread)
|
|
{
|
|
pthread_cancel(thread);
|
|
}
|
|
|
|
|
|
|
|
int elev_init(void)
|
|
{
|
|
memset(callbacks_g, 0, sizeof(callbacks_g));
|
|
|
|
return io_init();
|
|
}
|
|
|
|
|
|
|
|
static void *polling_thread(void *p)
|
|
{
|
|
// Store previous values of inputs, raise signal if changed between
|
|
// two polls.
|
|
static int prev_values[N_FLOORS][N_SIGNALS];
|
|
|
|
memset(prev_values, 0, sizeof(prev_values));
|
|
|
|
while (1) {
|
|
for (int type = 0; type < N_SIGNALS; type++){
|
|
for (int floor = 0; floor < N_FLOORS; floor++){
|
|
int value = io_read_bit(signal_channel_matrix[floor][type]);
|
|
|
|
// If no associated callback: ignore.
|
|
if (callbacks_g[type] == NULL) {
|
|
;
|
|
}
|
|
// If value has not changed, ignore.
|
|
else if (value == prev_values[floor][type]) {
|
|
;
|
|
}
|
|
// Obstruction is raised on any edge, with new value as param.
|
|
else if (type == SIGNAL_TYPE_OBSTR) {
|
|
callbacks_g[type](0, value);
|
|
}
|
|
// STOP is called with no arguments, only when pushed (not when
|
|
// released).
|
|
else if (type == SIGNAL_TYPE_STOP && value == 1) {
|
|
callbacks_g[type](0, 0);
|
|
}
|
|
// Floor sensor is raised on any edge, entering and leaving floor,
|
|
// with floor and value (edge) as param.
|
|
else if (type == SIGNAL_TYPE_SENSOR) {
|
|
callbacks_g[type](floor, value);
|
|
}
|
|
// Other signals (CALL_UP, CALL_DOWN, COMMAND) are raised on
|
|
// rising edge only, with floor and type as parameters.
|
|
else if (value == 1) {
|
|
callbacks_g[type](floor, type);
|
|
}
|
|
// Store current value of signal to avoid multiple calls on the
|
|
// same signal.
|
|
prev_values[floor][type] = value;
|
|
|
|
// Obstr and stop is not floor dependent, so only loop once.
|
|
if (type == SIGNAL_TYPE_OBSTR || type == SIGNAL_TYPE_STOP)
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
usleep(POLLING_INTERVAL);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
int elev_enable_callbacks(void)
|
|
{
|
|
pthread_t new_thread ;
|
|
|
|
if (pthread_create(&new_thread, NULL, polling_thread, NULL) != 0)
|
|
return -1;
|
|
else
|
|
return new_thread;
|
|
}
|
|
|
|
|
|
void elev_reset_all_lamps(void) {
|
|
elev_set_speed(0);
|
|
elev_set_stop_lamp(0);
|
|
elev_set_door_open_lamp(0);
|
|
|
|
for (int floor = 0; floor < N_FLOORS; ++floor) {
|
|
elev_set_button_lamp(ELEV_DIR_DOWN, floor, 0);
|
|
elev_set_button_lamp(ELEV_DIR_UP, floor, 0);
|
|
elev_set_button_lamp(ELEV_DIR_COMMAND, floor, 0);
|
|
}
|
|
}
|
|
|