Relatório TP2 - Fundamentos de Sistemas Operativos PDF

Document Details

FrugalGyrolite9375

Uploaded by FrugalGyrolite9375

LEIM

2024

Pedro Grilo, Fernando Prates, Ana Silva

Tags

sistemas operativos programação java interfaces gráficas multitarefa

Summary

Este relatório apresenta o trabalho prático 2 sobre fundamentos de sistemas operativos, focando na implementação de uma interface gráfica intuitiva com a biblioteca Swing, em Java. Descreve o desenvolvimento de uma aplicação multiprocesso para gestão e comunicação entre dois processos JAVA. O trabalho envolve a criação de GUIs para dois processos, um aproveitando o trabalho prático anterior (TP1), e um novo processo (IG) para tarefas de imitação e gravação.

Full Transcript

LEIM – Licenciatura em Engenharia Informática e Multimédia Fundamentos de Sistemas Operativos Relatório TP2 - 32D - G05 Pedro Grilo | A51319 Fernando Prates | A51635 Ana Silva | A50247 16-12-2024...

LEIM – Licenciatura em Engenharia Informática e Multimédia Fundamentos de Sistemas Operativos Relatório TP2 - 32D - G05 Pedro Grilo | A51319 Fernando Prates | A51635 Ana Silva | A50247 16-12-2024 1 Índice Introdução...................................................................................................... 5 Desenvolvimento............................................................................................. 6 Aula prática 1...................................................................................................... 6 Aula prática 2.................................................................................................... 10 Aula prática 3...................................................................................................... 6 Aula prática 4...................................................................................................... 9 Aula prática 5.................................................................................................... 12 Aula prática 6.................................................................................................... 15 Código........................................................................................................... 17 Comunicação...................................................................................................... 17 CanalComunicacao.java................................................................................... 17 CanalComunicacaoConsistente.java.................................................................. 19 Mensagem.java................................................................................................. 22 Gravador.java................................................................................................... 23 IG........................................................................................................................ 25 App..................................................................................................................... 25 Application.java................................................................................................ 25 BD.java............................................................................................................ 26 GUI.java........................................................................................................... 31 Tarefas................................................................................................................ 44 Gravar.java....................................................................................................... 44 Imitar.java........................................................................................................ 47 ITarefas.java..................................................................................................... 49 Reproduzir.java................................................................................................. 50 Tarefas.java...................................................................................................... 50 TP1...................................................................................................................... 53 App..................................................................................................................... 53 Application.java................................................................................................ 53 BD.java............................................................................................................ 54 GUI.java........................................................................................................... 58 2 Tarefas................................................................................................................ 72 Evitar.java........................................................................................................ 72 Fugir.java......................................................................................................... 73 ITarefas.java..................................................................................................... 75 Tarefa.java........................................................................................................ 76 Vaguear.java..................................................................................................... 77 Bibliografia..................................................................................................... 80 Índice Imagens Fig.1 - Aula prática 1 | GUI TP1.................................................................................................................6 Fig.2 - Aula prática 1 | GUI IG....................................................................................................................8 Fig.4 – Aula Prática 2|UML TP2 – TP1 e Comunicação..........................................................................5 Fig.5 – Aula Prática 2|UML TP2 – IG e Comunicação.............................................................................4 Fig.6 – Diagrama de estados da classe Gravar do projeto IG................................................................ 12 Fig.7– Excerto de código da classe Gravar – código que engloba os estados DORMIR e GRAVAR. 13 Fig.8 – Excerto de código da classe Gravar – código que engloba o estado REPRODUZIR e regresso a DORMIR.................................................................................................................................................. 14 Fig.9 – GUI TP1 – Finalizada.................................................................................................................... 16 3 Introdução Este trabalho tem como objetivo a implementação de uma interface gráfica intuitiva, utilizando a biblioteca Swing, e o desenvolvimento de uma aplicação multiprocesso que irá permitir a gestão e comunicação entre dois processos JAVA com memória partilhada suportada pela classe JAVA MappedByteBuffer. Um dos processos é aproveitado do primeiro trabalho prático (TP1), que já tem a comunicação com o robot sólida e estabelecida, o segundo processo será chamado IG em concordância com os comportamentos que irá adotar que serão o Imitar e o Gravar. Esta introdução prática à criação de GUIs e ao desenvolvimento de múltiplas aplicações multitarefa e a comunicação entre processos estabelece a base para a criação de sistemas mais complexos e eficientes, explorando aspetos fundamentais da comunicação e sincronização entre tarefas e processos em Java. O estabelecimento do modelo Produtor-Consumidor (TP1-IG) será dado pelo processo Comunicacao que proverá um desafio interessante para melhor compreensão de gestão entre processos e indispensável para entender e criar um sistema ainda mais intrincado e como os processos podem comunicar diretamente entre si e, neste caso, comandar os robôs a comportarem-se de forma síncrona. 4 Desenvolvimento Aula prática 1 Nesta aula estivemos a desenvolver a GUI para os nossos processos. Aproveitando a GUI do primeiro trabalho TP1 tivemos de realizar algumas alterações. Estas alterações consistiram: Na criação de um botão “Lançar IG” que lançará a GUI do processo de IG. Um campo e um botão para procurar um ficheiro onde aparecerá no campo do texto o nome do ficheiro escolhido Um botão radial para realizar o Debug, caso algo corra mal Um espaço para colocar o Nº de mensagens permitido sendo que o seu máximo será de 16 E claro, o botão radial de Abrir/Fechar Canal de comunicação entre este processo e o de IG que estará disponível após o carregar do botão de lançar IG. 5 Fig.1 - Aula prática 1 | GUI TP1 6 Seguidamente, preparámos a GUI do processo IG. Muito semelhante à GUI do TP1, sendo que as diferenças são: Campo Imitar: o Botão radial para Abrir o canal de comunicação o Botão checkbox para Ativar ou Desativar Campo Gravar: o Um campo e um botão para procurar um ficheiro onde aparecerá no campo do texto o nome do ficheiro escolhido o Um botão para Gravar o Um botão para Reproduzir o Um campo para escrever o Um botão para Limpar o Um botão checkbox para Imprimir o que foi escrito 7 Fig.2 - Aula prática 1 | GUI IG 8 Aula prática 2 A aula de hoje consistiu no mapeamento do nosso, até agora, código em UML com recurso à ferramenta MagicDraw. UML - Unified Modeling Language - trata-se de uma linguagem gráfica standard, estruturada e útil para uma melhor compreensão dos requisitos, arquitectura e design de software criado. Funciona quase que como um mapa com o objectivo de guiar os programadores, ou neste caso, nós, os alunos, a olhar para o nosso código e descobrir potenciais problemas e soluções. 9 Fig.3 – Aula Prática 2|UML TP2 Completo 10 Fig.4 – Aula Prática 2|UML TP2 – TP1 e Comunicação 11 TP1 Tarefas 1. Interface ITarefas Define os métodos que as classes Fugir, Vaguear e Evitar implementam, como executar() e bloquear(). Esta interface garante que todas as tarefas do robot seguem uma estrutura comum, facilitando a sua implementação. 2. Classes de Comportamento: Fugir, Vaguear, Evitar Estas classes implementam a interface ITarefas e contêm a lógica específica para cada comportamento do robot. Atributos: robot: Referência ao objeto do tipo RobotLegoEV3, que representa o robot controlado. gui: Um objeto GUI associado. ESTADO, distancia, angulo, etc., que ajudam a controlar o estado e o comportamento específico do robot. Operações: Cada classe tem métodos como run() e executar(), onde a lógica do comportamento específico é implementada. 12 O método bloquear(boolean bloquear) está relacionado com a sincronização ou gestão de bloqueios durante a execução das tarefas. App 1. Classe BD A classe BD (Base de Dados) armazena informações sobre o robot, como o seu estado (onOff, terminar, vaguear, evitar, fugir), bem como métodos para definir e obter esses valores. Esta classe também inclui métodos para manipular o estado e informações do robot, como setDistancia(), setAngulo(), setRobot(), entre outros. 2. Classe GUI Esta classe representa a interface gráfica do utilizador. Contém diversos componentes gráficos (ex.: JLabel, JTextField, JButton, JCheckBox), como elementos de interface que permitem a interação com o utilizador. Operações: Métodos como initGUI(), getEngineBD(), enableButtons(), e outros, indicam a configuração e manipulação da interface gráfica. 3. Classe Application 1 Esta é a classe principal que inicia o sistema. Ela configura a interface (gui) e tem o método main() que executa o programa. Relações entre as Classes As classes Fugir, Vaguear, e Evitar implementam a interface ITarefas, o que é mostrado pelas setas de herança. Estas classes encontram-se ligadas à classe Tarefa onde se encontram os métodos e atributos em comum dessas classes. A classe GUI usa a classe BD e mantém referências a instâncias das classes Fugir, Vaguear, e Evitar. A classe Application usa a classe GUI, demonstrando que esta é responsável por configurar e executar a interface gráfica. Comunicação 1.Classe Mensagem Será a classe responsável pela mensagem passar entre os processos. 2.Classe CanalDeComunicacao Classe que irá criar um canal de comunicação entre processos. 3.Classe CanalDeComunicacaoConsistente Classe de comunicação entre processos estável. 2 Relações entre as classes A classe Mensagem encontra-se ligada à classe Application tanto do processo TP1 como do processo IG. A classe de CanalDeComunicacaoConsistente herdará da classe CanalDeComunicacao e ligar-se-á à classe BD do processo TP1 e à classe Application do processo IG. 3 Fig.5 – Aula Prática 2|UML TP2 – IG e Comunicação IG O processo IG é uma cópia das Classes dos mesmos nomes de TP1 mas apenas com algumas alterações na GUI. Assim: 4 1. Classe BD A classe BD (Base de Dados) armazena informações sobre o robot, como o seu estado (onOff, terminar, vaguear, evitar, fugir), bem como métodos para definir e obter esses valores. Esta classe também inclui métodos para manipular o estado e informações do robot, como setDistancia(), setAngulo(), setRobot(), entre outros. 2. Classe GUI Esta classe representa a interface gráfica do utilizador. Contém diversos componentes gráficos (ex.: JLabel, JTextField, JButton, JCheckBox), como elementos de interface que permitem a interação com o utilizador. A diferença entre este processo e o TP1, é que são adicionados campos para Imitar e Gravar com tudo o que os involve. Operações: Métodos como initGUI(), getEngineBD(), enableButtons(), e outros, indicam a configuração e manipulação da interface gráfica. 3. Classe Application Esta é a classe principal que inicia o sistema. Ela configura a interface (gui) e tem o método main() que executa o programa. 5 Aula prática 3 A aula de hoje consistiu na elaboração das classes CanalComunicacao e CanalComunicacaoConsistente. Estas classes têm de existir para permitir a comunicação entre os processos TP1 e o IG de forma a possibilitar futuramente o caminhar sincronizado entre os robôs. CanalComunicacao Esta classe vai ser responsável por possuir métodos que permitem não só a abertura e fecho do canal de comunicação como também os métodos de receber e enviar mensagem. Começamos por criar o construtor, CanalComunicacao(), que inicializa a classe, definindo a variável indiceMensagens como 0, e deixando as variáveis de ficheiro, canal e buffer como null, preparando o objeto para ser usado. Para tal, o método de abertura do canal, abrirCanal(), vai criar um ficheiro com o nome “comunicacao.dat”. Seguidamente cria um canal de comunicação de leitura e escrita e finalmente mapeia o conteúdo do ficheiro para memória. O método receberMensagem(), como o nome indica, recebe uma mensagem e vai buscar quatro campos int (index, comando, argumento1 e argumento2) para depois convertere-la em objecto do tipo Mensagem(index, comando, argumento1, argumento2). O método enviarMensagem(Mensagem msg) que vai enviar um objecto Mensagem como uma mensagem recorrendo ao método putInt() de MappedByteBuffer para colocar a informação nos campos index, comando, argumento1 e argumento2 no buffer de forma sequencial. Depois de a 6 informação estar armazenada, o índice de mensagens é incrementado para não haver sobreposição. O método de fecho do canal, fecharCanal(), de forma aos recursos serem liberados após a finalização da sua utilização. O método getIndex() que, como o nome indica, vai buscar o indíce da mensagem. CanalComunicacaoConsistente Esta classe vai herdar da classe anterior e expandir sobre ela para implementar novos métodos: O método construtor CanalComunicacaoConsistente() que vai buscar o construtor da classe anterior pela implementação de super(). CanalLock(FileChannel canal) que recorrendo à utilização de FileLock, bloqueia o canal de maneira que apenas um processo (TP1 ou IG) esteja a utilizá-lo de cada vez sem interferências. CanalRelease(FileLock fl) liberta o canal assim que a sua utilização já não for necessária pelo processo que possui o seu acesso de momento. O método enviarMensagem(Mensagem msg) aproveitado da classe CanalComunicacao mas implementando os métodos de FileLock descritos anteriormente para garantir o acesso exclusivo do processo. 7 receberMensagem(), tal como anterior é aproveitado de CanalComunicacao mas estabilizado com o uso de FileLock para garantir o acesso exclusivo do canal. getAndSetConsumidor(Mensagem m), booleano, em que recebe a mensagem do Consumidor (IG), e se o comando da mensagem for equivalente a 0, o método envia a mensagem recebida “m” de volta para o canal, retornando true o que indica que foi bem sucedida. Senão retornará false o que indica que a operação não foi bem sucedida. E finalmente o booleano getAndSetProdutor(Mensagem m) que é idêntico ao método anterior, mas agora da parte do Produtor (TP1). 8 Aula prática 4 A aula de hoje consistiu na elaboração do código e implementação da sincronização de movimento dos dois robôs. 1. Para isso, para além dos canais de CanalComunicacao e CanalComunicacaoConsistente, foi criada a classe Mensagem, responsável por obter e tornar um objecto Mensagem (Mensagem (index, comando, argumento1, argumento2)) numa mensagem em formato String através de gets para cada campo da mensagem e pela aplicação do método toString(): public String toString() { return "indice: " + this.index +"\n" + "comando: " + this.comando +"\n" + "arg1: " + this.arg1 +"\n" + "arg2: " + this.arg2 +"\n"+ "FIM MENSAGEM"+"\n"; } 2. Foi alterada a classe BD do processo IG de forma a acomodar o canal de comunicação, nomeadamente de métodos get e setFile() de forma a obter e processar a informação do ficheiro, get e setCanalCom() para obter e definir informação do canal de comunicação e getTamanhoMensagem() para obter a informação do tamanho da mensagem. 3. Para além disto, foi adicionada na classe Application do processo IG métodos para a tarefa Imitar que permitirá o segundo robô “copiar” as acções do primeiro. 9 4. Criação da classe Imitar, responsável pela imitação de acções/comandos do primeiro robô pelo segundo robô. De maneira a conseguir fazer isto, a classe vai herdar da classe Tarefa e implementar os métodos de ITarefas. Assim ela vai buscar o canal, cria um ArrayList para a mensagem. O seu construtor vai buscar informação de GUI, adicionar mensagem se null e vai buscar informação sobre o canal. O processo run() consiste num while, que quando true, vai ter dois estados: O de BLOQUEADO onde liberta a Thread através do Thread.yield(), e uma condição onde se o estado for diferente de BLOQUEADO é lançado um print na consola da GUI "Tarefa vaguear iniciada" mudando seguidamente para o estado de EXECUTAR. O de EXECUTAR onde terá duas condições. Uma é que se o getAndSetConsumidor encontrar um objecto mensagem com todos os seus parâmetros a 0, aparecerá na consola da GUI um print da última mensagem em String existente no canal e irá adicionar uma mensagem. A segunda condição é que caso o estado seja o de BLOQUEADO, o estado actual torna-se BLOQUEADO. Na interface ITarefas foi adicionada a variável Random r que invocará o método Random() que randomizará uma acção dentro dos limites estipulados. As tarefas de TP1 Vaguear e Fugir vão receber r para randomizar os parâmetros de andamento do primeiro robô. No caso de Vaguear, r estará em distância onde, até ao limite de 90 escolherá 10 um número inteiro ao acaso (this.distancia = r.nextInt(90); ), seguidamente será o ângulo onde também escolherá um número inteiro ao acaso no mesmo limite (this.angulo = r.nextInt(90); ) e finalmente a acção que será escolhida aleatoriamente até limite de 3 (this.acao = r.nextInt(3); ). No Fugir, r irá escolher aleatoriamente na condição o próximo booleano que irá desencadear uma série de acções. 11 Aula prática 5 A aula de hoje consistiu na elaboração de UML, um diagrama de estados de forma a orientar a construção de código seguinte. Fig.6 – Diagrama de estados da classe Gravar do projeto IG 12 Explicando sucintamente o diagrama acima: Iniciando, o sistema encontra-se no estado DORMIR. O sistema sairá do estado DORMIR pela intervenção do utilizador em que poderá decidir entre os estados GRAVAR e REPRODUZIR. Supondo que o GRAVAR é ativado, ativará a parte do código gui.getBD().getGravar() que iniciará a gravação. Após a gravação de todas as mensagens do robô, ativa-se a parte do código gui.getBD().getMensagensGravar().isEmpty() e o estado do robô volta para o DORMIR. Fig.7– Excerto de código da classe Gravar – código que engloba os estados DORMIR e GRAVAR Para iniciar o estado de REPRODUZIR, será ativado a sequência de código de gui.getBD().getReproduzir(). Quando a sequência está terminada, ou por ter reproduzido todas as 13 mensagens ou por ordem do utilizador, é ativado pela negação do código anterior !gui.getBD().getReproduzir() como é denotado pelo ponto de exclamação “!” e o sistema volta ao estado DORMIR. Fig.8 – Excerto de código da classe Gravar – código que engloba o estado REPRODUZIR e regresso a DORMIR Quando o sistema está no estado DORMIR poder-se-á terminar o sistema assim que existir ordem para tal por parte do utilizador. 14 Aula prática 6 Nesta aula, foi necessário “limar algumas arestas” para que tudo corresse bem a nível de programa, GUI e de sincronização dos robôs. Foi adicionado um campo na GUI do TP1 para procura de ficheiros nomeadamente Ficheiro IG onde poderemos colocar o ficheiro adquirido após gravação para depois poder reproduzir o mesmo. Efectivamente o que irá acontecer é que o segundo robô irá reproduzir os comandos que foram gravados na execução do primeiro robô. Fig.9 – GUI TP1 – Finalizada 15 Quando experimentámos o robô ao lado do professor reparámos em alguns problemas nomeadamente: o segundo robô não voltava a imitar o primeiro quando parado por alguns minutos e voltar a ser activado. O primeiro robô (projecto TP1) apagava e reescrevia os campos do buffer sem intervenção da limpeza de mensagens por parte do processo IG do segundo robô. O botão do processo IG não tinha o comando associado. Todos estes pontos foram corrigidos de forma a conseguirmos validar positivamente o trabalho. Contudo, para melhorar a experiência do trabalho, os docentes acrescentaram um requisito a mais. Assim foi alterado o código para acomodar a nova exigência: No canal de comunicação foram adicionadas as variáveis protected int OFFSET_IDXPUT e OFFSET_IDXGET na classe CanalComunicacao de forma a controlar os índices de escrita e de leitura no buffer, optimizando a manipulação de mensagens, evitando colisões. No método de abrirCanal presente no CanalComunicacao: OFFSET_IDXPUT representa a posição onde o índice de escrita será armazenado garantindo que o programa saiba onde começar a escrever a próxima mensagem no buffer. OFFSET_IDXGET representa a posição no buffer onde o índice de leitura será armazenado. Assim o programa saberá onde deve procurar para começar a ler a próxima mensagem. @SuppressWarnings("resource") public boolean abrirCanal(String ficheiro, int n_mensagens) { try { 16 canal = new RandomAccessFile(new File(ficheiro), "rw").getChannel(); } catch (FileNotFoundException e) { System.out.println("Ficheiro não encontrado");return false;} try { buffer = canal.map(FileChannel.MapMode.READ_WRITE, 0, n_mensagens * TAMANHO_MENSAGEM + 8); this.n_mensagens = n_mensagens; index = this.loadFromBuffer(OFFSET_IDXPUT); this.storeInBuffer(OFFSET_IDXGET, index); this.OFFSET_IDXPUT = n_mensagens * TAMANHO_MENSAGEM; this.OFFSET_IDXGET = n_mensagens * TAMANHO_MENSAGEM + 4; this.limparCanal(n_mensagens); } catch (IOException e) { return false;} return true; } Temos a carga e armazenamento dos índices em: index = this.loadFromBuffer(OFFSET_IDXPUT); this.storeInBuffer(OFFSET_IDXGET, index); onde loadFromBuffer recupera o índice de escrita armazenado previamente no buffer para continuar as operações de escrita do ponto onde pararam através do método: protected int loadFromBuffer(int offset) { FileLock fl = canalLock(); int posInit = buffer.position(); buffer.position(offset); int value = buffer.getInt(); buffer.position(posInit); canalRelease(fl); 17 return value; } E storeInBuffer vai armazenar o índice de leitura inicial no buffer sincronizando o estado de leitura através do seu método: protected void storeInBuffer(int offset, int value) { FileLock fl = canalLock(); int posInit = buffer.position(); buffer.position(offset); buffer.putInt(value); buffer.position(posInit); canalRelease(fl); Thread.yield(); } Os Offsets são iniciados em: this.OFFSET_IDXPUT = n_mensagens * TAMANHO_MENSAGEM; this.OFFSET_IDXGET = n_mensagens * TAMANHO_MENSAGEM + 4; sendo que OFFSET_IDXPUT aqui é definido para ocupar 4 bytes (igual a um inteiro ((int))) logo após a última mensagem. E OFFSET_IDXGET ocupa os 4 bytes seguintes. Depois dos offsets serem definidos, o canal é limpo com: this.limparCanal(n_mensagens); garantindo assim que o buffer fique pronto para uso sendo que as mensagens antigas são eliminadas e os índices voltam a sofrer sincronização. 18 19 Código Comunicação CanalComunicacao.java package Comunicacao; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; public class CanalComunicacao { protected FileChannel canal; protected MappedByteBuffer buffer; //número de bytes numa mensagem protected int TAMANHO_MENSAGEM = 16; public CanalComunicacao(){ canal= null; buffer= null; } @SuppressWarnings("resource") public boolean abrirCanal(String ficheiro, int n_mensagens) { try { canal = new RandomAccessFile(new File(ficheiro), "rw").getChannel(); } catch (FileNotFoundException e) { System.out.println("Ficheiro não encontrado");return false;} try { buffer = canal.map(FileChannel.MapMode.READ_WRITE, 0, n_mensagens * TAMANHO_MENSAGEM); } catch (IOException e) { return false;} return true; } public void fecharCanal() { if (canal!=null) 20 try { canal.close(); } catch (IOException e) { canal= null; } } //recebe 4 ints seguidos e interpreta-os como uma mensagem public Mensagem receberMensagem() { int[] params = new int; for (int i = 0; i < 4; i++){ params[i] = buffer.getInt(); } //se chegar ao fim do buffer, volta ao inicio if(!buffer.hasRemaining()) { buffer.position(0); } return new Mensagem(params, params, params, params); } //percorre o canal de comunicacao e limpa-o, enviando mensagens vazias public void limparCanal(int n_mensagens) { for (int i = 0; i < n_mensagens; i++) { enviarMensagem(new Mensagem(0,0,0,0)); } } //envia uma mensagem para o canal no formato de 4 ints seguidos public void enviarMensagem(Mensagem msg) { int[] params = {msg.getIndex(), msg.getComando(), msg.getArg1(), msg.getArg2()}; for (int i = 0; i < 4; i++){ buffer.putInt(params[i]); } //se chegar ao fim do buffer, volta ao inicio if(!buffer.hasRemaining()) { buffer.position(0); } } public int getTamanhoMensage() { return this.TAMANHO_MENSAGEM; }} 21 CanalComunicacaoConsistente.java package Comunicacao; import java.io.IOException; import java.nio.channels.FileLock; public class CanalComunicacaoConsistente extends CanalComunicacao { private int index; private Mensagem ultimaMensagemLida; public CanalComunicacaoConsistente() { this.index = 0; } public FileLock canalLock() { try { return super.canal.lock(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } public void canalRelease(FileLock fl) { try { fl.release(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); 22 } } @Override public void enviarMensagem(Mensagem msg) { FileLock fl = canalLock(); super.enviarMensagem(msg); canalRelease(fl); } @Override public Mensagem receberMensagem() { FileLock fl = canalLock(); Mensagem msg = super.receberMensagem(); canalRelease(fl); return msg; } public boolean getAndSetProdutor(Mensagem m) { Mensagem msg = receberMensagem(); //envia mensagem apenas houver um espaço vazio if(msg.getComando() == 0) { //reposiciona o buffer para escrever no slot vazio if(buffer.position() != 0) { buffer.position(buffer.position() - TAMANHO_MENSAGEM); } else buffer.position(buffer.capacity() - TAMANHO_MENSAGEM); this.enviarMensagem(m); index++; 23 return true; } return false; } public boolean getAndSetConsumidor() { Mensagem msg = receberMensagem(); //lê as mensagens e substitui por mensagens vazias, ignora mensagens vazias if(msg.getComando() == 0) { return false; } else { //reposiciona o buffer para limpar a mensagem lida if(buffer.position() != 0) { buffer.position(buffer.position() - TAMANHO_MENSAGEM); } else buffer.position(buffer.capacity() - TAMANHO_MENSAGEM); this.enviarMensagem(new Mensagem(0,0,0,0)); this.ultimaMensagemLida = msg; index++; return true; } } public int getIndex() { return this.index; } public Mensagem getUltimaMensagemLida() { return this.ultimaMensagemLida; } } 24 Mensagem.java package Comunicacao; import robot.RobotLegoEV3; public class Mensagem { private int index; private int comando; private int arg1; private int arg2; public Mensagem(int index, int comando, int arg1, int arg2){ this.index = index; this.comando = comando; this.arg1 = arg1; this.arg2 = arg2; } public int getIndex() { return this.index; } public int getComando() { return this.comando; } public int getArg1() { return this.arg1; } public int getArg2() { return this.arg2; } public void setTimestamp(long t) { this.index = (int)t; } public long getTimestamp() { return this.index; } public void executarComandoMensagem(RobotLegoEV3 robot) { switch (comando){ case 1: robot.Reta(arg1); break; case 2: robot.CurvarDireita(arg1, arg2); break; 25 case 3: robot.CurvarEsquerda(arg1, arg2); break; case 4: robot.Parar(true); break; default: break; } } public String toString() { return "indice/tempo: " + this.index +" | " + "comando: " + this.comando +" | " + "arg1: " + this.arg1 +" | " + "arg2: " + this.arg2; } } Gravador.java package Comunicacao; import java.io.IOException; import java.nio.channels.FileLock; import java.util.ArrayList; public class Gravador extends CanalComunicacao{ public Gravador() { super(); super.TAMANHO_MENSAGEM = 16; } @Override public void enviarMensagem(Mensagem msg) { FileLock fl = canalLock(); int[] params = {msg.getIndex(), msg.getComando(), msg.getArg1(), msg.getArg2()}; for (int i = 0; i < 4; i++){ buffer.putInt(params[i]); } canalRelease(fl); } @Override public Mensagem receberMensagem() { 26 FileLock fl = canalLock(); int[] params = new int; for (int i = 0; i < 4; i++){ params[i] = buffer.getInt(); } canalRelease(fl); return new Mensagem(params, params, params, params); } public ArrayList lerMensagens(int n_mensagens) { ArrayList mensagens = new ArrayList(); buffer.position(0); for (int i = 0; i < n_mensagens; i++) { if (buffer.remaining() >= TAMANHO_MENSAGEM) { mensagens.add(receberMensagem()); } else { break; } } return mensagens; } public FileLock canalLock() { try { return super.canal.lock(); } catch (IOException e) { e.printStackTrace(); } return null; } public void canalRelease(FileLock fl) { try { fl.release(); } catch (IOException e) { e.printStackTrace(); } } } 27 IG App Application.java package App; import java.io.File; import Tarefas.Gravar; import Tarefas.Imitar; public class Application { private GUI gui; private Gravar gravar; private Imitar imitar; public Application() { gui = new GUI(this); imitar = new Imitar(gui); gravar = new Gravar(gui); } public void run(String[] args) { if(args.length != 0) { //receber dados do processo TP1 gui.getBd().setFileCom(new File(args)); gui.getBd().setTamanhoMensagem(Integer.parseInt(args)); //substituir por path do ficheiro de comunicação para poder dar debug ao lançar no IDE } else gui.getBd().setFileCom(new File("C:\\Users\\kingofthevoi\\Documents\\FSO\\comunicacao.txt")) ; imitar.start(); imitar.pausar(); 28 gravar.start(); gravar.pausar(); while(!gui.getBd().isTerminar()) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } gui.getBd().getCanal().fecharCanal(); gui.fecharRobot(); } public static void main(String[] args) { Application app = new Application(); System.out.println("A aplicação começou!"); app.run(args); System.out.println("A aplicação terminou!"); } public Gravar getGravar() { return this.gravar; } public Imitar getImitar() { return this.imitar; } } BD.java package App; import java.io.File; import java.util.ArrayList; import Comunicacao.CanalComunicacaoConsistente; import Comunicacao.Mensagem; import robot.RobotLegoEV3; public class BD { 29 private RobotLegoEV3 robot; private String nomeRobot; private File fileCom; private File fileGravar; private int distancia; private int angulo; private int tamanhoMensagem; private boolean Debug; private boolean onOff; private boolean terminar; private boolean imitar; private boolean canalCom; private boolean gravar; private boolean reproduzir; private boolean imprimir; private boolean lerCanal; private CanalComunicacaoConsistente canal; private ArrayList mensagensGravar; public BD() { robot = new RobotLegoEV3(); canal = new CanalComunicacaoConsistente(); distancia = 20; angulo = 45; Debug = false; onOff = false; terminar = false; imitar = false; canalCom = false; gravar = false; reproduzir = false; imprimir = false; lerCanal = false; mensagensGravar = new ArrayList(); this.tamanhoMensagem = 8; } public RobotLegoEV3 getRobot() { return robot; } 30 public void setRobot(RobotLegoEV3 robot) { this.robot = robot; } public String getNomeRobot() { return nomeRobot; } public void setNomeRobot(String nomeRobot) { this.nomeRobot = nomeRobot; } public void setAngulo(int angulo) { this.angulo = angulo; } public int getAngulo() { return this.angulo; } public int getDistancia() { return distancia; } public void setDistancia(int distancia) { this.distancia = distancia; } public boolean isOnOff() { return onOff; 31 } public void setOnOff(boolean onOff) { this.onOff = onOff; } public boolean isDebug() { return this.Debug; } public void setDebug(boolean debug) { this.Debug = debug; } public boolean isTerminar() { return terminar; } public void setTerminar(boolean terminar) { this.terminar = terminar; } public void setFileCom(File fileCom) { this.fileCom = fileCom; } public File getFileCom() { return this.fileCom; } public boolean getImitar() { return this.imitar; } public void setImitar(boolean imitar) { this.imitar = imitar; } 32 public boolean getCanalCom() { return this.canalCom; } public void setCanalCom(boolean canalCom) { this.canalCom = canalCom; } public int getTamanhoMensagem() { return this.tamanhoMensagem; } public void setTamanhoMensagem(int tamanhoMensagem) { this.tamanhoMensagem = tamanhoMensagem; } public void setGravar(boolean gravar) { this.gravar = gravar; } public boolean getGravar() { return this.gravar; } public void setReproduzir(boolean reproduzir) { this.reproduzir = reproduzir; } public boolean getReproduzir() { return this.reproduzir; } public File getFileGravar() { return this.fileGravar; } public void setFileGravar(File fileGravar) { this.fileGravar = fileGravar; } public void setImprimir(boolean imprimir) { this.imprimir = imprimir; } public boolean getImprimir() { return this.imprimir; } 33 public boolean getLerCanal() { return this.lerCanal; } public CanalComunicacaoConsistente getCanal() { return this.canal; } public void setLerCanal(boolean lerCanal) { this.lerCanal = lerCanal; } public ArrayList getMensagensGravar() { return this.mensagensGravar; } } GUI.java package App; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.border.EmptyBorder; import com.formdev.flatlaf.themes.FlatMacLightLaf; import java.awt.Font; import javax.swing.JCheckBox; import java.awt.Color; 34 import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.JFileChooser; import javax.swing.ScrollPaneConstants; public class GUI extends JFrame { private static final long serialVersionUID = 1L; private JPanel contentPane; private JLabel lblRobotNome; //Variables private BD bd; private Application app; private JRadioButton rdbtnOnOff; private JTextArea textAreaConsola; private JTextField textFieldNome; private JTextField textFieldConsola; private JButton btnRight; private JButton btnForward; private JButton btnLeft; private JButton btnStop; private JButton btnBackwards; private JTextField textFieldFicheiro; final JFileChooser fc = new JFileChooser(); private JButton btnGravar; private JButton btnReproduzir; private JButton btnLimpar; private long logCode; private long startTime; public void myPrint(String S) { EventQueue.invokeLater(new Runnable() { public void run() { try { textAreaConsola.append('\n' + getCurrentTimeFormated() + S); textFieldConsola.setText(S); }catch (Exception e) { e.printStackTrace(); 35 } //se imprimir for selecionado, passa a imprimir todas as mensagens da consola para um ficheiro txt para facilitar debugging if(bd.getImprimir()) log('\n' + getCurrentTimeFormated() +S, "IG_log_"+logCode+".txt"); } }); } //retorna timestamps usadas na consola private String getCurrentTimeFormated () { long t = System.currentTimeMillis() - startTime; long minutes = (t / 1000) / 60; long seconds = (t / 1000) % 60; return "["+minutes+":"+seconds+"] "; } //imprime strings para um ficheiro, usado para dar log dos conteudos da consola private void log(String S, String filepath) { try { PrintWriter out = new PrintWriter(new FileWriter(filepath, true), true); out.write(S); out.close(); } catch (IOException e) { e.printStackTrace(); } } private void initGUI() { EventQueue.invokeLater(new Runnable() { public void run() { try { UIManager.setLookAndFeel(new FlatMacLightLaf()); setDefaultCloseOperation(JFrame. EXIT_ON_CLOSE); setBounds(100, 100, 479, 691); contentPane = new JPanel(); 36 contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); getContentPane().setLayout(null); lblRobotNome = new JLabel("Nome:"); lblRobotNome.setHorizontalAlignment(SwingConstants. CENTER); lblRobotNome.setBounds(20, 39, 46, 14); getContentPane().add(lblRobotNome); rdbtnOnOff = new JRadioButton("On/Off"); rdbtnOnOff.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { bd.setNomeRobot(textFieldNome.getText()); bd.setOnOff(!bd.isOnOff()); if(bd.isOnOff()) { if(!initRobot()) { myPrint("Erro ao iniciar o robot"); rdbtnOnOff.setSelected(false); bd.setOnOff(false); } else { enableButtons(); myPrint("Sucesso ao iniciar o robot "+ bd.getNomeRobot()); } } else { disableButtons(); fecharRobot(); } } }); rdbtnOnOff.setBounds(306, 35, 68, 23); getContentPane().add(rdbtnOnOff); JRadioButton rdbtnDebug = new JRadioButton("Debug"); rdbtnDebug.addActionListener(new ActionListener() { 37 public void actionPerformed(ActionEvent e) { bd.setDebug(!bd.isDebug()); if(bd.isDebug()) { myPrint("Modo Debug inicializado"); enableButtons(); } else { myPrint("Modo Debug terminado"); disableButtons(); } } }); rdbtnDebug.setBounds(376, 35, 75, 23); contentPane.add(rdbtnDebug); textFieldNome = new JTextField(); textFieldNome.setBounds(76, 36, 224, 20); getContentPane().add(textFieldNome); textFieldNome.setColumns(10); JScrollPane scrollPane = new JScrollPane(); scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants. HORIZONTAL_SCROLLBAR_NEVER); scrollPane.setBounds(9, 365, 442, 188); contentPane.add(scrollPane); textAreaConsola = new JTextArea(); scrollPane.setViewportView(textAreaConsola); textAreaConsola.setFont(new Font("Monospaced", Font.BOLD, 13)); textAreaConsola.setEnabled(false); textAreaConsola.setEditable(false); btnForward = new JButton("Frente"); btnForward.setEnabled(false); btnForward.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { 38 myPrint("Robot a andar para a frente " + bd.getDistancia()+" cm"); bd.getRobot().Parar(false); } }); btnForward.setFont(new Font("Tahoma", Font.PLAIN, 11)); btnForward.setBounds(184, 84, 90, 20); contentPane.add(btnForward); btnRight = new JButton("Direita"); btnRight.setEnabled(false); btnRight.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { myPrint("Robot a virar à direita com raio " + bd.getDistancia()+" cm e ângulo "+ bd.getAngulo()+"º"); bd.getRobot().Parar(false); } }); btnRight.setBounds(284, 117, 90, 20); contentPane.add(btnRight); btnLeft = new JButton("Esquerda"); btnLeft.setEnabled(false); btnLeft.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { myPrint("Robot a virar à esquerda com raio" + bd.getDistancia()+" cm e ângulo"+ bd.getAngulo()+"º"); bd.getRobot().Parar(false); } }); btnLeft.setBounds(87, 116, 90, 20); contentPane.add(btnLeft); btnStop = new JButton("Parar"); btnStop.setEnabled(false); btnStop.setBackground(new Color(255, 255, 255)); btnStop.addActionListener(new ActionListener() { 39 public void actionPerformed(ActionEvent arg0) { myPrint("Robot a parar"); bd.getRobot().Parar(true); } }); btnStop.setBounds(184, 116, 90, 20); contentPane.add(btnStop); btnBackwards = new JButton("Trás"); btnBackwards.setEnabled(false); btnBackwards.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { myPrint("Robot a andar para trás " + bd.getDistancia()+" cm"); bd.getRobot().Parar(false); } }); btnBackwards.setBounds(184, 147, 90, 20); contentPane.add(btnBackwards); JLabel lblRobotNome_1 = new JLabel("Robot"); lblRobotNome_1.setFont(new Font("Tahoma", Font.BOLD, 12)); lblRobotNome_1.setHorizontalAlignment(SwingConstants. LEFT); lblRobotNome_1.setBounds(10, 11, 46, 14); contentPane.add(lblRobotNome_1); textFieldFicheiro = new JTextField(); textFieldFicheiro.setEditable(false); textFieldFicheiro.setText(""); textFieldFicheiro.setBounds(95, 261, 279, 20); contentPane.add(textFieldFicheiro); textFieldFicheiro.setColumns(10); JLabel lblFicheiro = new JLabel("Ficheiro Gravação:"); lblFicheiro.setBounds(0, 264, 90, 14); contentPane.add(lblFicheiro); btnGravar = new JButton("Gravar"); 40 btnGravar.setEnabled(false); btnGravar.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { bd.setGravar(!bd.getGravar()); if(bd.getGravar()) { app.getGravar().retomarGravar(); } updateBtnGravar(); } }); btnGravar.setBounds(128, 292, 89, 23); contentPane.add(btnGravar); btnReproduzir = new JButton("Reproduzir"); btnReproduzir.setEnabled(false); btnReproduzir.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { bd.setReproduzir(!bd.getReproduzir()); if(bd.getReproduzir()) { app.getGravar().retomarReproduzir(); } updateBtnReproduzir(); } }); JButton btnFileChooser = new JButton("Browse"); btnFileChooser.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { if (fc.showOpenDialog(GUI.this) == JFileChooser.APPROVE_OPTION) { bd.setFileGravar(fc.getSelectedFile()); textFieldFicheiro.setText(bd.getFileGravar().getAbsolutePath()); 41 if(bd.getFileGravar() != null) btnReproduzir.setEnabled(true); btnGravar.setEnabled(true); } } }); btnFileChooser.setBounds(376, 260, 89, 23); contentPane.add(btnFileChooser); btnReproduzir.setBounds(223, 292, 106, 23); contentPane.add(btnReproduzir); btnLimpar = new JButton("Limpar"); btnLimpar.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { textAreaConsola.setText(""); textFieldConsola.setText(""); } }); btnLimpar.setFont(new Font("Tahoma", Font.PLAIN, 12)); btnLimpar.setBounds(128, 613, 89, 23); contentPane.add(btnLimpar); JCheckBox chckbxImprimir = new JCheckBox("Imprimir"); chckbxImprimir.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if(!bd.getImprimir()) { logCode = System.currentTimeMillis(); } bd.setImprimir(!bd.getImprimir()); } }); chckbxImprimir.setFont(new Font("Tahoma", Font.PLAIN, 12)); chckbxImprimir.setBounds(237, 613, 75, 23); contentPane.add(chckbxImprimir); 42 JLabel lblRobotNome_1_1 = new JLabel("Consola"); lblRobotNome_1_1.setHorizontalAlignment(SwingConstants.LEFT) ; lblRobotNome_1_1.setFont(new Font("Tahoma", Font.BOLD, 12)); lblRobotNome_1_1.setBounds(10, 340, 56, 14); contentPane.add(lblRobotNome_1_1); JLabel lblRobotNome_1_2 = new JLabel("Gravar"); lblRobotNome_1_2.setHorizontalAlignment(SwingConstants.LEFT) ; lblRobotNome_1_2.setFont(new Font("Tahoma", Font.BOLD, 12)); lblRobotNome_1_2.setBounds(10, 239, 46, 14); contentPane.add(lblRobotNome_1_2); JLabel lblRobotNome_1_3 = new JLabel("Imitar"); lblRobotNome_1_3.setHorizontalAlignment(SwingConstants.LEFT) ; lblRobotNome_1_3.setFont(new Font("Tahoma", Font.BOLD, 12)); lblRobotNome_1_3.setBounds(10, 173, 46, 14); contentPane.add(lblRobotNome_1_3); JCheckBox chckbxAtivardesativar = new JCheckBox("Ativar/Desativar"); chckbxAtivardesativar.setEnabled(false); chckbxAtivardesativar.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { bd.setImitar(!bd.getImitar()); if(bd.getImitar() || !bd.getLerCanal()) { bd.setLerCanal(true); app.getImitar().retomar(); } 43 if(!bd.getImitar()) { bd.getRobot().Parar(true); } } }); chckbxAtivardesativar.setFont(new Font("Tahoma", Font.PLAIN, 12)); chckbxAtivardesativar.setBounds(334, 194, 117, 23); contentPane.add(chckbxAtivardesativar); JRadioButton rdbtnAbrirCanalComunio = new JRadioButton("Abrir Canal Comunicação"); rdbtnAbrirCanalComunio.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if(!bd.getCanalCom()) { //ABRIR CANAL DE COMUNICAÇÃO myPrint("Canal de Comunicação aberto no ficheiro "+bd.getFileCom().getName()); bd.setCanalCom(bd.getCanal().abrirCanal(bd.getFileCom().getA bsolutePath(), bd.getTamanhoMensagem())); chckbxAtivardesativar.setEnabled(true); if(bd.getImitar()) app.getImitar().retomar(); } else { //FECHAR CANAL DE COMUNICAÇÃO myPrint("Canal de Comunicacao Fechado"); bd.setCanalCom(false); //bd.setLerCanal(false); //bd.setImitar(false); app.getImitar().pausar(); chckbxAtivardesativar.setEnabled(false); //chckbxAtivardesativar.setSelected(false); bd.getCanal().fecharCanal(); } } 44 }); rdbtnAbrirCanalComunio.setFont(new Font("Tahoma", Font.PLAIN, 12)); rdbtnAbrirCanalComunio.setBounds(20, 194, 167, 23); contentPane.add(rdbtnAbrirCanalComunio); textFieldConsola = new JTextField(); textFieldConsola.setBounds(9, 552, 442, 23); contentPane.add(textFieldConsola); textFieldConsola.setEditable(false); textFieldConsola.setColumns(10); setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } public BD getBd() { return bd; } public GUI(Application app) { setTitle("Imitar & Gravar"); startTime = System.currentTimeMillis(); bd = new BD(); this.app = app; initGUI(); } public void enableButtons() { btnRight.setEnabled(true); btnLeft.setEnabled(true); btnForward.setEnabled(true); btnStop.setEnabled(true); 45 btnBackwards.setEnabled(true); } public void disableButtons() { btnRight.setEnabled(false); btnLeft.setEnabled(false); btnForward.setEnabled(false); btnStop.setEnabled(false); btnBackwards.setEnabled(false); } public void updateBtnGravar() { if(bd.getGravar()) { btnReproduzir.setEnabled(false); btnGravar.setText("Parar Gravação"); } else { btnReproduzir.setEnabled(true); btnGravar.setText("Gravar"); } } public void updateBtnReproduzir() { if(bd.getReproduzir()) { btnGravar.setEnabled(false); btnReproduzir.setText("Parar Reprodução"); } else { btnGravar.setEnabled(true); btnReproduzir.setText("Reproduzir"); } } public boolean initRobot() { myPrint("A inicializar robot..."); return bd.getRobot().OpenEV3(bd.getNomeRobot()); } public void fecharRobot() { bd.getRobot().CloseEV3(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } myPrint("Comunicação com o robot terminada"); } 46 } Tarefas Gravar.java package Tarefas; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import App.GUI; import Comunicacao.Gravador; import Comunicacao.Mensagem; public class Gravar extends Tarefa implements ITarefas{ private int tamanhoGravar; private Gravador gravador; private String file; private long tempoInicio; ArrayList mensagens; long timeStart; public Gravar(GUI gui) { super(gui); this.gravador = new Gravador(); this.bloqueado = false; file = null; } public void run() { while(true) { switch(ESTADO) { case DORMIR: Dormir(); Thread.yield(); break; case GRAVAR: 47 this.file = gui.getBd().getFileGravar().getAbsolutePath(); gui.myPrint("Gravação Iniciada"); //limpar ficheiro de gravação antes de gravar //se forem gravadas menos mensagens que existiam no ficheiro, vão aparecer mensagens vazias no fim dele this.tamanhoGravar = getFileSize(file); if(gravador.abrirCanal(file, tamanhoGravar)) { gravador.limparCanal(tamanhoGravar); gravador.fecharCanal(); } //esperar que o utilizador volte a carregar no botão de gravar para saber quando deixam de ser colocadas mensagens no Arraylist while(gui.getBd().getGravar()) Thread.yield();; //enviar as mensagens que foram colocadas no ArrayList, no ficheiro de gravação //esvazia o ArrayList à medida que mensagens são colocadas //para quando não houver mais mensagens no ArrayList this.tamanhoGravar = gui.getBd().getMensagensGravar().size(); if(gravador.abrirCanal(file, tamanhoGravar)){ while(!gui.getBd().getMensagensGravar().isEmpty()) { gui.myPrint(file); gravador.enviarMensagem(gui.getBd().getMensagensGravar().get (0)); gui.getBd().getMensagensGravar().remove(0); } gravador.fecharCanal(); } else gui.myPrint("Ficheiro Inválido"); gui.myPrint("Gravação Terminada"); this.pausar(); break; case REPRODUZIR: 48 this.file = gui.getBd().getFileGravar().getAbsolutePath(); gui.myPrint("Reprodução Iniciada"); this.tamanhoGravar = getFileSize(file); //abre um canal de tamanho igual ao tamanho do ficheiro if(gravador.abrirCanal(file, tamanhoGravar)) { //lê as mensagens todas no ficheiro de gravação e retorna-as num ArrayList mensagens = gravador.lerMensagens(tamanhoGravar); gravador.fecharCanal(); tempoInicio = System.currentTimeMillis(); for(int i = 0; i= msg.getTimestamp()) { //acaba a reprodução se encontrar uma mensagem vazia //acontece apenas quando foi usada a funcionalidade de gravar num ficheiro maior do que a gravação obtida if(msg.getComando() == 0) break; msg.executarComandoMensagem(robot); gui.myPrint(msg.toString()); } else i--; } //para o robot ao completar a reprodução this.robot.Parar(true); //limpa o ArrayList de reprodução 49 mensagens.clear(); } else gui.myPrint("Ficheiro Inválido"); gui.myPrint("Reprodução Finalizada"); gui.getBd().setReproduzir(false); gui.updateBtnReproduzir(); this.pausar(); break; } } } public void setFile(File file) { this.file = file.getAbsolutePath(); } public void retomarGravar() { pausar.release(); ESTADO = GRAVAR; } public void retomarReproduzir() { pausar.release(); ESTADO = REPRODUZIR; } @SuppressWarnings("null") //retorna o número de mensagens num ficheiro private int getFileSize(String fileName) { Path path = Paths.get(fileName); try { // size of a file (in bytes) return (int) Files.size(path) / gravador.getTamanhoMensage(); } catch (IOException e) { e.printStackTrace(); return (Integer) null; } } } Imitar.java package Tarefas; 50 import java.util.ArrayList; import App.GUI; import Comunicacao.CanalComunicacaoConsistente; import Comunicacao.Mensagem; public class Imitar extends Tarefa implements ITarefas{ CanalComunicacaoConsistente canal; private ArrayList mensagens = new ArrayList(); private long tempoInicio; private boolean tempoGravado; private boolean pararImitar; public Imitar(GUI gui) { super(gui); mensagens.add(null); this.canal = gui.getBd().getCanal(); this.tempoGravado = false; this.pararImitar = false; } public void run() { while(true) { switch(ESTADO) { case DORMIR: Thread.yield(); Dormir(); break; case EXECUTAR: mensagens = new ArrayList(); if(gui.getBd().getCanalCom()) { if(canal.getAndSetConsumidor()) { //adiciona as mensagens recebidas a um ArrayList local Mensagem msg = canal.getUltimaMensagemLida(); mensagens.add(msg); gui.myPrint(msg.toString()); //enquanto gravar estiver ativado, deposita as mensagens recebidas num ArrayList, tendo em conta timeStamps if(gui.getBd().getGravar()) { if(!tempoGravado) { tempoInicio = System.currentTimeMillis(); 51 tempoGravado = true; } msg.setTimestamp(System.currentTimeMillis() - tempoInicio); if(gui.getBd().getImitar()) { gui.getBd().getMensagensGravar().add(msg); this.pararImitar = false; } else if (!pararImitar) { gui.getBd().getMensagensGravar().add(new Mensagem((int)(System.currentTimeMillis() - tempoInicio), 4, 0,0)); pararImitar = true; } } else tempoGravado = false; } } //envia as mensagens no ArrayList local ao robot, esvazia o ArrayList à medida que são enviadas //só envia as mensagens se imitar estiver ativado if(!mensagens.isEmpty()) { if(gui.getBd().getImitar() && !gui.getBd().getReproduzir()) { mensagens.get(0).executarComandoMensagem(robot); } mensagens.remove(0); } break; } } } } ITarefas.java package Tarefas; import java.util.Random; 52 public interface ITarefas{ final int DORMIR = 1; final int EXECUTAR = 2; final int GRAVAR = 3; final int REPRODUZIR = 4; final int VIRAR_ESQUERDA = 1; final int VIRAR_DIREITA = 2; final int ANDAR_FRENTE = 3; static Random r = new Random(); } Reproduzir.java package Tarefas; import App.GUI; public class Reproduzir extends Tarefa implements ITarefas{ public Reproduzir(GUI gui) { super(gui); // TODO Auto-generated constructor stub } public void run() { while(true) { } } } Tarefas.java package Tarefas; 53 import java.util.concurrent.Semaphore; import App.GUI; import robot.RobotLegoEV3; public class Tarefa extends Thread implements ITarefas{ protected GUI gui; protected RobotLegoEV3 robot; protected Semaphore pausar; protected int ESTADO; protected boolean bloqueado; public Tarefa(GUI gui) { this.gui = gui; this.robot = gui.getBd().getRobot(); this.bloqueado = true; this.ESTADO = DORMIR; pausar = new Semaphore(1); } public void bloquear(boolean bloquear) { this.bloqueado = bloquear; } public void pausar() { pausar.drainPermits(); ESTADO = DORMIR; } public void retomar() { pausar.release(); ESTADO = EXECUTAR; } protected void Dormir() { try { pausar.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } } protected void trySleep(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { 54 e.printStackTrace(); } } } 55 TP1 App Application.java package App; import Tarefas.Evitar; import Tarefas.Fugir; import Tarefas.Vaguear; public class Application { private GUI gui; private Vaguear vaguear; private Evitar evitar; private Fugir fugir; public Application() { gui = new GUI(); vaguear = new Vaguear(gui, gui.getCanal()); evitar = new Evitar(gui); fugir = new Fugir(gui); fugir.setVaguear(vaguear); evitar.setVaguear(vaguear); evitar.setFugir(fugir); } private void run() { vaguear.start(); evitar.start(); fugir.start(); while(!gui.getBd().isTerminar()) { evitar.bloquear(!gui.getBd().getEvitar()); fugir.bloquear(!gui.getBd().getFugir()); vaguear.bloquear(!gui.getBd().getVaguear()); 56 try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } gui.fecharRobot(); } public static void main(String[] args) { Application app = new Application(); System.out.println("A aplicação começou!"); app.run(); System.out.println("A aplicação terminou!"); } } BD.java package App; import java.io.File; import java.util.concurrent.Semaphore; import robot.RobotLegoEV3; public class BD { private RobotLegoEV3 robot; private String nomeRobot; private File file; private int distancia; private int angulo; private int tamanhoMensagem; private boolean canalCom; private boolean Debug; private boolean onOff; private boolean terminar; private boolean vaguear; private boolean evitar; private boolean fugir; private Semaphore acessoRobot; private String jarPath; public BD() { 57 robot = new RobotLegoEV3(); acessoRobot = new Semaphore(1); tamanhoMensagem = 8; canalCom = false; Debug = false; onOff = false; terminar = false; vaguear = false; evitar = false; fugir = false; } public RobotLegoEV3 getRobot() { return robot; } public void setRobot(RobotLegoEV3 robot) { this.robot = robot; } public String getNomeRobot() { return nomeRobot; } public void setNomeRobot(String nomeRobot) { this.nomeRobot = nomeRobot; } public void setAngulo(int angulo) { this.angulo = angulo; } public int getAngulo() { return this.angulo; } public int getDistancia() { return distancia; } public void setDistancia(int distancia) { this.distancia = distancia; } public boolean isOnOff() { return onOff; } public void setOnOff(boolean onOff) { this.onOff = onOff; } public boolean isDebug() { return this.Debug; } public void setDebug(boolean debug) { this.Debug = debug; } public boolean isTerminar() { return terminar; } public void setTerminar(boolean terminar) { this.terminar = terminar; } 59 public void setVaguear(boolean vaguear) { this.vaguear = vaguear; } public boolean getVaguear() { return this.vaguear; } public void setEvitar(boolean evitar) { this.evitar = evitar; } public boolean getEvitar() { return this.evitar; } public boolean getFugir() { return fugir; } public void setCanalCom(boolean canalCom) { this.canalCom = canalCom; } public boolean getCanalCom() { return this.canalCom; } public void setFugir(boolean fugir) { this.fugir = fugir; } public void setFile(File file) { this.file = file; } public File getFile() { return this.file; } public Semaphore getAcessoRobot() { return this.acessoRobot; } public void setTamanhoMensagem(int tamanhoMensagem) { this.tamanhoMensagem = tamanhoMensagem; 60 } public int getTamanhoMensagem() { return this.tamanhoMensagem; } public void setJarPath(File jar) { this.jarPath = jar.getAbsolutePath(); } public String getJarPath() { return this.jarPath; } } GUI.java package App; import java.awt.Color; import java.awt.EventQueue; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.text.ParseException; import Comunicacao.CanalComunicacaoConsistente; import Comunicacao.Mensagem; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSpinner; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SpinnerNumberModel; import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.border.EmptyBorder; import javax.swing.event.ChangeListener; 61 import com.formdev.flatlaf.themes.FlatMacLightLaf; import javax.swing.event.ChangeEvent; public class GUI extends JFrame { private static final long serialVersionUID = 1L; private JPanel contentPane; private JLabel lblRobotNome; //Variables private BD bd; private JRadioButton rdbtnOnOff; private JTextArea textAreaConsola; private JTextField textFieldNome; private JTextField textFieldConsola; private JTextField textFieldRaio; private JTextField textFieldAngulo; private JButton btnRight; private JButton btnForward; private JButton btnLeft; private JButton btnStop; private JButton btnBackwards; private JLabel lblRobotNome_2; private JCheckBox chckbxRoam; private JCheckBox chckbxAvoid; private JCheckBox chckbxEscape; private JRadioButton rdbtnAbrirFecharCanal; private JTextField textFieldFicheiro; private CanalComunicacaoConsistente canal; final JFileChooser fc = new JFileChooser(); private JButton btnIG; private JTextField textFieldJar; public void myPrint(String S) { EventQueue.invokeLater(new Runnable() { public void run() { try { textAreaConsola.append('\n' + S); textFieldConsola.setText(S); }catch (Exception e) { 62 e.printStackTrace(); } } }); } private void initGUI() { EventQueue.invokeLater(new Runnable() { public void run() { try { UIManager.setLookAndFeel(new FlatMacLightLaf()); setDefaultCloseOperation(JFrame. EXIT_ON_CLOSE); setBounds(100, 100, 521, 737); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); getContentPane().setLayout(null); lblRobotNome = new JLabel("Nome:"); lblRobotNome.setHorizontalAlignment(SwingConstants. CENTER); lblRobotNome.setBounds(32, 39, 46, 14); getContentPane().add(lblRobotNome); rdbtnOnOff = new JRadioButton("On/Off"); rdbtnOnOff.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { bd.setNomeRobot(textFieldNome.getText()); bd.setOnOff(!bd.isOnOff()); if(bd.isOnOff()) { if(!initRobot()) { myPrint("Erro ao iniciar o robot"); rdbtnOnOff.setSelected(false); bd.setOnOff(false); } else { 63 enableButtons(); myPrint("Sucesso ao iniciar o robot "+ bd.getNomeRobot()); } } else { disableButtons(); fecharRobot(); } } }); rdbtnOnOff.setBounds(284, 35, 68, 23); getContentPane().add(rdbtnOnOff); JRadioButton rdbtnDebug = new JRadioButton("Debug"); rdbtnDebug.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { bd.setDebug(!bd.isDebug()); if(bd.isDebug()) { myPrint("Modo Debug inicializado"); enableButtons(); } else { myPrint("Modo Debug terminado"); disableButtons(); } } }); rdbtnDebug.setBounds(354, 35, 75, 23); contentPane.add(rdbtnDebug); textFieldNome = new JTextField(); textFieldNome.setBounds(88, 36, 190, 20); getContentPane().add(textFieldNome); textFieldNome.setColumns(10); textFieldConsola = new JTextField(); textFieldConsola.setEditable(false); textFieldConsola.setBounds(32, 639, 442, 38); getContentPane().add(textFieldConsola); 64 textFieldConsola.setColumns(10); JScrollPane scrollPane = new JScrollPane(); scrollPane.setBounds(32, 440, 442, 188); contentPane.add(scrollPane); textAreaConsola = new JTextArea(); scrollPane.setViewportView(textAreaConsola); textAreaConsola.setFont(new Font("Monospaced", Font.BOLD, 13)); textAreaConsola.setEnabled(false); textAreaConsola.setEditable(false); btnForward = new JButton("Frente"); btnForward.setEnabled(false); btnForward.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { bd.getAcessoRobot().acquire(); } catch (InterruptedException e1) { e1.printStackTrace(); } myPrint("Robot a andar para a frente " + bd.getDistancia()+" cm"); bd.getRobot().Reta(Integer. parseInt(textFieldRaio.getText()) ); bd.getRobot().Parar(false); bd.getAcessoRobot().release(); Mensagem msg = new Mensagem(canal.getIndex(), 1, bd.getDistancia(), bd.getAngulo()); myPrint(msg.toString()); canal.getAndSetProdutor(msg); } }); btnForward.setFont(new Font("Tahoma", Font.PLAIN, 11)); btnForward.setBounds(309, 114, 90, 20); contentPane.add(btnForward); 65 btnRight = new JButton("Direita"); btnRight.setEnabled(false); btnRight.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { bd.getAcessoRobot().acquire(); } catch (InterruptedException e1) { e1.printStackTrace(); } myPrint("Robot a virar à direita com raio " + bd.getDistancia()+" cm e ângulo "+ bd.getAngulo()+"º"); bd.getRobot().CurvarDireita(Integer. parseInt(textFieldRaio.g etText()), Integer.parseInt(textFieldAngulo.getText())); bd.getRobot().Parar(false); bd.getAcessoRobot().release(); Mensagem msg = new Mensagem(canal.getIndex(), 2, bd.getDistancia(), bd.getAngulo()); myPrint(msg.toString()); canal.getAndSetProdutor(msg); } }); btnRight.setBounds(409, 147, 90, 20); contentPane.add(btnRight); btnLeft = new JButton("Esquerda"); btnLeft.setEnabled(false); btnLeft.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { bd.getAcessoRobot().acquire(); } catch (InterruptedException e1) { e1.printStackTrace(); } myPrint("Robot a virar à esquerda com raio" + bd.getDistancia()+" cm e ângulo"+ bd.getAngulo()+"º"); 66 bd.getRobot().CurvarEsquerda(Integer. parseInt(textFieldRaio. getText()), Integer.parseInt(textFieldAngulo.getText())); bd.getRobot().Parar(false); bd.getAcessoRobot().release(); Mensagem msg = new Mensagem(canal.getIndex(), 3, bd.getDistancia(), bd.getAngulo()); myPrint(msg.toString()); canal.getAndSetProdutor(msg); } }); btnLeft.setBounds(212, 146, 90, 20); contentPane.add(btnLeft); btnStop = new JButton("Parar"); btnStop.setEnabled(false); btnStop.setBackground(new Color(255, 255, 255)); btnStop.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { myPrint("Robot a parar"); bd.getRobot().Parar(true); Mensagem msg = new Mensagem(canal.getIndex(), 4, bd.getDistancia(), bd.getAngulo()); myPrint(msg.toString()); canal.getAndSetProdutor(msg); } }); btnStop.setBounds(309, 146, 90, 20); contentPane.add(btnStop); btnBackwards = new JButton("Trás"); btnBackwards.setEnabled(false); btnBackwards.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { bd.getAcessoRobot().acquire(); } catch (InterruptedException e1) { e1.printStackTrace(); 67 } myPrint("Robot a andar para trás " + bd.getDistancia()+" cm"); bd.getRobot().Reta(- Integer.parseInt(textFieldRaio.getText())); bd.getRobot().Parar(false); bd.getAcessoRobot().release(); } }); btnBackwards.setBounds(309, 177, 90, 20); contentPane.add(btnBackwards); chckbxAvoid = new JCheckBox("Evitar"); chckbxAvoid.setEnabled(false); chckbxAvoid.setBounds(309, 204, 57, 23); contentPane.add(chckbxAvoid); chckbxAvoid.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { bd.setEvitar(!bd.getEvitar()); } }); chckbxEscape = new JCheckBox("Fugir"); chckbxEscape.setEnabled(false); chckbxEscape.setBounds(409, 204, 57, 23); contentPane.add(chckbxEscape); chckbxEscape.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { bd.setFugir(!bd.getFugir()); } }); chckbxRoam = new JCheckBox("Vaguear"); chckbxRoam.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { bd.setVaguear(!bd.getVaguear()); } }); chckbxRoam.setEnabled(false); chckbxRoam.setBounds(212, 204, 68, 23); 68 contentPane.add(chckbxRoam); textFieldRaio = new JTextField(); textFieldRaio.setText("0"); textFieldRaio.setBounds(106, 115, 86, 20); contentPane.add(textFieldRaio); textFieldRaio.setColumns(10); textFieldAngulo = new JTextField(); textFieldAngulo.setText("0"); textFieldAngulo.setBounds(106, 146, 86, 20); contentPane.add(textFieldAngulo); textFieldAngulo.setColumns(10); bd.setAngulo(Integer.parseInt(textFieldAngulo.getText())); JLabel lblRaio = new JLabel("Raio/Distancia"); lblRaio.setHorizontalAlignment(SwingConstants. CENTER); lblRaio.setBounds(10, 117, 85, 14); contentPane.add(lblRaio); JLabel lblAngulo = new JLabel("Angulo"); lblAngulo.setHorizontalAlignment(SwingConstants. CENTER); lblAngulo.setBounds(32, 148, 46, 19); contentPane.add(lblAngulo); JButton btnUpdate = new JButton("Confirmar"); btnUpdate.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { getBd().setDistancia(Integer.parseInt(textFieldRaio.getText( ))); getBd().setAngulo(Integer. parseInt(textFieldAngulo.getText() )); myPrint("Distância/raio inseridos a "+ bd.getDistancia()); myPrint("Ângulo inserido a "+ bd.getAngulo()); 69 } }); btnUpdate.setBounds(103, 177, 90, 20); contentPane.add(btnUpdate); JLabel lblRobotNome_1 = new JLabel("Robot"); lblRobotNome_1.setFont(new Font("Tahoma", Font.BOLD, 15)); lblRobotNome_1.setHorizontalAlignment(SwingConstants. LEFT); lblRobotNome_1.setBounds(10, 11, 46, 14); contentPane.add(lblRobotNome_1); lblRobotNome_2 = new JLabel("Controlo"); lblRobotNome_2.setHorizontalAlignment(SwingConstants. LEFT); lblRobotNome_2.setFont(new Font("Tahoma", Font.BOLD, 15)); lblRobotNome_2.setBounds(10, 92, 68, 14); contentPane.add(lblRobotNome_2); rdbtnAbrirFecharCanal = new JRadioButton("Abrir/Fechar Canal"); rdbtnAbrirFecharCanal.setEnabled(false); rdbtnAbrirFecharCanal.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { if(!bd.getCanalCom()) { myPrint(""+bd.getFile().getAbsolutePath()); bd.setCanalCom(canal.abrirCanal(bd.getFile().getAbsolutePath (), bd.getTamanhoMensagem())); } else { //canal.limparCanal(); bd.setCanalCom(false); canal.fecharCanal(); } } }); rdbtnAbrirFecharCanal.setBounds(201, 400, 134, 33); contentPane.add(rdbtnAbrirFecharCanal); 70 JSpinner nMsgs = new JSpinner(); nMsgs.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent arg0) { try { nMsgs.commitEdit(); } catch (ParseException e) { e.printStackTrace(); } bd.setTamanhoMensagem((int) nMsgs.getValue()); System.out.println(""+bd.getTamanhoMensagem()); } }); nMsgs.setModel(new SpinnerNumberModel(8, 8, 16, 1)); nMsgs.setBounds(201, 363, 62, 27); contentPane.add(nMsgs); textFieldFicheiro = new JTextField(); textFieldFicheiro.setEditable(false); textFieldFicheiro.setBounds(136, 289, 248, 20); contentPane.add(textFieldFicheiro); textFieldFicheiro.setColumns(10); JLabel lblFicheiro = new JLabel("Ficheiro Comunicação:"); lblFicheiro.setBounds(10, 292, 125, 17); contentPane.add(lblFicheiro); JLabel lblMsgs = new JLabel("Nº msgs:"); lblMsgs.setBounds(106, 369, 86, 14); contentPane.add(lblMsgs); JButton btnFileChooserCom = new JButton("Browse"); btnFileChooserCom.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { if (fc.showOpenDialog(GUI.this) == JFileChooser.APPROVE_OPTION) { bd.setFile(fc.getSelectedFile()); 71 textFieldFicheiro.setText(bd.getFile().getAbsolutePath()); if(bd.getFile() != null) rdbtnAbrirFecharCanal.setEnabled(true); if(bd.getJarPath() != null && bd.getFile() != null) btnIG.setEnabled(true); } } }); btnFileChooserCom.setBounds(394, 288, 89, 23); contentPane.add(btnFileChooserCom); btnIG = new JButton("Lançar IG"); btnIG.setEnabled(false); btnIG.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { nMsgs.setEnabled(false); btnFileChooserCom.setEnabled(false); if(bd.getCanalCom()) { canal.limparCanal(bd.getTamanhoMensagem()); } String nameProcess = bd.getJarPath();; String filePath = bd.getFile().getAbsolutePath(); String dimensaoCanal = String.valueOf(bd.getTamanhoMensagem()); ProcessBuilder pb = new ProcessBuilder("java", "-jar", nameProcess, filePath, dimensaoCanal); try { pb.start(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } }

Use Quizgecko on...
Browser
Browser