EE4214 REAL TIME EMBEDDED SYSTEMS

sanatoriumdrumΗλεκτρονική - Συσκευές

25 Νοε 2013 (πριν από 3 χρόνια και 8 μήνες)

71 εμφανίσεις

1
















EE4214 REAL TIME EMBEDDED SYSTEMS

Group 9


Clinic Queue Management System


PROJECT REPORT

DATED : 13 November 2009













Cheung Zi Eu Augustine
-

U070394R

Huynh Le Trung
-

U066027B

Mateja Dokleja
-

NT090887R

Ritika Taragi
-

U066042L

Sa
hil Gupta
-

U066618E

Tiew Ee Yeong
-

U070447U



2


CONTENTS



1. PROJECT INTRODUCTION......................................................................................................
.4


1.1

Overview ...........................................................
......................................................4


1.2

Detailed Description ................................................................................................5


1.2.1 Data collection mechanism................................................
.......................................5





1.2.1.1 Graphical User Interface...........................................................................5








1.2.1.2 mySQL database.........................................................................
.............7





1.2.1.3 Input using Bluetooth technology.............................................................7


1.2.2 Data Transfer through Socket Mechanism using TCP/IP.........................................7


1.2.3 Room Allocation Mechanism.
...................................................................................8


1.2.4 Process Scheduling/ Task handling..........................................................................9


1.2.5 Speaker.........................................
..........................................................................10


1.2.6 LED’s……………………...........................................................................................10


1.2.7 Push Button and Interrupts …………………………………………………………......10


1.2.8 Clinic System Display ……………………………………………………………………10


1.2.9 Patient Threshold ………………………………………………………………………..11


1.3 System Manual (user level) ……………………………………………………….................11


1.4

System Flowchart (High level overview) ..........................
.....................................12


1.5

Use Case Diagram.................................................................................................12


2. Software Design Features .....................................................................
..................................13


2.1
I/O facilities…………………………………….
.....................................................................13


2.2 Process Scheduling
..........................................................................................
.................13


2.3
& Inter
-
process communication
.........................................................................................13


2.4
Deadlock Management
......................................................................................
...............14

3



2.5
Mutual Exclusion
...............................................................................................................14


3. Software Design Diagram............................................................................
..............................15



3.1 Data Flow Diagram.....................................................................................................15




3.1.1 Level 0................................................................................
........................15




3.1.2 Level 1........................................................................................................15



4. Testing..............................................................................................
........................................16


5. Learning Outcomes.........................................................................................................
..........17



APPENDIX


Project Code..................................................
...............................................................................21


4


1 PROJECT INTRODUCTION


1.1

OVERVIEW


Hospitals and clinics provide essential and mandatory health care services to the people. With
the growing volume of patients seeking medic
al attention everyday, it is imperative to have in
place a smooth functioning Service Management System to ensure highest standards of
serviceability. An inefficient system could lead to overcrowding of clinics, a strain on facilities, and
inconvenience to

patients, making health care more inaccessible and inequitable for the
population.


For our project, we propose to develop a fair Clinic Queue Management System to allocate
patients to a well managed hospital
Queue Management System (QMS)
.







5



1.2

DETAIL
ED DESCRIPTION


The aim of the project is to build a Real Time Queue Management System. The system manages
the following activities:


-

Data collection from Incoming patients using a friendly Graphical User Interface (GUI)

-

Data transfer from GUI (workstation
) to Queue Management module (uCsimm board)

-

Room allocation based on a planned algorithm

-

Room occupancy status display through the board LED’s

-

Speaker to indicate incoming patient.



In this section, we will describe the Queue Management System, in detaile
d steps.


1.2.1. Data collection mechanism

Data collection mechanism is divided into 2 main parts: Graphic User Interface(GUI) for
interaction with user and mySQL database for retrieving user’s data and medical history.


1.2.1.1.

Graphic User Interface (GUI)

GUI is

user friendly interface that allows patient to log in using his unique user identification
number. When that happens, first GUI connect to mySQL database and searches for patient’s ID.
If ID is found, patient’s information and medical history are retrieve
d from database presented in
box ‘Patient data’. After that, random values generator mechanism is used to simulate results of
patient’s initial examination. For key factors ‘0’ or ‘1’ is randomly generated and that information is
presented in ‘Initial exam
ination results’ box.

6




Data retrieved from the database and randomly generated data is chosen in the way to fit chosen
prediction model. Prediction model which was used was developed originally for pneumonia by
the team of researchers supported through
a grant from the Federal Agency for Health Care
Policy and Research and has been validated as being accurate and applicable. Model goes
though all the key factors and for each of them, according to it’s status, certain value is added up
to patient’s sum. A
fter that, patient is put into one of 5 risk categories according to his/her sum.
As our system supports only normal and emergency patients, patients of upper two categories, of
medium and high risk, are considered emergency patients while everybody else i
s considered
normal patients.

For patients to be sent to the board and to the queue, application has to be connected to the
board. That is done by clicking on the ‘Connect with hospital’ button. When button is pressed,
socket is created on fixed IP address

168.192.1.1. and port 4242 and GUI acts like a server and
7


listens on the port of the attempt of connecting by the client. When the connection is established,
patients can be sent into the queue by sending letter ‘e’ or ‘n’ over the Ethernet using TCP/IP
p
rotocol, according to patient’s calculated status. Both sending and establishing the connection
are done in by using asynchronous functions which do their job and then when other side (board
as a client) responds callback function is evoked to process that

response. That way the program
is not blocked while waiting for action of other side and it’s possible to execute other tasks. On
the very bottom of the screen, at status strip information about connection are displayed.

Additionally, GUI has a log box wh
ere information about events relevant to the user are
displayed.


1.2.1.2.

mySQL database

MySQL database is used to store information about patient’s details and past medical records.
GUI connects to the database when ID is provided and gets that information. Datab
ase consists
only of one table, ‘Patients’, and is protected by password. In the table patient’s id is used as a
primary key of the database so no duplicate records of the same id are possible.


1.2.1.3. Input using Bluetooth technology

Another mechanism
is used for generation of test cases as this scenario cannot generate users
fast enough for system to be stressed. For that reasons and for more flexibility of the system
another mechanism of input is realized. Idea is simple: instead of manually typing th
eir user id’s in
GUI, users can do that by using Bluetooth capabilities of their cellphones. File including patient’s
id is transferred over Bluetooth connection to certain folder at the computer where GUI is running.
GUI has a mechanism of listening for a
n event of creating the new file in selected directory of the
computer and it detects transfer of file with patient’s id. When it is detected, file reader
implemented the GUI opens the file, reads patient’s id and from that point on processing goes on
as f
or any normal user who has typed in his/her details in GUI. Initial examination and patient
data for new user are shown in the boxes and data about new user is shown in log box, too.


1.2.2 Data Transfer through Socket Mechanism using TCP/IP


The uCsimm/u
Clinux
combination provides necessary hardware and software for Ethernet connectivity. We use the
Ethernet capabilities through the socket mechanism that supports the client/server interaction
over an internet i.e. over a local lan. The server executes on
the linux workstation and the client
on the uCSimm board. When the QMS software is booted, a program is used to establish client
-
server connection, and information on incoming patients (‘n’, ‘e’) is sent over the network
throughout the program.

On the uCs
imm side, the information sent over the link is stored in the socket buffer for reading. A
RTAI FIFO is created in kernel space to read the incoming data for processing.

8


RTAI provides a variety of mechanism for inter
-
process communication. Although the Uni
x
system provides similar IPC mechanism to the user
-
space processes, RTAI needs to provide its
own implementation for them in order to make it possible for the real
-
time tasks to use the IPC
mechanism, as they can not use the standard Linux system calls. T
he different IPC mechanism
are included as Kernel modules, which can be loaded in addition to the basic RTAI and
scheduler
-
modules only when they are needed by the tasks.


We use the communication mechanism of RTAI


FIFO. FIFO is a synchronous and unblock
ing
one
-
way communication channel between a Linux process and a real time task having a size
limit. No data can be overwritten in a FIFO, but a FIFO can become full in which new data cannot
be written until the old data is consumed.


When patient data is r
eceived in the FIFO, a FIFO handler detects any new incoming data and
passes it to the main program for queue/room allocation.




1.2.3 Room Allocation Mechanism
-

Two queues are created, one to hold the incoming patients
that are not emergency cases (‘n
’) and one to hold emergency cases (‘e’). The incoming data (‘n’,
‘e’) is assigned to the respective queues and the size of each queue at any point of time
represents the number of emergency and normal patients in waiting for being attended by the
doctor.

9



The system has 4 clinic rooms that can be allocated to patients. To determine fair priority of room
allocation to normal and emergency patients, we use the following algorithm.


p = size_e / (size_n + size_e),



where:

p is used (as below) to determine
the priority of emergency patients over normal,

size_e = size of queue holding emergency patients, i.e. no of emergency patients in system

size_n = size of queue holding normal patients, i.e. no of normal patients in the system


If

(p = 0), no_of_room_em
ergency = 0;

(0 < p <=0.25), no_of_room_emergency = 1;

(0.25 <= p <=0.50), no_of_room_emergency = 2;

(0.50 <= p <=0.75), no_of_room_emergency = 3;

(0.75 <= p <=1.00), no_of_room_emergency = 4;

where no_of_room_emergency is the number of rooms that can be
allocated at a single point of
time to emergency patients.


This algorithm determined the number of rooms to be allocated on priority basis to emergency
patients over normal patients, based on the two queue sizes. Hence, when
no_of_room_emergency=2, at mos
t two emergency patients can be assigned rooms, as and
when the rooms become available.


For example; a) size_e=0, all rooms will be allocated for normal patients.

b) Size_e=3, size_n=12, 1 room will be assigned (as and when any room is free) for emergency

patients so that all at most 1 emergency patient will be assigned a room, which becomes
available the first. The second emergency patient will only be assigned the first available room
after the first emergency patient has been attended to.


1.2.4 Process

Scheduling/ Task handling


The Main program has 3 main tasks:


Task 1
-

Fifo handling (to retrieve patient detail incoming over the network link)

Task 2


Reading Data from Buffer and allocating room, display LED

Task 3


Speaker invocation


Task 1 has
the highest priority. It is an event driven task. When data is available in the FIFO, the
FIFO handler will start task 1. Task 1 then updates the queue information accordingly.

10


Task 2 and task 3 are periodic tasks. The Time period has been pre
-
determined b
ased on
analysis. Task 2 checks the current queue information and room status and allocates the rooms
to the patients. It also controls the LEDs to inform each room’s occupancy. Because interrupts
can change the queue information and room status at any poi
nt of time, we need task 2 to check
the queue and room status again once in a while and a periodic task implementation would be the
most suitable choice for task 2 over here.

Task 3 has the lowest priority, and hence whenever any other task is activated, i
t is pre
-
empted.


1.2.5 Speaker


The Speaker is the lowest priority task in the system. It is scheduled to run
throughout, and is pre
-
empted by higher priority tasks. Hence a speaker in the off mode indicates
that another task is currently active. A user
space program is coded to read from a audio file and
then write the read data into a real time FIFO. Then a kernel module is there to invoke the FIFO
handler and subsequently, the PWM output of the microcontroller is loader with audio samples to
produce so
unds.


1.2.6 LEDs



The uCsimm board LEDs on Port D is used to display a room occupancy status. If a
room is occupied, the LED assigned will be lighted, and when vacant, the LED assigned will be
off.


1.2.7 Push Buttons and Interrupts

-

A push button/dip
switch is used to indicate when a room
becomes vacant. This is achieved by using hardware interrupts provided by the MC68EZ328
micro
-
controller. When there are edge sensitive triggers to the Port D inputs, an interrupt service
routine is called to clear th
e room and update the patient queue status. This is analogous to the
reality where the doctor in each room has a button available to indicate when he is ready for the
next patient. The interrupts handlers are registered in Linux and reflected in /proc/inte
rrupts.
Since there are 3 doctor rooms, 3 pins are used to generate interrupt to indicate that the patient is
leaving the particular room. The LED display will change to vacant accordingly.


1.2.8 Clinic status display



Since a kernel module is employed t
o schedule patients and
update room availability, data needs to be passed to the user application for displaying an overall
clinic status. Therefore, shared memory is employed because of its convenience and ease in
reference. It can be described as an arra
y of storage with each element having the details
needed to display status. The user application is allowed to read from the array and output to
console necessary information that describes the whole clinic status.

11




1.2.9 Patient threshold



There will b
e a limit to how many patients 3 doctors in a clinic can
handle. We are setting a limit using a general semaphore, such that when a new patient arrives, a
semaphore is being taken and if he leaves a semaphore is being posted. The motivation to use a
genera
l semaphore is that adding and subtracting patients from queue are two different tasks
running and semaphores may be used to prevent any concurrency issues.


1.3

SYSTEM MANUAL


The system (at the user level) is made up of 2 components, the server (uCsimm) and
the
workstation. The workstation will continuously play a sound if it has no other tasks (indicating an
idle system).


When a patient enters the clinic he will have his details entered into the system GUI at the
workstation. The user will also include whe
ther he requires emergency assistance. Based on his
entry and urgency level, he will be assigned a queue number and automatically directed to an
appropriate room when one becomes available.


The clinic consists of 4 rooms and 4 LEDs (on uCsimm) represent t
he status of the 4 rooms. An
active LED means the room is occupied. Pressing a button represents the patient has left the
room and will turn off its corresponding LED. In the case the button is not pressed within 15
minutes from the patient entering the ro
om, the patient will also be considered as having left the
room.






12


1.4

SYSTEM FLOWCHART (High level overview)

















1.5


Use Case Diagram

















13


2. Software Design Features


2.1
I/O facilities


The Queue Management System uses a user friend
ly GUI, designed in C#, to input patient
details. The GUI runs on the workstation and requests for relevant patient details, including
whether emergency or normal assistance is required.


Inter
-
process Communication is achieved through socket mechanism us
ing TCP/IP. Sockets
provide a special kind of inter
-
process communication that emphasizes the distinction between
a

server

process and

client

processes. The server and client may be on the same machine or on
different machines connected via

ethernet.

We us
e a connection oriented system where sockets
use TCP to connect client to server, and server to client. The Server runs on the uCsimm and
Client runs on the workstation. The server program runs in the background and the GUI passes
information across the li
nk as and when patients come in.


At the uCsimm socket, data is written onto a Fifo structure in the kernel space from where the
data is extracted to enter into respective queues (normal/emergency).


2.2
Process Scheduling


When data is read from the socke
t, the user space program will write data the a FIFO. The FIFO
handler will then send a command to invoke task 1. After updating the queue information and the
allocation of the total number of room based on the dynamic load balancing algorithm mentioned
ab
ove, task 1 stops. When the next period of task 2 is reached, it will use the newly updated
queue information, the room allocation information for each type of patients, and the current
status of the rooms to arrange a new patient into a room if possible.


The period of task 2 (500ms) is designed to be long enough compared to its execution time
(which is in nanoseconds unit) so that the user space process is not starved. When the control is
changed back to the user space program, it will again check the s
ocket and send data to the
kernel space again if it is available.




14



2.3
Inter
-
process Communication


To communicate between tasks and processes in the system, we use FIFOs, shared memory
and semaphores. The FIFOs are used as a medium to transfer data fr
om the user space to the
kernel module and to send that data around between tasks in the kernel space. The FIFO that
connects the user space and the kernel space has a FIFO handler attached to it to invoke task 1
when data is available. Other FIFOs in the
kernel space do not need immediate responses from
the tasks and therefore no FIFO handlers are attached to them. They are used as normal buffers.


Shared memory & semaphores

Memory space is allocated to the same address space in both kernel and user space
and
accessing them from either space gives the same data. This is similar to global variables where
modify one would affect all functions that are running in a program. Note that this must be use
with caution since there are no checks to reading and writin
g to these shared memory spaces.
This program is avoided since only the kernel module in our system writes and the user program
will only read from it.


Real time semaphores provide a low level blocking or non blocking checks to ensure that there
will be n
o concurrency problems. In our system, the task that will add new patient to the queue
will take a semaphore before updating the queue. On the contrary, the task that deletes a existing
patient will give a semaphore to allow more patients to enter.


2.4 De
adlock Management


Deadlock is a situation where

a group

of

processes

are all blocked and none of them can
become

unblocked
as the resources will never be released. Our Queue Management System
employs static prevention of deadlock where we restrict type of

request and acquisition to make
deadlock impossible. A possibility for a deadlock is at the network communication level but our
program is such that it prevents any such occurrence with the client and server exchanging data
in a uni
-
direction pattern.


2.
5 Mutual Exclusion

To preserve data consistency, shared resources must be accessed in mutual exclusion. When a
process has to read or update certain shared resources, it first enters a critical region to achieve
mutual exclusion and ensure that no other pr
ocess will use the shared resource at the same time.

15



3 SOFTWARE DESIGN DIAGRAMS


3.1

Data Flow Diagrams


3.1.1

Level 0


3.1.2


Level 1


4 TESTING

16



Under normal testing, different values of n and e are used to test the dynamic load balancing
algorithm. Interrupts are ge
nerated to test the response of the system. It shows that rooms are
allocated as expected based on the ratio between n and e. The interrupt service routines also
update the room status information and the queue information correctly whenever interrupts are

triggered.


Under stress testing, data is continuously read and interrupts are continuously triggered. We
expect the queue information update, rooms status update and room allocation to follow the
current rules. It can be observed that our system is actua
lly be able to meet this expectation
under heavy load condition.






















5 LEARNING OUTCOMES

17



Augustine Cheong

The pulse
-
width modulator of the uCsimm was intended to play a tune while the system was not
processing other tasks. We started with

using the PWM in tone mode, which causes it to
generate a continuous tone as long as the PWM sample register contains a non
-
zero value. We
then experimented with having the PWM play a proper sound file instead of a single tone.

While the PWM was able to d
o so, we were not able to integrate it succesfully with the rest of the
system. With longer sound files, the system would spend more time playing the sound. Since the
system is non
-
preemptive, the task of playing a long sound file would end up blocking the

higher
priority tasks. We were thus unable to implement a schedule such that the higher priority tasks
would not undergo starvation.


One possible solution would be to use a shorter sound file. However,


we did not implement this
method as we wanted our s
ystem to be able to perform the real
-
time requirements even with long
sound files.


This project has taught me the difficulties that arise in designing a real
-
time embedded system,
such as how to deal with the possibility of deadlocks and priority inversio
n. I can also better
understand the importance of planning an efficient scheduling algorithm to prevent resource
starvation.

The team suffered minor setbacks during the integration phase because there was insufficient
communication between members working
on different parts of the system, leading to
incompatible code. More regular updates using the wiki provided would have prevented this from
occuring.


Ritika Taragi


For each implementation, the Linux operating system is run as the lowest priority task of
a small
real
-
time operating system.

Linux undergoes no changes to its operation from the standpoint of
the user or the Linux kernel, except that it is permitted to execute only when there are no real
-
time tasks executing. Both implementations extend the st
andard Linux programming environment
to real
-
time problems by allowing real
-
time tasks and interrupt handlers to communicate with
ordinary Linux processes. As the client program is a user space process, there will be problem
running it continuously with ou
r kernel tasks running at the same time. There is only one
18


processor and if the kernel tasks keep running, the client program will starve, and even if there is
new patient, it would not have the resources to sense it.

Hence, the kernel module will be used
to
provide service to the user app when there is any data available. The client program will be in a
continuous loop, and once it receives a new patient, it will write some data into a RT FIFO. FIFO
is a synchronous and unblocking one
-
way communication cha
nnel between a Linux process and
a real time task having a size limit. No data can be overwritten in a FIFO, but a FIFO can become
full in which new data cannot be written until the old data is consumed.

. The difference is that the kernel module does not
keep running now.

There will be a handler in the kernel to notice the new patient and it will starting executing tasks
like queuing and allocating rooms. Once done, this task goes into a suspend mode, freeing
resources to allow the client program to take i
n new patient.


Through the project, I understood the use of RT features. I learnt basic mechanism of Inter
-
Process Communication between user space process and RTAI code, principles of process
synchronization through interrupts and event driven mechanism,

concepts of mutual exclusion,
and deadlock management.


Huynh Le Trung

After this project, I have learnt much on how a real
-
time system can be designed using RTAI
-
Linux. I have also understood about different real
-
time scheduling algorithms and the inter
-
process communication between various processes in the system. Various difficulties that our
group had to face during the implementation of the system gave me many good experiences so
that I could avoid and overcome similar issues in my future projects. I
n summary, although the
project was not easy and would sometimes become very confusing (partly due to the limitation of
the hardware itself), it was a good introduction to the field of real
-
time embedded system design.


Tiew Ee Yeong

Through this project,
I’ve learnt a lot about Linux kernel and writing codes such that it suits both
the Linux API and the RTAI API. The foremost problem encountered will be the difference in
writing kernel modules where Linux system calls, like open() and read() cannot be used
. This has
force me to dwell deeper into understanding the Linux kernel where I learnt about some basics
about writing device drivers and some kernel functions. For example, the request_irq() function
was used in this project to register interrupts handler

for the microcontroller. With some
understanding of the Linux kernel structure, I’ve proceeded to read about what services RTAI
could provide. The most useful service will be the real time FIFO where it serves to communicate
data between the kernel and us
er. I feel that the RTAI FIFO function is like a character device file
in Linux, thus I learnt that RTAI provides a framework to substitute services in Linux kernel ( e.g.
19


rtf_get() similar to read() ) and the API provided by RTAI are mostly sufficient for

the scope of our
project. I’ve also learnt about programming loadable modules in which there must have an init
and cleanup function. In these modules, there are running kernel tasks that can be initialized,
suspending, pending or even blocked. Each task h
as its own work to do and that programming
the tasks such that they do not starve other tasks, know when to suspend and when to wake up
are problems that could take a long time to solve. Therefore, I understood why there are so many
documented synchronizat
ions examples, such as the dining philosophers’ problem to let people
use them and improve on them since writing one from scratch could be highly error prone.
Overall, I feel that it is a challenge to predict the behavior of a real time system, especially
built on
a portable platform like Linux, but I have gained invaluable experiences in programming in both
RTAI and Linux environment.


Mateja Dokleja

Through this project, I have learnt much on how a real
-
time system can be designed using RTAI
-
Linux.I have
also learnt the basics of using Bluetooth with C#, to implement a robust
communication system. As our group discussed the project and tested various sections, I learnt
more about real time tasks, their scheduling algorithms, and how the RTAI processes work
.


Sahil Gupta


I was in charge of designing the architecture of the project and leading the group.


To work efficiently, we had divided our team into 3 groups: Trung and Me in charge of finding out
how the Board and RTAI work, designing the controller. E
e yeong and Augustine in charge of the
speaker and interrupts, Ritika and Mateja with the communication and GUI.


So apart of designing the algorithm, I was also in charge of co
-
ordination of activites, assigning
work to members.


My first task was to find

out how the uCSimm board really works? What are the hardware
specifications? So we started of with understand what kernel modules, user applications mean.
After getting the simple "hello world" prog we went on to try the task implementation example
given
in the RTAI manual. This didn't work as mentioned in the manual for us since our processor
was a Uni Processor and not an SMP.


20


Then we figured out how to write to PortD and switch between tasks. We also found out how to
use the "make periodic function" a
nd it works flawlessly. We were able to implement the task
switching using LEDs as shown in lecture notes.


After experimenting we found out that there is a problem with the hardware. Once a lower priority
task is pre
-
empted by a higher priority task, it
is not restored after the computation time for the
higher priority task is over. So once pre
-
empted,a task is never restored.


I also came up with the Dynamic Load Balancing algorithm and a simple method to implement
Bluetooth. For the dynamic load balanci
ng algo, The rooms to emergency and normal patients
are allocated based on their relative ratios. So if the percentage of normal patients is less, less
rooms will be allocated to them. But this algorithm gives priority to emergency patients; as long as
the
re is atleast one emergency patient, a room will be allocated to him, but it is not the same case
with normal patients.
























21


Appendix


PROJECT CODE


User Space Module


#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <sy
s/time.h>

#include <sys/types.h>

#include <fcntl.h>

#include <unistd.h>

#include <sys/ioctl.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>


#include "rtai_shm.h"

// note that a different compileApp.sh is
needed to use rtai functi
ons in userland

#include "control.h"


/*definitions for SHM*/

#define SPACE1 0xAAAA

#define MEMSIZE 20

unsigned int *adr;

#define BUFSIZE 70


char buf[BUFSIZE];


int t;


void print(void) // function to print out the full status of the clinic

{


printf("===
===============Clinic Status
Report====================

\
n");

22



printf("


<Patient>



<Room Reserved for>

\
n");


printf("Room 1:


%c%d




%c

\
n",
adr[0], adr[1], adr[6]);


printf("Room 2:


%c%d




%c

\
n",
adr[2], adr[3], adr[7]);


printf("Room 3:


%c%d




%
c

\
n",
adr[4], adr[5], adr[8]);


printf("
---------------------------------------------------------
-

\
n");


printf("Total number of normal[n] patients

:

%d
\
n",
adr[9]);


printf("Total number of emergency[e] patients

:

%d
\
n",
adr[10]);


printf("Total number
of patients


:

%d
\
n",
adr[9]+adr[10]);


printf("=========================================================
=

\
n");

}


int main(int argc,char *argv[])

{


fd_set rfds;


static unsigned char buf[16384*3];



struct timeval tv;


int fd0, fds, ctl, sFifo, rd_nu
m, wr_num;


struct my_msg_struct msg;



int client_sock_desc, client_len;


struct sockaddr_in client_addr;


char ch;


int result;


unsigned char *ptr;



adr = rtai_malloc(SPACE1, MEMSIZE);

// allocate a memory pointing
to the same address as that declared
in kernel




printf("Here in app main
\
n");


23



if ((fd0 = open("/dev/rtf0", O_RDONLY)) < 0) {



fprintf(stderr, "Error opening /dev/rtf1
\
n");



exit(1);


}



if ((ctl = open("/dev/rtf1", O_WRONLY)) < 0) {



fprintf(stderr, "Error opening /dev/rtf2
\
n");



exi
t(1);


}



/*
---------------------------------------------------------------
-------
*/


client_sock_desc = socket(AF_INET, SOCK_STREAM, 0);


client_addr.sin_family = AF_INET;


result = inet_aton("192.168.1.1", &client_addr.sin_addr);


if (result == 0)


{



perror("inet_aton error");



return (
-
1);


}


client_addr.sin_port = htons(4242);


client_len = sizeof(client_addr);


bind(client_sock_desc, (struct sockaddr *)&client_addr,
client_len);


result = connect(client_sock_desc, (struct sockaddr
*)&client_addr,
client_len);


if (result ==
-
1)


{



perror("client cannot connect");



return (
-
1);


}


/*
---------------------------------------------------------------
-------
*/



while(1)


{

24




/****************************************************************
**/



print
f(" Awaiting new patients...
\
n");



while ( read(client_sock_desc, &ch, 1) < 0 );// if there
are no new patient, do nothing {}



/****************************************************************
**/



/* now start the tasks */

//


printf("New Patient: ");

//


scanf("%c", &ch);



if( ch == 'n' || ch == 'e' )



{




printf(" New patient arrived!
\
n");




msg.command = START_TASK;




msg.task = 0;




msg.period = 500;




msg.data = ch;




if (write(ctl, &msg, sizeof(msg)) < 0)




{





fprintf(stderr, "Can't
send a command to RT
-
task
\
n");





exit(1);




}





msg.task = 1;




msg.period = 700;




msg.data = 'z';




if (write(ctl, &msg, sizeof(msg)) < 0)




{





fprintf(stderr, "Can't send a command to RT
-
task
\
n");





exit(1);




}



}






if ( ch == 'p')

25




print();

// if get p as input, print the status of the
clinic




FD_ZERO(&rfds);



FD_SET(fd0, &rfds);



tv.tv_sec = 5;



tv.tv_usec = 0;


}



return 0;

}


Kernel Space (RTAI) Module



#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/e
rrno.h>

#include <linux/fs.h>

#include <linux/mm.h>

#include <asm/uaccess.h>


#include <rtai.h>

#include <rtai_sched.h>

#include <rtai_fifos.h>


#include <asm/MC68EZ328.h>

#include <asm/irq.h>


#include "rtai_shm.h"

#include "control.h"


/*definitions for
SHM*/

#define SPACE1 0xAAAA

#define MEMSIZE 20

unsigned int *adr;


int countn=0;

26


int counte=0;


#define PWMIRQ 0x00000080

#define PWM_IRQ_ENABLE 0x40

#define PWM32KHZ 0x00

#define PWM16KHZ 0x01

#define PWM8KHZ 0x02

#define REPEAT 0x08

#define PWM_SIZE 1024
*16*3


#define MAXSIZE

10

#define SOUNDFIFO 4


MODULE_LICENSE("GPL");


EXPORT_NO_SYMBOLS;


static RT_TASK tasks[3];


static int n = 0, e = 0, nin = 1, ein = 1;

int eOut[3];

int nOut[3];

int roomNo;

int availRooms = 3;

char roomReserved[3];

/* e = reserved
for 'e', n = reserved for 'n'
*/

char roomStatus[3] = {'a', 'a', 'a'};

/* a = available, n =
occupied by 'n', e = occupied by 'e' */


SEM *notfull;


void allocRooms(void);

//static char *data[] = {"Frank ", "Zappa "};

/*

void init_PWM(void)

{


printk("Ini
tialising PWM
\
n");


PWMC=0x0020; // reset

27





PWMC = PWMC_EN | PWM32KHZ | REPEAT;



printk("Initilise end
\
n");

}

*/

void myIrq1(int irq, void *dev_id, struct pt_regs * regs)

{


if (roomStatus[0] != 'a') // if empty but interrupt, do nothing
or else availRoo
ms will increase indefintely


{



rt_printk("Doctor in room 1 finishes.
\
n");



if (roomStatus[0] == 'n')



{




rt_printk("n%d has left room 1
\
n", nOut[0]);




countn
--
;



}



else if (roomStatus[0] == 'e')



{




rt_printk("e%d has left room 1
\
n", eOut[0]
);




counte
--
;




}




roomStatus[0] = 'a';



rt_sem_signal(notfull);

// add to semaphore



/* update shared memory */



adr[0]='
-
';



adr[1]= 0;



adr[9]=countn;



adr[10]=counte;



availRooms++;

// increase available rooms



PDDATA |= 0x01;



//

allocR
ooms();

// no need to alloc rm anymore


}


ISR |= 0x00010000; /* reset IRQ1 */

}


void myIrq2(int irq, void *dev_id, struct pt_regs * regs)

28


{


if (roomStatus[1] != 'a') // if empty but interrupt, do nothing
or else availRooms will increase indefintely


{



rt_printk("Doctor in room 2 finishes.
\
n");



if (roomStatus[1] == 'n')



{




rt_printk("n%d has left room 2
\
n", nOut[1]);




countn
--
;


//


n
--
;

// just make room available after patient
leaves



}



else if (roomStatus[1] == 'e')



{




rt_printk("e%d h
as left room 2
\
n", eOut[1]);




counte
--
;



//


e
--
;

// just make room available after patient
leaves



}




roomStatus[1] = 'a';



rt_sem_signal(notfull);// add to semaphore



/* update shared memory */



adr[9]=countn;



adr[10]=counte;



adr[2]='
-
';



a
dr[3]=0; // ascii for '
-
'



availRooms++;

// increase available rooms



PDDATA |= 0x02;


//

allocRooms();

// no need to alloc rm anymore


}


ISR |= 0x00020000; /* reset IRQ2 */

}


void myIrq3(int irq, void *dev_id, struct pt_regs * regs)

{


if (roomStatus[
2] != 'a') // if empty but interrupt, do nothing
or else availRooms will increase indefintely


{

29




rt_printk("Doctor in room 3 finishes.
\
n");



if (roomStatus[2] == 'n')



{




rt_printk("n%d has left room 3
\
n", nOut[2]);




countn
--
;


//


n
--
;



}



else
if (roomStatus[2] == 'e')



{




rt_printk("e%d has left room 3
\
n", eOut[2]);




counte
--
;



//


e
--
;



}




roomStatus[2] = 'a';



rt_sem_signal(notfull);// add to semaphore



/* update shared memory */



adr[9]=countn;



adr[10]=counte;



adr[4]='
-
';



a
dr[5]=0; // ascii for '
-
'



availRooms++;

// increase available rooms



PDDATA |= 0x04;



//

allocRooms();

// no need to alloc rm anymore


}


ISR |= 0x00040000; /* reset IRQ3 */

}

/*

void play_pwm(int fifo)

{

//

unsigned int status;


//

int i, j = 0;



int

taskno = fifo;


struct my_msg_struct msg;


while (1)


{

30




if ((rtf_get(taskno + COMMAND_FIFO + 1, &msg, sizeof(msg))
)== sizeof(msg) )



{




switch (msg.command)




{





case START_TASK:






rt_task_make_periodic_relative_ns(rt_whoami(), 0,
msg.peri
od*1000000);






break;





default:






rt_printk("RTL task: bad command
\
n");





}



}



i = rtf_get(SOUNDFIFO, pwm_buf, sizeof(pwm_buf));



if (i < 0)




rt_printk("get data failed
\
n");



play_pwm(i);



next = pwm_buf;



PWMS = *(next++);



while (j <

i)



{




status = PWMC;




status &= 0x0020;




if (status!= 0)




{






PWMS=*(next++);





j++;




}



}



PWMC = 0x0020;




PWMS = 0x0A0A;



rt_busy_sleep(200000000);



PWMS = 0x0000;



rt_task_suspend(rt_whoami());


}

}

31


*/

void allocRooms(void)

{


/
* Dynamic allocation of the number of rooms based on the ratio
between 'n' and 'e' cases */


if (e == 0)


{



roomReserved[0] = 'n';



roomReserved[1] = 'n';



roomReserved[2] = 'n';




adr[6] = 'n';



adr[7] = 'n';



adr[8] = 'n';



}


else if (0 < e && (
3 * e) <= (n + e))


{




roomReserved[0] = 'e';



roomReserved[1] = 'n';



roomReserved[2] = 'n';




/* update shared memory */



adr[6] = 'e';



adr[7] = 'n';



adr[8] = 'n';



}


else if ((3 * e) > (n + e) && (3 * e) <= (2 * (n + e)))


{



roomReserved[0
] = 'e';



roomReserved[1] = 'e';



roomReserved[2] = 'n';




/* update shared memory */



adr[6] = 'e';



adr[7] = 'e';



adr[8] = 'n';



}



else if ((3 * e) > (2 * (n + e)))




{



roomReserved[0] = 'e';

32




roomReserved[1] = 'e';



roomReserved[2] = 'e';




/* update shared memory */



adr[6] = 'e';



adr[7] = 'e';



adr[8] = 'e';



}


return;

}


static void getData(int fifo)

{


int taskno = fifo;


struct my_msg_struct msg;


while (1)


{



if ((rtf_get(taskno + COMMAND_FIFO + 1, &msg, sizeof(msg))
)== si
zeof(msg) )



{




switch (msg.command)




{





case START_TASK:






rt_task_make_periodic_relative_ns(rt_whoami(), 0,
msg.period*1000000);






break;





default:






rt_printk("RTL task: bad command
\
n");





}



}











if (msg.data == 'e')



{





rt_sem_wait(notfull);

// take a semaphore with
every patient coming in

33





e++;




counte++;



}

else if (msg.data == 'n')




{




rt_sem_wait(notfull);

// take a semaphore with
every patient coming in




n++;




countn++; // update total number of pat
ients



}



adr[9]=countn;



adr[10]=counte;



allocRooms();



if (rt_whoami() == &tasks[0])




rtf_put(fifo, &e, sizeof(int));







rt_task_suspend(rt_whoami());



rt_task_wait_period();


}

}


static void allocateRooms(int fifo)

{


int taskno = fifo;


in
t adjnum=0;


struct my_msg_struct msg;


while (1)


{



if (rtf_get(taskno + COMMAND_FIFO + 1, &msg, sizeof(msg))
== sizeof(msg))



{




switch (msg.command)




{





case START_TASK:






rt_task_make_periodic_relative_ns(rt_whoami(), 0,
msg.period*1000
000);






break;





default:

34







rt_printk("RTL task: bad command
\
n");




}



}




for (roomNo = 0; roomNo < 3; roomNo++)



{





if (e > 0 && roomReserved[roomNo] == 'e' &&
roomStatus[roomNo] != 'e')




{





if (roomStatus[roomNo] == 'n')





{






i
f (availRooms == 0)






{








n++;








roomStatus[roomNo] = 'e';







e
--
;

// decrease the number in
queue after allocating room








allocRooms();







}

//





else { /*should continue loop since there
are availroom n will find one eventually*
/

//






roomStatus[3
-

availRooms] = 'e';



//






e
--
;

// decrease the number in
queue after allocating room

//






availRooms
--
;

//





}







} else {






roomStatus[roomNo] = 'e';

// if room
is not e not n but a, just occupy it






availRooms
--
;






e
--
;

// decrease the number in queue
after allocating room







allocRooms();


35






}





if (roomNo == 0)






PDDATA &= 0xFE;





else if (roomNo == 1)






PDDATA &= 0xFD;





else if (roomNo == 2)






PDDATA &= 0xFB;





if (roomStatus[roomNo]
=='e')






{ // only when e finds a room, status is
updated






rt_printk("e%d is now in room %d
\
n", ein,
roomNo+1);







eOut[roomNo]=ein;






/* update shared memory, adjust to make
sure numbers tally */






if (roomNo==0) adjnum=0;







else if (r
oomNo==1) adjnum=2;








else if (roomNo==2) adjnum=4;







adr[adjnum] = 'e';






adr[adjnum+1] = ein;






ein++;






}






}




if (n > 0 && roomReserved[roomNo] == 'n' &&
roomStatus[roomNo] == 'a')





{





roomStatus[roomNo] = 'n';






availR
ooms
--
;





n
--
;

// decrease the number in queue after
allocating room






allocRooms();





if (roomNo==0) adjnum=0;






else if (roomNo==1) adjnum=2;







else if (roomNo==2) adjnum=4;

36






/* update shared memory, adjust to make sure
numbers tally */





if (roomNo == 0)






PDDATA &= 0xFE;





else if (roomNo == 1)






PDDATA &= 0xFD;





else if (roomNo == 2)






PDDATA &= 0xFB;





rt_printk("n%d is now in room %d
\
n", nin,
roomNo+1);





nOut[roomNo]=nin;





adr[adjnum] = 'n';





adr[adjnum+1
] = nin;





nin++;




}



}

//


rtf_put(taskNo, data[taskNo], 6);

//


rt_task_suspend(rt_whoami());



rt_task_wait_period();


}


}


static int my_handler(unsigned int fifo, int rw)

{


struct my_msg_struct msg;


int err;




if (rw == 'r')


{



return
-
EIN
VAL;


}


while ((err = rtf_get(COMMAND_FIFO, &msg, sizeof(msg))) ==
sizeof(msg))



{



rtf_put(msg.task + COMMAND_FIFO + 1, &msg, sizeof(msg));



rt_task_resume(&tasks[msg.task]);


}


if (err != 0)

37



{



return
-
EINVAL;


}


return 0;

}



int init_module(vo
id)

{


int i;




rtf_create(0, 4000);


rtf_create(1, 4000);


rtf_create(2, 4000);


rtf_create(3, 4000);

//

rtf_create(4, 2000);




PDDIR = 0x0F;


PDSEL = 0x0F;


PDDATA |= 0x0F;


ICR |= 0xEE00;

// IRQs 1,2,3 positive polarity and edge
triggered



//

init_PW
M();


/*Request IRQ1, 2 and 3*/


if (request_irq(16, myIrq1, IRQ_FLG_LOCK, "irq1", NULL))


{



rt_printk("Error:irq1 not set
\
n");



return
-
1;


}


if (request_irq(17, myIrq2, IRQ_FLG_LOCK, "irq2", NULL))


{



rt_printk("Error:irq2 not set
\
n");



return
-
1;


}


if (request_irq(18, myIrq3, IRQ_FLG_LOCK, "irq3", NULL))


{



rt_printk("Error:irq3 not set
\
n");

38




return
-
1;


}


/* initialise share memory and put default values into them */


adr = rtai_kmalloc(SPACE1, MEMSIZE);


i=0;


while ( i != MEMSIZE )


{



adr[i]='
-
';



i++;


}


adr[1]=adr[3]=adr[5]=0;


adr[9]=adr[10]=0;



rt_task_init(&tasks[0], getData, 0, 1000, 0, 0, 0);


rt_task_init(&tasks[1], allocateRooms, 1, 1000, 2, 0, 0);

//

rt_task_init(&tasks[2], play_pwm, 2, 1000, 1, 0, 0);


rtf_create_handle
r(COMMAND_FIFO, X_FIFO_HANDLER(my_handler));




/*Semaphore init*/


rt_sem_init(notfull, MAXSIZE);




rt_set_oneshot_mode();


start_rt_timer_ns(10000000);


return 0;

}



void cleanup_module(void)

{


PDDATA |= 0x0F;


rtf_destroy(0);


rtf_destroy(1);


rtf_de
stroy(2);


rtf_destroy(3);


free_irq(16, NULL);


free_irq(17, NULL);


free_irq(18, NULL);


stop_rt_timer();

39



rt_task_delete(&tasks[0]);


rt_task_delete(&tasks[1]);


rtai_kfree(SPACE1);

}


Speaker User Space Module


#include <stdio.h>

#include <fcntl.h>

#in
clude <unistd.h>



int main(int argc, char *argv[]) {


int rd_num, wr_num, fd, fifo_id;


static unsigned char buf[16384*3];


unsigned char *ptr;




if (argc<2)


{



printf("Please specify files to use
\
n");



return 0;


}




printf("Opening sound file and F
IFO
\
n");




if ( (fifo_id = open("/dev/rtf1", O_WRONLY)) < 0) {



printf("Error opening write file
\
n");



return 0;

//open FIFO of minor number 1


}





if ( (fd=open("argv[2]", O_RDONLY)) < 0 )



printf("error opening file
\
n");


while ((rd_num = read(fd,
buf, sizeof(buf))) > 0) { //while
entire audio file is not yet read



ptr=buf; //points to current buffer position



printf("reading
\
n");




40




do { //loop until everything that is read is written into
FIFO








if ( (wr_num=write(fifo_id, ptr, rd_num)) >

0) //if
writing the number of bytes read to FIFO is successful




{






ptr+=wr_num; //points to next data





rd_num
-
=wr_num; //decrease available bytes to
write




} else { //else write failed





printf("Error in writing to FIFO
\
n");





return 0;




}




printf("Write success
\
n");




} while(rd_num>0);


}


printf("EXIT from user
\
n");


return 0;

}


Speaker Kernel Space Module


#include <asm/MC68EZ328.h>

#include <linux/module.h>

#include <linux/kernel.h>

#include <rtai_fifos.h>

#include <rtai.h>


#defi
ne PWMIRQ 0x00000080

#define PWM_IRQ_ENABLE 0x40

#define PWM32KHZ 0x00

#define PWM16KHZ 0x01

#define PWM8KHZ 0x02

#define REPEAT 0x08


#define FIFO_num 1

#define PWM_SIZE 1024*16*3

41



unsigned short *next;

unsigned short pwm_buf[PWM_SIZE];


void init_PWM(voi
d)

{


printk("Initialising PWM
\
n");


PWMC=0x0020; // reset


PWMC = PWMC_EN | PWM32KHZ | REPEAT;

// 32KHZ sampling with 3
repeats


printk("Initilise end
\
n");

}


void play_pwm(int i)

{


unsigned int status;



int j=0;


next = pwm_buf;


PWMS=*(next++);


whil
e(j < i)

// to make sure all bytes are put into PWM
output


{



status = PWMC;

// get PWMC status



status &= 0x0020;

//check for FIFOAV bit



if ( status!= 0)

// if bit=1 then put one byte into PWMS



{





PWMS=*(next++);




j++;



}


}

}


int data_in(un
signed int fifo)

{


int i;


printk("In FIFO handler
\
n");


i = rtf_get(FIFO_num, pwm_buf, sizeof(pwm_buf));

// read
FIFO

42



if(i<0)printk("get data failed
\
n");


play_pwm(i);


return 0;

}


int init_module(void) {



rtf_create(FIFO_num, PWM_SIZE);

// create a
new FIFO buffer


rtf_create_handler(FIFO_num, data_in);

// call data_in every
time there is new data



printk("Opening file and attempt to play
\
n");


init_PWM();



return 0;

}


void cleanup_module(void) {


PWMC=0x0020;

// reset


rtf_destroy(FIFO_num);

// d
elete FIFO


printk("The End
\
n");

}