Pretend we have a circular railroad-track divided into 24 sections as shown in the figure belove. A train is allowed to enter a section only if it is free from any other trains. Each train moves in a clock-wise direction on the railroad. We have 3 towns(the first one has a Mc-rail station), and 2 gold mines in the system. Each train visits Mc-rail 3 times a day (in order to keep the train-driver fit :-)O<. The trains transport gold from the 2 gold mines to the 3 cities.
A simulator for the Olimex-kit I have used in this project.
We advance a train one pixel by calling the function advance. The function returns the actual sector number for the locomotive of the train. We control the access to towns, McRail and gold mines by calling the function track_shift. It has 3 parameters. The first parameter is the sector number, where we have to choose between the two next sectors. The chosen sector is the second parameter. The third parameter is the disabled sector. This choice will last until we call the function again with these parameters, where we exchange the second and third parameters.
We made an eCos multi-threaded program. Our program has meaningful names of variables and functions also have an appropriate amount of comments. The speed of an individual train is adjustable by using a potentiometer on the Olimex-kit. The selection of a train has done by using the buttons on the Olimex-kit (we use push-buttons and the small joy-stick on the Olimex-kit).
Two operational modes have been implemented. The user shall use a button on the Olimex-kit for switching between them:
Manual mode.
In this mode the user performs the shift of tracks manually by pushing buttons on the Olimex-kit.
Notice that the 3 sectors, which are the parameters of a call of the function track_shift, must be free from trains before our program calls the track_shift function. Whenever a train reaches a town or McRail or a gold mine it stops. The user pushes a button for starting it again.
Secure automatic mode.
In this mode our program operates all the track shifts. Each train must-visit Mc-rail 3 times a day. Whenever a train reaches a town or McRail or a gold mine it must pause for a while.
Our program implemented fairness. This means that in the long run the gold mines have been visited equally many times and each town should have its fair share of the gold.
#include<cyg/kernel/kapi.h>
#include<cyg/infra/diag.h>
#include "typedef.h"
#include "bmp/bmpPastelRainbow.h"
#include "adc/adc.h"
#include "lcd/lcd.h"
#include "pio/pio.h"
#include "pwmc/pwmc.h"
#include "hardware.h"
#include<stdio.h>
#define TICKS_PER_SECOND (100)
#define TRAIN1_TASK_STACK_SIZE (4096)
#define TRAIN1_TASK_PRIORITY (10)
#define TRAIN2_TASK_STACK_SIZE (4096)
#define TRAIN2_TASK_PRIORITY (10)
#define TRAIN3_TASK_STACK_SIZE (4096)
#define TRAIN3_TASK_PRIORITY (10)
#define REACTION_TASK_STACK_SIZE (4096)
#define REACTION_TASK_PRIORITY (10)
#define RAILWAY_TASK_STACK_SIZE (4096)
#define RAILWAY_TASK_PRIORITY (10)
#define MANUAL (0)
#define AUTOMATIC (1)
#define STOP (-1)
#define MOVE (0)
#define NO_OBSTACLE (0)
#define TOWN (1)
#define GOLD_MINE (2)
#define CROSS (3)
#define NO_GOLD (0)
#define PAUSE_TIME (10)
#define TRAIN1 (0)
#define TRAIN2 (1)
#define TRAIN3 (2)
#define NO_OF_SECTORS 24
#define RAIL_COLOR WHITE
#define BACKGROUND_COLOR BLACK
struct Sector_type
{
int x1;
int y1;
int x2;
int y2;
int dx;
int dy;
int enabled;
int next_sector;
int object; // 0: nothing 1: city 2: mine 3:cross
int position;
int with_train;
} sector[NO_OF_SECTORS] = { { 60,20,60,30,0 ,1 ,1,1,}, // 0
{ 60,30,10,30,-1,0 ,1,6,1,40,1 }, // 1
{ 50,20,10,20,-1,0 ,1,5,1,40,1 }, // 2
{ 50,10,10,10,-1,0 ,1,4,1,40,1 }, // 3
{ 10,10,10,20,0 ,1 ,1,5 }, // 4
{ 10,20,10,30,0 ,1 ,1,6 }, // 5
{ 10,30,10,60,0 ,1 ,1,7,3 ,60}, // 6
{ 10,60,10,70,0 ,1 ,1,9 }, // 7
{ 10,60,20,60,1 ,0 ,0,10}, // 8
{ 10,70,10,100,0 ,1 ,1,12}, // 9
{ 20,60,50,60,1 , 0, 1,11,2,50 }, // 10
{ 50,60,50,100,0 , 1,1,13}, // 11
{ 10,100,50,100,1 , 0,1,13}, // 12
{ 50,100,80,100,1 , 0,1,14,3,80}, // 13
{ 80,100,90,100,1 , 0,1,16}, // 14
{ 80,100,80, 90,0 ,-1,0,19}, // 15
{ 90,100,120,100,1 , 0,1,17}, // 16
{ 120,100,120,10, 0,-1,1,18,2,55}, // 17
{ 120,10,80,10,-1, 0,1,20}, // 18
{ 80,90,80,10, 0, -1,1,20}, // 19
{ 80,10,60,10,-1, 0,1,21,3,60}, // 20
{ 60,10,50,10,-1, 0,1,3}, // 21
{ 60,10,60,20,0 , 1,0,0,3,20}, // 22
{ 60,20,50,20,-1,0,0,2}, // 23
};
struct Train_position_type
{
int x; // x position
int y; // y position
int sector_no; // number of sector that train enter
int train_gold; // if train_gold == 0, no gold in train.
int speed; // speed of train
int pause_time; // -1: stop until user pushes joystick.
int reach_obstacle; // 0: nothing 1: city 2: gold mine 3:cross
} train_position[3] = { {50,30,1,0,3},
{50,20,2,0,4},
{50,10,3,0,5}
};
cyg_mutex_t sectorMutex[NO_OF_SECTORS];
// record how much gold town gets.
int town[3] = {0,0,0};
int target_town = 0;
char Mode = AUTOMATIC; // two operational modes. 0: manual, 1: automatic .The default mode is manual.
//Sector_type sector[NO_OF_SECTORS];
void draw_sector(struct Sector_type s)
{
if ( s.enabled )
{
LCDSetLine(s.x1, s.y1, s.x2, s.y2, RAIL_COLOR);
}
else
{
LCDSetLine(s.x1, s.y1, s.x2, s.y2, BACKGROUND_COLOR);
}
if( s.object > 0){
if(s.object == 1){
LCDSetRect(s.position, s.y1, s.position-6, s.y1+6, 1, BLUE);
}
else if(s.object == 2){
if(s.x1 == 20)
LCDSetRect(s.position, s.y1, s.position+6, s.y1+6, 1, YELLOW);
else
LCDSetRect(s.x1, s.position, s.x1+6, s.position-6, 1, YELLOW);
}
}
}
void draw_train(int i, struct Train_position_type tp) // i = number of the train
{
int color = 0;
if(tp.train_gold != NO_GOLD)
color = YELLOW;
else
color = GREEN;
// train1: draw one circle ; train2: two circles ; train3: three circles
do{
LCDSetCircle(tp.x, tp.y, 3-i, color);
i--;
}while(i > -1);
}
int advance_train( struct Train_position_type *tp_ptr)// tp must be reference
{
if(tp_ptr->pause_time == MOVE){
if(tp_ptr->reach_obstacle == TOWN){
if(tp_ptr->train_gold != NO_GOLD){
town[tp_ptr->sector_no - 1] += tp_ptr->train_gold ;
tp_ptr->train_gold = NO_GOLD;
}
}
else if(tp_ptr->reach_obstacle == GOLD_MINE){
tp_ptr->train_gold ++;
}
tp_ptr->reach_obstacle = NO_OBSTACLE;
// when the train reach the end of current sector ,and ready to enter next sector
if ( tp_ptr->x == sector[tp_ptr->sector_no].x2 && tp_ptr->y == sector[tp_ptr->sector_no].y2 ){
// no train in the next sector
if(Mode == MANUAL){
cyg_mutex_lock(§orMutex[sector[tp_ptr->sector_no].next_sector]);
cyg_mutex_unlock(§orMutex[tp_ptr->sector_no]);
sector[tp_ptr->sector_no ].with_train = 0;
tp_ptr->sector_no = sector[tp_ptr->sector_no].next_sector;
sector[tp_ptr->sector_no ].with_train = 1;
tp_ptr->x = sector[tp_ptr->sector_no].x1;
tp_ptr->y = sector[tp_ptr->sector_no].y1;
}
else{
switch(tp_ptr->sector_no){
case 6:
cyg_mutex_lock(§orMutex[7]);
cyg_mutex_lock(§orMutex[8]);
if(sector[10].with_train == 0){
track_shift(6, 8, 7);
}
else{
track_shift(6, 7, 8);
}
cyg_mutex_unlock(§orMutex[tp_ptr->sector_no]);
break;
case 7:
case 8:
cyg_mutex_lock(§orMutex[sector[tp_ptr->sector_no].next_sector]);
cyg_mutex_unlock(§orMutex[7]);
cyg_mutex_unlock(§orMutex[8]);
break;
case 13:
cyg_mutex_lock(§orMutex[14]);
cyg_mutex_lock(§orMutex[15]);
if(sector[17].with_train == 0){
track_shift(13, 14, 15);
}
else{
track_shift(13, 15, 14);
}
cyg_mutex_unlock(§orMutex[tp_ptr->sector_no]);
break;
case 15:
cyg_mutex_lock(§orMutex[sector[tp_ptr->sector_no].next_sector]);
cyg_mutex_unlock(§orMutex[14]);
cyg_mutex_unlock(§orMutex[15]);
break;
case 16:
cyg_mutex_lock(§orMutex[sector[tp_ptr->sector_no].next_sector]);
cyg_mutex_unlock(§orMutex[14]);
cyg_mutex_unlock(§orMutex[15]);
cyg_mutex_unlock(§orMutex[tp_ptr->sector_no]);
break;
case 20:
cyg_mutex_lock(§orMutex[21]);
cyg_mutex_lock(§orMutex[22]);
if(sector[3].with_train == 0){
if(town[2] >= town[1] & town[2] >= town[0]){
track_shift(20, 22, 21);
}
else{
track_shift(20, 21, 22);
}
}
else{
track_shift(20, 22, 21);
}
cyg_mutex_unlock(§orMutex[tp_ptr->sector_no]);
break;
case 21:
cyg_mutex_lock(§orMutex[sector[tp_ptr->sector_no].next_sector]);
cyg_mutex_unlock(§orMutex[21]);
cyg_mutex_unlock(§orMutex[22]);
break;
case 22:
cyg_mutex_lock(§orMutex[23]);
cyg_mutex_lock(§orMutex[0]);
cyg_mutex_unlock(§orMutex[21]);
cyg_mutex_unlock(§orMutex[22]);
if(sector[1].with_train == 0 && sector[2].with_train != 0){
track_shift(22, 0, 23);
}
else if(sector[1].with_train != 0 && sector[2].with_train == 0){
track_shift(22, 23, 0);
}
else if(sector[1].with_train == 0 && sector[2].with_train == 0){
if(town[0] >= town[1]){
track_shift(22, 23, 0);
}
else{
track_shift(22, 0, 23);
}
}
break;
case 2:
cyg_mutex_lock(§orMutex[sector[tp_ptr->sector_no].next_sector]);
cyg_mutex_unlock(§orMutex[23]);
cyg_mutex_unlock(§orMutex[0]);
cyg_mutex_unlock(§orMutex[tp_ptr->sector_no]);
break;
default:
cyg_mutex_lock(§orMutex[sector[tp_ptr->sector_no].next_sector]);
cyg_mutex_unlock(§orMutex[tp_ptr->sector_no]);
break;
}
sector[tp_ptr->sector_no ].with_train = 0;
tp_ptr->sector_no = sector[tp_ptr->sector_no].next_sector;
sector[tp_ptr->sector_no ].with_train = 1;
tp_ptr->x = sector[tp_ptr->sector_no].x1;
tp_ptr->y = sector[tp_ptr->sector_no].y1;
}
}
else
{
// move on x direction
if(sector[tp_ptr->sector_no].dx != 0){
// something on the sector
if(sector[tp_ptr->sector_no].object != 0){
if((sector[tp_ptr->sector_no].position - tp_ptr->x)*sector[tp_ptr->sector_no].dx > 0 && (sector[tp_ptr->sector_no].position - tp_ptr->x)*sector[tp_ptr->sector_no].dx < tp_ptr->speed){
tp_ptr->x = sector[tp_ptr->sector_no].position ;
tp_ptr->reach_obstacle = sector[tp_ptr->sector_no].object;
}
else{
//if 0<(x2-x)*dx<speed then speed is (x2-x)*dx else speed is (x2-x)*d+speed
if((sector[tp_ptr->sector_no].x2 - tp_ptr->x)*sector[tp_ptr->sector_no].dx > 0 && (sector[tp_ptr->sector_no].x2 - tp_ptr->x)*sector[tp_ptr->sector_no].dx < tp_ptr->speed)
tp_ptr->x = sector[tp_ptr->sector_no].x2 ;
else{
if ((sector[tp_ptr->sector_no].position - tp_ptr->x)*sector[tp_ptr->sector_no].dx == tp_ptr->speed)
tp_ptr->reach_obstacle = sector[tp_ptr->sector_no].object;
tp_ptr->x += (sector[tp_ptr->sector_no].dx*tp_ptr->speed);
}
}
}
// nothing on the sector
else{
if((sector[tp_ptr->sector_no].x2 - tp_ptr->x)*sector[tp_ptr->sector_no].dx > 0 && (sector[tp_ptr->sector_no].x2 - tp_ptr->x)*sector[tp_ptr->sector_no].dx < tp_ptr->speed)
tp_ptr->x = sector[tp_ptr->sector_no].x2 ;
else
tp_ptr->x += (sector[tp_ptr->sector_no].dx*tp_ptr->speed);
}
}
// move on y direction
if(sector[tp_ptr->sector_no].dy != 0){
if(sector[tp_ptr->sector_no].object != 0 ){
if((sector[tp_ptr->sector_no].position - tp_ptr->y)*sector[tp_ptr->sector_no].dy > 0 && (sector[tp_ptr->sector_no].position - tp_ptr->y)*sector[tp_ptr->sector_no].dy < tp_ptr->speed){
tp_ptr->y = sector[tp_ptr->sector_no].position ;
tp_ptr->reach_obstacle = sector[tp_ptr->sector_no].object;
}
else{
if((sector[tp_ptr->sector_no].y2 - tp_ptr->y)*sector[tp_ptr->sector_no].dy > 0 && (sector[tp_ptr->sector_no].y2 - tp_ptr->y)*sector[tp_ptr->sector_no].dy < tp_ptr->speed)
tp_ptr->y = sector[tp_ptr->sector_no].y2 ;
else{
if ((sector[tp_ptr->sector_no].position - tp_ptr->y)*sector[tp_ptr->sector_no].dy == tp_ptr->speed)
tp_ptr->reach_obstacle = sector[tp_ptr->sector_no].object;
tp_ptr->y += (sector[tp_ptr->sector_no].dy*tp_ptr->speed);
}
}
}
else{
if((sector[tp_ptr->sector_no].y2 - tp_ptr->y)*sector[tp_ptr->sector_no].dy > 0 && (sector[tp_ptr->sector_no].y2 - tp_ptr->y)*sector[tp_ptr->sector_no].dy < tp_ptr->speed)
tp_ptr->y = sector[tp_ptr->sector_no].y2 ;
else
tp_ptr->y += (sector[tp_ptr->sector_no].dy*tp_ptr->speed);
}
}
// when train meet an obstacle
if(tp_ptr->reach_obstacle != 0){
if(Mode == MANUAL)
tp_ptr->pause_time = STOP;
else{
if(tp_ptr->reach_obstacle != 3)
tp_ptr->pause_time = PAUSE_TIME;
}
}
}
}
else{
// stop for a while
if(tp_ptr->pause_time > 0 ){
tp_ptr->pause_time--;
if(Mode == MANUAL)
tp_ptr->pause_time = STOP;
}
// stop until pressing button
else{
if(Mode == AUTOMATIC)
tp_ptr->pause_time = PAUSE_TIME;
}
}
return tp_ptr->sector_no;
}
void track_shift( int from_sector, int enable_sector, int disable_sector)
{
sector[from_sector].next_sector = enable_sector;
sector[enable_sector].enabled = 1;
sector[disable_sector].enabled = 0;
}
// which town have at least gold
int get_target_town(int town[]){
int i = 0;
int min = 0;
for(i = 1; i < 3; i++)
if(town[i] < town[min])
min = i;
return min;
}
void init_railroad(){
}
//draw the sectors and the trains
void draw_railroad(void)
{
int i;
LCDClearScreen();
for( i=0; i < NO_OF_SECTORS ; i++)
{
draw_sector( sector[i] );
}
for( i=0; i <= 2 ; i++)
{
draw_train(i, train_position[i] );
}
}
int8_t train1TaskStack[TRAIN1_TASK_STACK_SIZE];
cyg_thread train1TaskObj;
cyg_handle_t train1TaskHdl;
int8_t train2TaskStack[TRAIN2_TASK_STACK_SIZE];
cyg_thread train2TaskObj;
cyg_handle_t train2TaskHdl;
int8_t train3TaskStack[TRAIN3_TASK_STACK_SIZE];
cyg_thread train3TaskObj;
cyg_handle_t train3TaskHdl;
int8_t reactionTaskStack[REACTION_TASK_STACK_SIZE];
cyg_thread reactionTaskObj;
cyg_handle_t reactionTaskHdl;
int8_t railwayTaskStack[RAILWAY_TASK_STACK_SIZE];
cyg_thread railwayTaskObj;
cyg_handle_t railwayTaskHdl;
cyg_mutex_t lcdMutex;
#define COLOR_RED 0
#define COLOR_YELLOW 1
#define COLOR_GREEN 2
#define RAIL_COLOR WHITE
void controlTrain1Task(){
cyg_mutex_lock(§orMutex[train_position[0].sector_no]);
while(1){
cyg_thread_delay(TICKS_PER_SECOND / 5);
advance_train( &train_position[0] );
}
}
void controlTrain2Task(){
cyg_mutex_lock(§orMutex[train_position[1].sector_no]);
while(1){
cyg_thread_delay(TICKS_PER_SECOND / 5);
advance_train( &train_position[1] );
}
}
void controlTrain3Task(){
cyg_mutex_lock(§orMutex[train_position[2].sector_no]);
while(1){
cyg_thread_delay(TICKS_PER_SECOND / 5);
advance_train( &train_position[2] );
}
}
void reactionTask(){
static uint32_t trim;
static int s[8];
static int SelectedTrain = TRAIN1; //show the index of selected train.
static int Speed = 0; //show the speed of selected train.
while(1){
cyg_thread_delay(TICKS_PER_SECOND / 5);
if (((ADC_GetStatus(AT91C_BASE_ADC)) & (1 << TRIM_CHANNEL)))
{
// Read the ADC result output
trim = ADC_GetConvertedDataCH6 (AT91C_BASE_ADC); // TRIM_CHANNEL
// Start the conversion
ADC_StartConversion (AT91C_BASE_ADC);
if(trim < 88)
Speed = 0;
else
Speed = trim/250 + 1;
train_position[SelectedTrain].speed = Speed;
}
// press switch1 to change mode
if ( !PIO_Get(&switch_pins[SWITCH1]) ) {
Mode = (Mode + 1)%2;
}
if ( !PIO_Get(&switch_pins[SWITCH2]) ) {
SelectedTrain = (SelectedTrain + 1)%3;
}
if(Mode == MANUAL && train_position[SelectedTrain].reach_obstacle != 0){
// press joystick
if ( !PIO_Get(&joystick_pins[JOYSTICK_BUTTON]) ){
train_position[SelectedTrain].pause_time = MOVE;
}
if(train_position[SelectedTrain].reach_obstacle == 3){
if (!PIO_Get(&joystick_pins[JOYSTICK_LEFT])){
if(train_position[SelectedTrain].sector_no == 20)
track_shift( 20, 21, 22);
if(train_position[SelectedTrain].sector_no == 22)
track_shift( 22, 23, 0);
}
if (!PIO_Get(&joystick_pins[JOYSTICK_RIGHT])){
if(train_position[SelectedTrain].sector_no == 6)
track_shift( 6, 8, 7);
if(train_position[SelectedTrain].sector_no == 13)
track_shift( 13, 14, 15);
}
if (!PIO_Get(&joystick_pins[JOYSTICK_UP])){
if(train_position[SelectedTrain].sector_no == 6)
track_shift( 6, 7, 8);
if(train_position[SelectedTrain].sector_no == 20)
track_shift( 20, 22, 21);
if(train_position[SelectedTrain].sector_no == 22)
track_shift( 22, 0, 23);
}
if (!PIO_Get(&joystick_pins[JOYSTICK_DOWN])){
if(train_position[SelectedTrain].sector_no == 13)
track_shift( 13, 15, 14);
}
}
}
cyg_mutex_lock(&lcdMutex);
LCDPutStr("MODE",10,105,SMALL, WHITE, BLACK);
if(Mode == MANUAL)
LCDPutStr("Manu",20,105,SMALL, WHITE, BLACK);
else
LCDPutStr("Auto",20,105,SMALL, WHITE, BLACK);
LCDPutStr("TOG",30,105,SMALL, WHITE, BLACK);
snprintf(s, 8, "%2u", SelectedTrain+1);
LCDPutStr(s, 40, 105, SMALL, WHITE, BLACK);
LCDPutStr("SPD",50,105,SMALL, WHITE, BLACK);
snprintf(s, 8, "%2u", Speed);
LCDPutStr(s, 60, 105, SMALL, WHITE, BLACK);
LCDPutStr("BY1",70,105,SMALL, WHITE, BLACK);
snprintf(s, 8, "%2u", town[0]);
LCDPutStr(s, 80, 105, SMALL, WHITE, BLACK);
LCDPutStr("BY2",90,105,SMALL, WHITE, BLACK);
snprintf(s, 8, "%2u", town[1]);
LCDPutStr(s,100,105,SMALL, WHITE, BLACK);
LCDPutStr("BY3",110,105,SMALL, WHITE, BLACK);
snprintf(s, 8, "%2u", town[2]);
LCDPutStr(s,120,105,SMALL, WHITE, BLACK);
cyg_mutex_unlock(&lcdMutex);
}
}
// what we doing inside the function
void dispalyRailwayTask(){
while(1){
cyg_thread_delay(TICKS_PER_SECOND / 5);
cyg_mutex_lock(&lcdMutex);
draw_railroad();
cyg_mutex_unlock(&lcdMutex);
}
}
void cyg_user_start(void)
{
int i = 0;
hardwareInit();
cyg_mutex_init(&lcdMutex);
for(i = 0; i < NO_OF_SECTORS; i++)
cyg_mutex_init(§orMutex[i]);
// create a thread to control the shift of train1
cyg_thread_create(TRAIN1_TASK_PRIORITY,
controlTrain1Task,
(cyg_addrword_t)0,
"Train1 Task",
(void *)train1TaskStack,
TRAIN1_TASK_STACK_SIZE,
&train1TaskHdl,
&train1TaskObj);
// create a thread to control the shift of train2
cyg_thread_create(TRAIN2_TASK_PRIORITY,
controlTrain2Task,
(cyg_addrword_t)0,
"Train2 Task",
(void *)train2TaskStack,
TRAIN2_TASK_STACK_SIZE,
&train2TaskHdl,
&train2TaskObj);
// create a thread to control the shift of train3
cyg_thread_create(TRAIN3_TASK_PRIORITY,
controlTrain3Task,
(cyg_addrword_t)0,
"Train3 Task",
(void *)train3TaskStack,
TRAIN3_TASK_STACK_SIZE,
&train3TaskHdl,
&train3TaskObj);
// create a thread to interact with buttons or joy-sticks.
cyg_thread_create(REACTION_TASK_PRIORITY,
reactionTask,
(cyg_addrword_t)0,
"Reaction Task",
(void *)reactionTaskStack,
REACTION_TASK_STACK_SIZE,
&reactionTaskHdl,
&reactionTaskObj);
// create a thread to display railway sectors, trains. towns and mines
cyg_thread_create(RAILWAY_TASK_PRIORITY,
dispalyRailwayTask,
(cyg_addrword_t)0,
"Railway Task",
(void *)railwayTaskStack,
RAILWAY_TASK_STACK_SIZE,
&railwayTaskHdl,
&railwayTaskObj);
cyg_thread_resume(train1TaskHdl);
cyg_thread_resume(train2TaskHdl);
cyg_thread_resume(train3TaskHdl);
cyg_thread_resume(reactionTaskHdl);
cyg_thread_resume(railwayTaskHdl);
diag_printf("eCos extra example :-)\n");
}
No comments:
Post a Comment