Partie 1 : Apprentissage de Workbench, et utilisation de tâches et sémaphores
1) Tâche qui s'endort periodiquement (dans notre cas : toute les 3 secondes):
int IDtache1;
int systick_freq;
void init(void){
systick_freq=sysClkRateGet();
IDtache_news=taskSpawn("test",101,0,5000,(FUNCPTR)test,10,0,0,0,0,0,0,0,0,0);
taskDelete(MOI);
}
void test(int variable_quelquonque){
while(1){
printf("Variable quelquonque : %d\nZzZzZzZ\n",variable_quelquonque);
taskDelay(3*systick_freq);
}
}
2) Deux tâches dont une (tperiodique) synchronisant la deuxième (tesclave) :
Dans cet exemple, la priorité n'a pas un rôle primordial (cela risque uniquement de changer l'ordre des tâches, en aucun cas elles ne bloqueront (pas de famine) !
int IDtache1;
int IDtache2;
void init(void){
systick_freq=sysClkRateGet();
IDtache1=taskSpawn("tperiodique",102,0,5000,(FUNCPTR)tperiodique,0,0,0,0,0,0,0,0,0,0);
IDtache2=taskSpawn("tesclave",101,0,5000,(FUNCPTR)tesclave,0,0,0,0,0,0,0,0,0,0);
taskDelete(MOI);
}
void tperiodique(void){
while(1){
printf("tperiodique (id %d)\n",IDtache1);
taskDelay(3*systick_freq);
taskResume(IDtache2);
}
}
void tesclave(void){
while(1){
printf("tesclave (id %d)\n",IDtache2);
taskSuspend(IDtache2);
}
}
3) Etude du fichier partie1-3.c :
Le code de l'application fourni dans le fichier "partie1-3.c" ne gérait pas le cas où le scheduler donnait la main à une autre tâche pendant que celle-ci édite des ressources critiques (var1 et var2).
Il faut donc proteger ces ressources à l'aide d'un sémaphore :
SEM_ID semaphore1;
void init(void)
{
semaphore1=semBCreate(SEM_Q_PRIORITY,SEM_EMPTY);
...
}
void codeTache1(void)
{
while(TRUE)
{
semTake(semaphore1,WAIT_FOREVER);
var1=compteur;
var2=compteur;
semGive(semaphore1);
compteur++;
}
}
void codeTache2(void)
{
while(TRUE)
{
semTake(semaphore1,WAIT_FOREVER);
if ((var1==var2)) printf("var1 = %d var2=%d\n",var1,var2);
semGive(semaphore1);
taskDelay(1);
}
}
4) Image de VxWorks :
Etant donné que des fichiers .c et .h du noyau VxWorks sont manquant sur notre ordinateur, il n'a pas été possible de générer l'image de VxWorks...
Heureusement qu'il y a deux binômes par carte !
Partie 2 : gestion des interruptions UART 2 :
Dans cette partie, nous allons concevoir un code permettant de recevoir via l'UART2 des caractères (interruption).
Nous les mettrons dans un buffer afin de recevoir un paquet complet (67 octets).
Quand celui-ci est plein, nous regardons le 'numéro du canal' de ce paquet afin de l'envoyer (avec une mailbox) dans la tâche correspondante.
Voici le code correspondant :
#define MOI 0
#define adr_base_uart2 0xFF400000+0x4600
#define URBR2 ((volatile unsigned char*)(adr_base_uart2+0x00))
#define UTHR2 ((volatile unsigned char*)(adr_base_uart2+0x00))
#define UDLB2 ((volatile unsigned char*)(adr_base_uart2+0x00))
#define UDMB2 ((volatile unsigned char*)(adr_base_uart2+0x01))
#define UIER2 ((volatile unsigned char*)(adr_base_uart2+0x01))
#define ULCR2 ((volatile unsigned char*)(adr_base_uart2+0x03))
#define ULSR2 ((volatile unsigned char*)(adr_base_uart2+0x05))
#include <stdio.h>
#include <taskLib.h>
#include <semLib.h>
#include <logLib.h>
#include <sysLib.h>
#include <intLib.h>
#include <iv.h>
int position_dans_buffer;
char buffer[67];
void serveurIT(int);
void init_global(void);
void init(void);
void init_irq(void);
void news(void);
void news2(void);
int IDtache1;
int IDtache2;
int IDtache_news;
int IDtache_news2;
MSG_Q_ID news_box;
MSG_Q_ID news_box2;
void init_global(void){
init();
init_irq();
taskDelete(MOI);
}
void init(void){
news_box=msgQCreate(1,67,MSG_Q_FIFO);
news_box2=msgQCreate(1,67,MSG_Q_FIFO);
IDtache_news=taskSpawn("news",101,0,5000,(FUNCPTR)news,0,0,0,0,0,0,0,0,0,0);
IDtache_news2=taskSpawn("news2",101,0,5000,(FUNCPTR)news2,0,0,0,0,0,0,0,0,0,0);
printf("OS initialisé\n");
}
void init_irq(void){
STATUS erreur;
position_dans_buffer=-1;
*ULCR2=0x80;
*UDLB2=0xB7;
*UDMB2=0x06;
*ULCR2=0x03;
erreur=intConnect(10,serveurIT,0);
if(erreur!=OK)
printf("ERREUR intConnect\n");
*UIER2=0x01;
intEnable(10);
}
void serveurIT(int x){
char valeur = *URBR2;
if(position_dans_buffer==-1){
if(valeur==0x7F){
position_dans_buffer=0;
buffer[0]=0x7F;
}
}
else{
position_dans_buffer++;
buffer[position_dans_buffer]=valeur;
if(position_dans_buffer==66){
position_dans_buffer=-1;
if(buffer[1]==0){
if(msgQSend(news_box,buffer,sizeof(buffer),NO_WAIT,MSG_PRI_NORMAL)==ERROR)
logMsg("Error send mailbox (canal 0)\n",0,0,0,0,0,0);
else
logMsg("OK send mailbox (canal 0)\n",0,0,0,0,0,0);
}
else if(buffer[1]==1){
if(msgQSend(news_box2,buffer,sizeof(buffer),NO_WAIT,MSG_PRI_NORMAL)==ERROR)
logMsg("Error send mailbox (canal 1)\n",0,0,0,0,0,0);
else
logMsg("OK send mailbox (canal 1)\n",0,0,0,0,0,0);
}
else
logMsg("Probleme : mauvais numero de canal\n",0,0,0,0,0,0);
}
}
}
void news(void){
int nb_octets_recus;
char buffer2[67];
while(1){
nb_octets_recus=msgQReceive(news_box,buffer2,67,WAIT_FOREVER);
if(nb_octets_recus==67){
printf("TACHE 1 (canal 0) :\nTrame de news du canal %d :\nNuméro du paquet : %c%c%c\nNews : %s\n",buffer2[1],buffer2[2],buffer2[3],buffer2[4],buffer2+6);
}
else{
printf("Pas assez d'éléments dans le msgQueue de\n");
}
}
}
void news2(void){
int nb_octets_recus;
char buffer2[67];
while(1){
nb_octets_recus=msgQReceive(news_box2,buffer2,67,WAIT_FOREVER);
if(nb_octets_recus==67){
printf("TACHE 2 (canal 1) :\nTrame de news du canal %d :\nNuméro du paquet : %c%c%c\nNews : %s\n",buffer2[1],buffer2[2],buffer2[3],buffer2[4],buffer2+6);
}
else{
printf("Pas assez d'éléments dans le msgQueue\n");
}
}
}
Partie 3 : Développement d'un driver de news UART
Nous allons maintenant développer un driver permettant de gérer les canaux de news afin de les associer à une tâche.
Par exemple, si nous souhaitons écouter uniquement ce qu'il se passe dans le canal 0, il faudra initialiser le service complet de news puis activer le canal 0 (et l'associer à une tâche).
...................................
Vous trouverez ici la description des différentes fonctions crées :
Fonctions du driver
Vous trouverez ici la description des différentes structures crées :
Structures du driver
Voici maintenant le code complet du driver :