| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 
 |  
// Il y a deux buffers
// - Le premier buffer contient la configuration active de l'équipement : elle ne doit être accessible qu'en lecture seule pour le code application
// - Le second buffer est une zone de travail temporaire : lorsque l'équipement reçoit une nouvelle demande de configuration (appel de writerReadersProcess_openWriter()),
//   la configuration active est copiée dans ce buffer puis le processus applicatif doit modifier la zone de travail en fonction des commandes de configuration reçues.
// => une fois toutes les commandes reçues sont traitées, la nouvelle configuration doit être appliquée au hardware de l'équipement puis les données de la zone de travail
//    sont copiées dans la configuration active en appelant writerReadersProcess_closeWriter(TRUE).
//
// Un seul processus à la fois est autorisé à travailler sur la zone de travail temporaire (writerReadersProcess_openWriter() est blocant dans qu'il y a un writer d'actif).
// Plusieurs processus à la fois sont autorisés à lire la configuration active sauf au moment de la mise à jour de celle-ci.
// La mise à jour de la configuration active n'est autorisé que s'il n'y a plus aucun processus de lecture qui travaille sur la configuration active.
//
// La gestion des semaphore est inspirée de : https://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem#Second_readers-writers_problem
// 
// writerReadersProcess_ptrRead : pointeur sur la structure en lecture seul (configuration active)
// writerReadersProcess_ptrWrite : pointeur sur la seconde structure qui est en lecture et écriture (configuration temporaire)
// writerReadersProcess_readersCounter : nombre de reader en cours
// writerReadersProcess_writersCounter : nombre de writer en cours
SemaphoreHandle_t mutex_changePersistentInfos; // accès pour modification des variables persistantes (writerReadersProcess_ptrRead, writerReadersProcess_ptrWrite et writerReadersProcess_readersCounter, writerReadersProcess_writersCounter)
 
STRUCT_CONFIG config1;
STRUCT_CONFIG config2;
STRUCT_CONFIG * writerReadersProcess_ptrRead;
STRUCT_CONFIG * writerReadersProcess_ptrWrite;
int writerReadersProcess_readersCounter;
int writerReadersProcess_writersCounter;
 
void writerReadersProcess_init(void){
	mutex_changePersistentInfos = xSemaphoreCreateMutex();
	if(mutex_changePersistentInfos == NULL){
		printf("[ERR] mutex_changePersistentInfos init\r\n");
		while(1);
	}
 
	writerReadersProcess_ptrRead = &config1;
	writerReadersProcess_ptrWrite = &config2;
 
	writerReadersProcess_readersCounter = 0;
	writerReadersProcess_writersCounter = 0;
}
 
 
// Réserve le mutex du processus de lecture
// => On peut ouvrir autant de readers que l'on veut sauf pendant que les 
//    données de writerReadersProcess_ptrWrite sont copiées dans writerReadersProcess_ptrRead.
const STRUCT_CONFIG * writerReadersProcess_openReader(void){
	STRUCT_CONFIG * ret;
 
	while(1){
		xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
		if(writerReadersProcess_writersCounter == 0){ // il n'y a plus/pas de writer actif
			break; // pour pouvoir sortir de la boucle
 
		}
		xSemaphoreGive(mutex_changePersistentInfos); // redonne la main aux autres processus pour pouvoir libérer les readers actifs
	}
 
	writerReadersProcess_readersCounter++;
	ret = writerReadersProcess_ptrRead;
	xSemaphoreGive(mutex_changePersistentInfos); // autorise un nouveau reader a être réservé
 
	return ret;
}
 
 
void writerReadersProcess_closeReader(void){
	xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
	writerReadersProcess_readersCounter--;
	xSemaphoreGive(mutex_changePersistentInfos);
}
 
 
 
// Réserve le mutex du processus d'écriture
// Copie structure des données de writerReadersProcess_ptrRead dans writerReadersProcess_ptrWrite
// => On peut réserver un writer alors qu'il y a déja des readers d'actifs car le writer n'écrit pas dans la même zone mémoire que les readers
STRUCT_CONFIG * writerReadersProcess_openWriter(void){
	while(1){
		xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
		if(writerReadersProcess_writersCounter == 0){ // il n'y a plus/pas de writer actif
			break; // pour pouvoir sortir de la boucle
 
		}
		xSemaphoreGive(mutex_changePersistentInfos); // redonne la main aux autres processus pour pouvoir libérer les readers actifs
	}
 
	// Initialisation du buffer de travail 
	memcpy(writerReadersProcess_ptrWrite, writerReadersProcess_ptrRead, sizeof(*writerReadersProcess_ptrWrite)); // 65Ko à copier avec CPU 330DMIPS	
 
	writerReadersProcess_writersCounter++;	
	xSemaphoreGive(mutex_changePersistentInfos); // autorise un nouveau reader a être réservé
 
	return writerReadersProcess_ptrWrite;
}
 
 
 
 
// Libère le mutex du processus d'écriture
// Si enableNewConfig vaut TRUE, mise à jour de writerReadersProcess_ptrRead avec valeurs de writerReadersProcess_ptrWrite
// => le changement ne se fait que s'il y a aucun reader d'ouvert
void writerReadersProcess_closeWriter(BOOL enableNewConfig){
 
	if(enableNewConfig){
		while(1){
			xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
			if(writerReadersProcess_readersCounter == 0){ // il n'y a plus/pas de reader actif
				break; // pour pouvoir sortir de la boucle
 
			}
			xSemaphoreGive(mutex_changePersistentInfos); // redonne la main aux autres processus pour pouvoir libérer les readers actifs
		}
 
		// Mise à jour de la configuration active avec les nouvelles données du buffer de travail
		memcpy(writerReadersProcess_ptrRead, writerReadersProcess_ptrWrite, sizeof(*writerReadersProcess_ptrRead));	// 65Ko à copier avec CPU 330DMIPS
 
		xSemaphoreGive(mutex_changePersistentInfos); // autorise un nouveau reader a être réservé
 
	}
 
	xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
	writerReadersProcess_writersCounter--; // Mise à jour du nombre de Writer
	xSemaphoreGive(mutex_changePersistentInfos);
} | 
Partager