/*
* Thermal Control
Demonstration - POSIX Threads Version
*
* Copyright (c) 1997,
ESTEC
*
* Written by Marizio Martignano, ESTEC
* Changes for POSIX
Threads Version by Chris Nettleton
*/
#include <pthread.h>
#include <stddef.h>
#include <assert.h>
#include <time.h>
#ifndef M_1750
#include <fcntl.h>
#include <sched.h>
#endif
#define TM_DELAY 1
#define T1_LC 10
#define T1_LW 15
#define T1_HW 25
#define T1_HC 30
#define T1_DELAY 4
#define T1_STEP 2
#define T2_LC 0
#define T2_LW 10
#define T2_HW 40
#define T2_HC 50
#define T2_DELAY 3
#define T2_STEP 3
#define T3_LC 6
#define T3_LW 10
#define T3_HW 16
#define T3_HC 30
#define T3_DELAY 2
#define T3_STEP 1
#define TMIN 0
#define TMAX 60
#define BLEN 256
static int istat;
void
delay (void)
{
time_t
now;
time_t
wakeup;
now = time(NULL);
wakeup = now;
#ifdef M_1750
while (1) {
now =
time(NULL);
if (now !=
wakeup) {
break;
}
sched_yield();
}
#else
sleep (secs);
#endif
}
/*
* Global data, each
object protected by a mutex
*/
static struct tc
{
pthread_mutex_t m;
int temp;
int automatic;
int on;
int lw;
int hw;
int step;
int period;
}
t1, t2, t3;
char timebuf [BLEN + 1];
pthread_mutex_t timebuf_m;
char inputline [BLEN + 1];
pthread_mutex_t inputline_m;
int p_tele
= 1;
pthread_mutex_t p_tele_m;
void
tc_init (struct
tc *t, int low, int high, int _step, int _period)
{
pthread_mutex_init
(&t->m, NULL);
t->temp = 0;
t->automatic = 0;
t->on = 0;
t->lw =
low;
t->hw = high;
t->step = _step;
t->period =
_period;
}
// Set the standard input,
// when needed
int
set_input (void)
{
#ifndef M_1750
int
stat;
stat = fcntl (0, F_GETFL);
fcntl
(0, F_SETFL, O_NDELAY);
return stat;
#else
return 0;
#endif
}
// Reset the standard input,
// when needed
void
reset_input (int
stat)
{
#ifndef M_1750
fcntl
(0, F_SETFL, stat);
#endif
}
/*
* Get a character
from the standard input,
* without suspending
*/
int
nodelay_getchar (void)
{
int
res;
char ch;
#ifndef M_1750
res = read (0, &ch, 1);
if (res)
{
return (int) ch;
}
else
{
return 0;
}
#endif
#ifdef M_1750
asm
volatile ("xio
%0,0x8501":"=r" (res));
if (res & 0x02)
{
asm volatile ("xio %0,0x8500":"=r" (ch));
return ch & 0xff;
}
else
return 0;
#endif
}
/*
* Body of the
telemetry thread
* Print telemetry
every TM_DELAY seconds
*/
void *
telemetry_body (void *arg)
{
for (;;)
{
int i, temp, automatic, on;
for (i = 0; i < TM_DELAY; i++) {
delay();
}
pthread_mutex_lock (&t1.m);
temp = t1.temp;
automatic = t1.automatic;
on = t1.on;
pthread_mutex_unlock (&t1.m);
printf ("T1:%d:%d:%d\n", temp, automatic, on);
pthread_mutex_lock (&t2.m);
temp = t2.temp;
automatic = t2.automatic;
on = t2.on;
pthread_mutex_unlock (&t2.m);
printf ("T2:%d:%d:%d\n", temp, automatic, on);
pthread_mutex_lock (&t3.m);
temp = t3.temp;
automatic = t3.automatic;
on = t3.on;
pthread_mutex_unlock (&t3.m);
printf ("T3:%d:%d:%d\n", temp, automatic, on);
pthread_mutex_lock (&timebuf_m);
printf ("TIME:%s\n", timebuf);
pthread_mutex_unlock (&timebuf_m);
pthread_mutex_lock (&inputline_m);
printf ("INPUT:%s\n", inputline);
pthread_mutex_unlock (&inputline_m);
}
}
/*
* Body for Thermal_control Threads:
*/
void *
thermal_control_body (void *tc_ptr)
{
struct
tc *t = (struct tc *) tc_ptr;
for (;;) {
int i;
for (i = 0; i < t->period; i++) {
delay();
}
/****
printf("l = %d, h = %d, a = %d, s = %d, o = %d, t =
%d\n",
t->lw, t->hw, t->automatic,
t->step, t->on, t->temp);
****/
if (t->automatic) {
if (t->temp < t->lw) {
if (t->on == 0) {
t->on = 1;
continue;
}
}
if (t->temp > t->hw) {
if (t->on == 1) {
t->on = 0;
continue;
}
}
}
if (t->on) {
t->temp += t->step;
if (t->temp > TMAX) {
t->temp = TMAX;
}
} else {
t->temp -= t->step;
if (t->temp < TMIN) {
t->temp = TMIN;
}
}
}
}
// Body for command interpreter thread
//
void *
reader_body (void *arg)
{
int
pos = 0;
char ch;
for (;;)
{
// Get character
ch = nodelay_getchar ();
// Process
character
if (ch)
{
// Exit program, if requested
if (ch == '~')
{
// Reset standard input
reset_input
(istat);
// Gracefully exit
exit (0);
}
if ((ch != '\n')
&& (ch != '\r') && (pos < BLEN))
{
// Store character in input buffer
pthread_mutex_lock
(&inputline_m);
inputline[pos++] = ch;
inputline[pos] = '\0';
pthread_mutex_unlock
(&inputline_m);
}
else if ((ch ==
'\n') || (ch == '\r'))
{
pos = 0;
pthread_mutex_lock
(&inputline_m);
/* act on command */
// If there's some input
if (strlen (inputline))
{
// Activate automatic control
if (strcmp
(inputline, "T1_AUTO") == 0)
{
if (t1.automatic == 0)
{
t1.automatic = 1;
t1.on = 0;
}
}
if (strcmp
(inputline, "T2_AUTO") == 0)
{
if (t2.automatic == 0)
{
t2.automatic = 1;
t2.on = 0;
}
}
if (strcmp
(inputline, "T3_AUTO") == 0)
{
if (t3.automatic == 0)
{
t3.automatic = 1;
t3.on = 0;
}
}
// Activate manual control
if (strcmp
(inputline, "T1_MAN") == 0)
{
if (t1.automatic == 1)
{
t1.automatic = 0;
t1.on = 0;
}
}
if (strcmp
(inputline, "T2_MAN") == 0)
{
if (t2.automatic == 1)
{
t2.automatic = 0;
t2.on = 0;
}
}
if (strcmp
(inputline, "T3_MAN") == 0)
{
if (t3.automatic == 1)
{
t3.automatic = 0;
t3.on = 0;
}
}
// Heater on
if (strcmp
(inputline, "T1_ON") == 0)
{
if (t1.automatic == 0)
{
t1.on = 1;
}
}
if (strcmp
(inputline, "T2_ON") == 0)
{
if (t2.automatic == 0)
{
t2.on = 1;
}
}
if (strcmp
(inputline, "T3_ON") == 0)
{
if (t3.automatic == 0)
{
t3.on = 1;
}
}
// Heater off
if (strcmp
(inputline, "T1_OFF") == 0)
{
if (t1.automatic == 0)
{
t1.on = 0;
}
}
if (strcmp
(inputline, "T2_OFF") == 0)
{
if (t2.automatic == 0)
{
t2.on = 0;
}
}
if (strcmp
(inputline, "T3_OFF") == 0)
{
if (t3.automatic == 0)
{
t3.on = 0;
}
}
}
pthread_mutex_unlock
(&inputline_m);
}
}
sched_yield ();
}
}
/*
* Clock_task:
* Update the time
buffer once a second
*/
void *
clock_task (void *arg)
{
static short hour =
0;
static short min =
0;
static short sec =
1;
time_t
t, ot = 0;
for (;;)
{
t = time(NULL);
if (t != ot) {
ot = t;
} else {
sched_yield();
continue;
}
sprintf (timebuf, "%02d:%02d:%02d", hour, min,
sec);
sec++;
if (sec > 59)
{
sec = 0;
min++;
if (min > 59)
{
min = 0;
hour++;
}
}
}
}
void
main ()
{
int
ans;
pthread_t
telemetry_thread;
pthread_t
t1_control;
pthread_t
t2_control;
pthread_t
t3_control;
pthread_t
reader_thread;
pthread_t
clock_thread;
int
status;
#ifdef M_1750
pthread_init
();
#endif
/* intitialize global data */
tc_init
(&t1, T1_LW, T1_HW, T1_STEP, T1_DELAY);
tc_init
(&t2, T2_LW, T2_HW, T2_STEP, T2_DELAY);
tc_init
(&t3, T3_LW, T3_HW, T3_STEP, T3_DELAY);
pthread_mutex_init
(&timebuf_m, NULL);
sprintf
(timebuf, "00:00:00");
pthread_mutex_init
(&inputline_m, NULL);
strcpy
(inputline, "");
printf
("\nThermal Control Demo\n");
printf
("M. Martignano - ESA/ESTEC/WME\n");
printf
("Copyright (C) 1997 ESTEC - ESA\n\n");
printf
("Strike '~' to exit...\n");
istat
= set_input ();
/* create the
threads */
ans
= pthread_create (&telemetry_thread,
NULL, telemetry_body, NULL);
assert (ans >= 0);
ans
= pthread_create (&t1_control, NULL, thermal_control_body, (void *) &t1);
assert (ans >= 0);
ans
= pthread_create (&t2_control, NULL, thermal_control_body, (void *) &t2);
assert (ans >= 0);
ans
= pthread_create (&t3_control, NULL, thermal_control_body, (void *) &t3);
assert (ans >= 0);
ans
= pthread_create (&reader_thread,
NULL, reader_body, NULL);
assert (ans >= 0);
ans
= pthread_create (&clock_thread,
NULL, clock_task, NULL);
assert (ans >= 0);
pthread_join
(telemetry_thread, (void *) &status);
}