// ui.cc - Classe User Interface // nono - Programme du robot Efrei Robotique I1-I2 2004 // Copyright (C) 2004 Olivier Gaillard /// @file ui.cc Interface ncurses permettant de piloter adjust #include #include #include #include #include #include #include #include "ovision/oconfig.h" #include "ui.h" #include "mainui.h" using namespace std; #define BALL 1 #define GOAL 2 /// Nombre d'items du menu #define NBITEMS 14 OConfig oconfig("rc/vision.conf"); /// Items du menu principal char *itemsName[NBITEMS][2] = {{"Move color", "Permet d'ajuster les niveaux d'une couleur"}, {"Del color", "Enleve une couleur du reseau"}, {"Merge colors", "Groupe plusieurs couleurs ensembles"}, {"Select color ball", "Selectionne l'index de la couleur des balles"}, {"Select color goal", "Selectionne l'index de la couleur des poteaux"}, {"Show objets found", "Affiche les balles et poteaux trouvés"}, {"Training", "Entraine le reseau de neurones"}, {"New network", "Regenere de nouveaux poids pour le reseau"}, {"Set dist point", "Fixe les points pour la distance"}, {"Switch rgb/yuv", "Change mode rgb/yuv"}, {"Cancel changes", "Recharge le fichier de oconfig"}, {"Save changes", "Sauvegarde les changements dans le fichier"}, {"Quit", "Quitte le programme"}, {NULL, NULL}}; /// Constructor UI::UI(char *filename) { // TODO verifier que le terminal est assez grand sinon écran noir // Suppression de l'ancien fifo system("rm -f uicmds"); // Creation du fifo if (mknod("uicmds", S_IFIFO | 0666, 0) != 0 && errno != EEXIST) { cerr << "UI::UI : Error during fifo creation"; return; } // Ouverture du fifo fifo = open("uicmds", O_RDWR); if (fifo < 0) { cerr << "UI::UI : Error during fifo opening"; return; } // On choppe le pid du prog adjust situé dans le fichier adjust.PID FILE *file; file = fopen("adjust.PID", "r"); if (!file) { cerr << "UI:UI : PID file not found" << endl; exit(1); } char buf[10]; fgets(buf, 10, file); pid = atol(buf); fclose(file); curImage = 0; ParseFileList(); oconfig.LoadNNFile(); savedNNColorNumber = oconfig.nn_NbCouleurs; // Ecriture du PID dans un fichier long uiPid = getpid(); file = fopen("ui.PID", "w+"); if (!file) { cerr << "UI::UI : Error during file opening" << endl; return; } fprintf(file, "%li\n", uiPid); fclose(file); // Ouverture du fifo kill(pid, SIGUSR2); // Init ncurses initscr(); start_color(); keypad(stdscr, TRUE); cbreak(); noecho(); curs_set(0); // Init couleurs init_pair(1, COLOR_BLUE, COLOR_BLACK); init_pair(2, COLOR_RED, COLOR_BLACK); init_pair(3, COLOR_GREEN, COLOR_BLACK); init_pair(4, COLOR_CYAN, COLOR_BLACK); if (filename) { sprintf(buf, "n %s\n", filename); SendSignal(buf); } } /// Destructeur UI::~UI() { // Libere memoire unpost_menu(menu); free_menu(menu); for(int i = 0; i < NBITEMS; ++i) free_item(item[i]); endwin(); close(fifo); // Ferme adjust SIGQUIT kill(pid, SIGQUIT); system("rm -f adjust.PID ui.PID"); if (fileList) delete fileList; } /// Synchronisation des poids locaux avec ceux du programme adjust void UI::UpdateNodes() { char buf[10]; // On parcours toutes les couleurs for (int i=0; i < oconfig.nn_NbCouleurs*3; i++) { // On lis le fifo et on le copie dans le tableau node read(fifo, buf, 10); oconfig.node[i] = atoi(buf); } } /// Cree la liste d'images a ouvrir void UI::ParseFileList() { // On enleve l'ancienne liste et on en cree une nouvelle char buf[100]; sprintf(buf, "rm -Rf imagelist ; ls %s | grep -e .jpg -e .JPG -e .png -e .PNG > imagelist", oconfig.imgPath); system(buf); FILE *file; file = fopen("imagelist", "r"); if (!file) { cerr << "UI:ParseFileList : file not found" << endl; cerr << "UI:ParseFileList : use 'ls pictures_dir > imagelist" << endl; exit(1); } lengthFileList = 0; while(fgets(buf, 30, file)) lengthFileList++; rewind(file); fileList = new char*[lengthFileList]; int fileCount = 0; char *p; while (fgets(buf, 30, file)) { fileList[fileCount] = new char[30]; p = strtok(buf, "\t\n"); if (p) { strcpy(fileList[fileCount], p); fileCount++; } else lengthFileList--; } } /// Envoie une donnee au prog adjust /// @param *cmd commande a envoyer void UI::SendSignal(char *cmd) { // Ecrit dans le fifo write(fifo, cmd, 50); // Envoie un signal USR1 au prog adjust kill(pid, SIGUSR1); // Attente de la reponse de adjust SetReady(0); while (!GetReady()) { usleep(1); } } /// Affiche un msg dans la barre d'etat /// @param *str message a afficher dans la barre d'etat void UI::PrintStatus(char *str) { // Creation de la fenetre WINDOW *statusWindow = newwin(3, 60, 20, 5); wattron(statusWindow, A_BOLD | COLOR_PAIR(4)); // Affichage du texte wprintw(statusWindow, "%s\n", str); wrefresh(statusWindow); // Liberation de la memoire delwin(statusWindow); } /// Menu de selection de couleur /// @param type choix du texte des items /// @param current item selectionne au depart int UI::ChooseColor(int type, int current) { // Choix de la couleur char **colorName; // Nombre d'item a afficher if (type == NB_COULEUR) oconfig.nn_NbCouleurs = 10; // Creation des items ITEM **colorItem = new ITEM*[oconfig.nn_NbCouleurs+2]; colorName = new char*[oconfig.nn_NbCouleurs+1]; for (int i=0; i "); post_menu(colorMenu); wrefresh(colorWindow); // Affichage d'info PrintStatus("Utiliser ENTREE pour selectionner la couleur\n"); char buf[50]; int car; int col=0; if (type == NUM_COULEUR) { // Cree une image de la couleur selectionnee sprintf(buf, "s %i\n", current); SendSignal(buf); } set_current_item(colorMenu, colorItem[current]); col = current; wrefresh(colorWindow); while((car = wgetch(colorWindow)) != 10) { switch (car) { case KEY_DOWN: // Touche BAS // Deplacement dans le menu if (col < (int)oconfig.nn_NbCouleurs) { menu_driver(colorMenu, REQ_DOWN_ITEM); col++; } break; case KEY_UP: // Touche HAUT // Deplacement dans le menu if (col > 0) { menu_driver(colorMenu, REQ_UP_ITEM); col--; } break; } if ( (type == NUM_COULEUR) && (col < oconfig.nn_NbCouleurs)) { // Cree une image de la couleur selectionnee sprintf(buf, "s %i\n", col); SendSignal(buf); } wrefresh(colorWindow); } // Cas d'annulation if (col == oconfig.nn_NbCouleurs) { col = -1; // On reaffiche l'image normale SendSignal("r -1\n"); } // Liberation memoire for(int i=0; i "); menu_opts_off(mergeMenu, O_ONEVALUE); post_menu(mergeMenu); wrefresh(mergeWindow); // Initialisation de variables int c; int end = 0; int col = 0; char buf[40]; char cmd[50]; char tmp[3]; int nbColorToMerge = 0; // Cree une image de la couleur selectionnee SendSignal("s 0\n"); // Affichage d'info PrintStatus("ESPACE pour choisir les valeurs, ENTREE pour valider\n"); // Boucle du menu de selection des couleurs int indexColor = -1; while(!end) { c = wgetch(mergeWindow); switch (c) { case ' ': // Touche ESPACE // Selection d'un element menu_driver(mergeMenu, REQ_TOGGLE_ITEM); break; case KEY_DOWN: // Touche BAS // Deplacement dans le menu if (col < oconfig.nn_NbCouleurs) { menu_driver(mergeMenu, REQ_DOWN_ITEM); col++; } break; case KEY_UP: // Touche HAUT // Deplacement dans le menu if (col > 0) { menu_driver(mergeMenu, REQ_UP_ITEM); col--; } break; case 10: // Touche ENTREE // Validation des elements items = menu_items(mergeMenu); // Si l'option unmerge est choisie if ( item_index(current_item(mergeMenu)) == item_count(mergeMenu)-1) { // On remet a zero la table d'index for (int i=0; i\n"); wprintw(colorWindow, "<---------------------------------------------------->\n"); wprintw(colorWindow, "<---------------------------------------------------->\n"); // Affichage du curseur sur les lignes // ainsi que des valeurs des composantes de la couleur wattron(colorWindow, A_BOLD | COLOR_PAIR(1)); mvwprintw(colorWindow, 1, 56, "%3u", c[0]); mvwprintw(colorWindow, 1, c[0]/5+1, "*"); wattroff(colorWindow, A_BOLD | COLOR_PAIR(1)); mvwprintw(colorWindow, 2, 56, "%3u", c[1]); mvwprintw(colorWindow, 3, 56, "%3u", c[2]); mvwprintw(colorWindow, 2, c[1]/5+1, "*"); mvwprintw(colorWindow, 3, c[2]/5+1, "*"); wrefresh(colorWindow); // Boucle pour la selection des valeurs int car; while ((car = wgetch(colorWindow)) != 10) { switch(car) { case KEY_UP: // Touche HAUT if (ligne != 0) { // Mise a jour affichage mvwprintw(colorWindow, ligne+1, 56, "%3u", c[ligne]); mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "*"); ligne--; } break; case KEY_DOWN: // Touche BAS if (ligne != 2) { // Mise a jour affichage mvwprintw(colorWindow, ligne+1, 56, "%3u", c[ligne]); mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "*"); ligne++; } break; case KEY_LEFT: // Touche gauche if (c[ligne] > 0) { // Mise a jour affichage mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "-"); c[ligne]--; } break; case KEY_RIGHT: // Touche droite if (c[ligne] < 255) { // Mise a jour affichage mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "-"); c[ligne]++; } break; case KEY_NPAGE : // Touche gauche if (c[ligne] > 9) { // Mise a jour affichage mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "-"); c[ligne]-=10; } break; case KEY_PPAGE: // Touche droite if (c[ligne] < 246) { // Mise a jour affichage mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "-"); c[ligne]+=10; } break; } // Mise a jour de l'affichage des valeurs wattron(colorWindow, A_BOLD | COLOR_PAIR(1)); mvwprintw(colorWindow, ligne+1, 56, "%3u", c[ligne]); mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "*"); wattroff(colorWindow, A_BOLD | COLOR_PAIR(1)); wrefresh(colorWindow); // Communication avec adjust sprintf(cmd, "c %i %u %u %u\n", col, c[0], c[1], c[2]); SendSignal(cmd); // Affichage d'info sprintf(cmd, "Couleur %i change en %u %u %u\n", col, c[0], c[1], c[2]); PrintStatus(cmd); } // Affectation des nouvelles valeurs for (int i=0; i<3; i++) oconfig.node[col*3+i] = c[i]; // Communication avec adjust sprintf(cmd, "c %i %u %u %u\n", col, c[0], c[1], c[2]); SendSignal(cmd); // Suppression de la fenetre ecran et affichage delwin(colorWindow); colorWindow = newwin(4, 60, 12, 25); wrefresh(colorWindow); delwin(colorWindow); } // Affiche les objets et poteaux trouvés void UI::ShowObjetsFound () { // Creation de la fenetre WINDOW *winInfo = newwin(15, 60, 5, 4); // Affichage du texte SendSignal ("f\n"); char buf[20] = "start"; bool end = 1; while ( end != 0 ) { read (fifo, buf, 20); end = strcmp ("end\n", buf); if (end != 0) wprintw (winInfo, "%s", buf); } wrefresh(winInfo); // Liberation de la memoire delwin(winInfo); } void UI::NewNN (int nbColor) { char buf[20]; if (nbColor != -1) { sprintf(buf, "p %i\n", nbColor); SendSignal(buf); if (oconfig.node) delete [] oconfig.node; oconfig.node = new unsigned char[nbColor*3]; oconfig.nn_NbCouleurs = nbColor; // Synchronisation des poids avec adjust UpdateNodes(); PrintStatus("Nouveau reseau de neurones charge\n"); } } /// Affiche le menu principale void UI::Menu() { // Init items item = new ITEM*[NBITEMS]; for (int i=0; i "); set_menu_win(menu, mainWindow); set_menu_sub(menu, derwin(mainWindow, 13, 65, 3, 1)); set_menu_format(menu, NBITEMS, 1); post_menu(menu); // Actualisation de la fenetre wrefresh(mainWindow); int c; int select=0; int end=0; // Affichage de l'aide de l'item wattron(mainWindow,COLOR_PAIR(3)); mvwprintw(mainWindow, 3+select, 25, itemsName[select][1]); char buf[50]; // Boucle du menu principal while(!end) { c = wgetch(mainWindow); switch(c) { case KEY_DOWN: // Touche flèche BAS // On se déplace vers le bas menu_driver(menu, REQ_DOWN_ITEM); if (select!=NBITEMS-2) { // Efface la ligne d'aide de l'item courant mvwprintw(mainWindow,3+select, 25, "\t\t\t\t\t\t\t"); select++; } break; case KEY_UP: // Touche flèche HAUT // On se déplace vers le haut menu_driver(menu, REQ_UP_ITEM); if (select!=0) { // Efface la ligne d'aide de l'item courant mvwprintw(mainWindow,3+select, 25, "\t\t\t\t\t\t\t"); select--; } break; case 10: // Touche ENTER switch(select) { case NBITEMS-2: // Quitte le programme end=1; break; case 0: // Change les valeurs des poids du NN pour une couleur GoChangeColor(); break; case 1: // Supprime une couleur GoDelColor(); break; case 2: // Melange 2 couleurs GoMergeWindow(); break; case 3: // Selectionne la couleur a grouper GoSelectGroup(BALL); break; case 4: // Selectionne la couleur des poteaux GoSelectGroup(GOAL); break; case 5: // Affiche les balles et potraux trouvés ShowObjetsFound (); wrefresh (mainWindow); break; case 6: // Entraine le NN sprintf(buf, "t\n"); SendSignal(buf); // Synchronisation des poids avec adjust UpdateNodes(); PrintStatus("Reseau de neurones entraine\n"); break; case 7: // Regeneration de poids int nbColor; nbColor = ChooseColor(NB_COULEUR, oconfig.nn_NbCouleurs); NewNN (nbColor); break; case 8: // Set dist point SendSignal("v\n"); break; case 9: // Change mode rgb/yuv SendSignal("y\n"); if (oconfig.colorMode == RGB) oconfig.colorMode = YUV; else oconfig.colorMode = RGB; break; case 10:// Annuler les changements // Reload du fichier de poids initial oconfig.LoadNNFile(); // Envoie du nombre de couleur initial du NN et reload de l'image sprintf(buf, "r %i", savedNNColorNumber); SendSignal(buf); oconfig.nn_NbCouleurs = savedNNColorNumber; PrintStatus("Les changements ont ete annules\n"); break; case 11: // Sauver les changements // Sauvegarde des poids dans le fichier poids oconfig.CreateNNFile("rc/poids", oconfig.colorMode, oconfig.nn_NbCouleurs); // Reload du NN et de l'image a partir des nouveaux poids sprintf(buf, "r -1"); SendSignal(buf); PrintStatus("Les changements ont ete sauves\n"); break; } // END switch touche ENTER break; // Sortie du programme case 27: // ECHAP end=1; break; // Changement d'image case ' ': // Image suivante curImage++; if (curImage >= lengthFileList) curImage = 0; // Envoie de la commande pour le chargement de la nouvelle image sprintf(buf, "n %s%s\n", oconfig.imgPath, fileList[curImage]); SendSignal(buf); break; case 'g': ShowObjetsFound (); break; case 'n': NewNN (oconfig.nn_NbCouleurs); break; } // On affiche le texte d'aide de l'item correspondant mvwprintw(mainWindow, 3+select, 25, itemsName[select][1]); wrefresh(mainWindow); } delwin(mainWindow); }