A organização das partes que compõe o firmware do CPDigi está sendo feita por meio de classes dentro da linguagem de programação C++. Cada classe terá seus respectivos métodos e caberá ao programa cpdigifirmware.ino fazer a união destas classes em um programa funcional. Cada uma das classes é definida em um conjunto arquivo header (.hpp) arquivo .cpp de maneira a deixar o projeto modular, visando que qualquer mudança necessária ao usuário possa ser feita minimizando a necessidade de grandes mudanças dentro do código do firmware em si.
As partes que compõe o CPDigiFirmware são:
- CPDigiMain: Funcionamento do loop principal do CPDigi e metodos que integram os demais módulos do firmware
- CPDigiCritical: Métodos críticos que exigem precisão temporal. São as ações executadas pela interrupção que devem garantir a sincronização do evento com a etiqueta temporal.
- CPDigiSensors: Métodos para leitura dos dados ambientais: GPS, temperatura
- CPDigiStorage: Métodos do armazenamento persistente do CPDigi: Armazenamento dos dados coletados, arquivos temporários, leitura e gravação das configurações do dispositivo.
- CPDigiDataHubIface: Interface para comunicação com o DataHub: envio dos dados, atualização de status do dispositivo, processamento das respostas do servidor.
- CPDigiQueueManager: Gerenciamento da fila de envio de dados para o servidor CPDataHub: adiciona e remove eventos da fila para envio. Ativa o CPDigiDataHubIface quando necessário.
- CPDigiCPAmpIface: Métodos de interação com o CPAmp: leitura do sinal, reset do circuito Sample and Hold. Leitura do trigger.
- CPDigiStatusDisplay: Interface para o status display do CPDigi: Ativa e desativas os indicadores de status.
Destes, cada um será também uma classe, com exceção do CPDigiCritial que, devido à sua necessidade de rapidez e complexidade não tem necessidade atual de implementação por meio de uma classe dedicada.
- void loop()
- CPDigiMain
- CPDigiCritical:
- CPDigiSensors
- CPDigiStorage
- CPDigiDataHubIface
- CPDigiQueueManager
- CPDigiCPAmpIface
- CPDigiStatusDisplay
void loop()
O loop principal do CPDigi é possivelmente a parte mais importante do programa, pois é o loop que será executado infinitamente durante o funcionamento do CPDigi. O fluxograma abaixo foi desenhado para exemplificar a sua lógica mais básica de funcionamento, visando seu uso como guia para a elaboração das classes e métodos que seriam necessários:
Fluxograma criado utilizando o dia diagram editor. TODO: Adicionar aqui o arquivo fonte do diagrama. Também adicionar um fluxograma para a interrupção.
A primeira ilha checa se foi ou não levantado um flag de evento. Este flag é definido dentro do interrupt ativado pelo CPAmp. Um pino de trigger faz o alerta ao NodeMCU que ele deve executar um interrupt quando o CPAmp detecta sinal na PMT. Neste interrupt, mede-se o valor do sinal da PMT através do conversor analógico-digital, obtêm-se o tempo exato da ocorrência do evento e então levanta-se o flag de evento, sinalizando que temos a ocorrência da detecção de um múon. A medição do sinal e do tempo é feita dentro do interrupt pois estas duas informações são de importância crítica. Como a chegada do múon e o efeito Cherenkov são muito rápidos, qualquer delay no momento de medição do sinal ou do tempo exato da ocorrência do evento podem acarretar em percas de informações preciosas.
Quando este flag for verdadeiro, deveremos dar início ao processamento deste evento. Para isso, iremos construir uma string na qual deverá constar os seguintes dados:
- Valor do sinal medido na PMT
- Tempo de ocorrência
- Temperatura
- Umidade
- Localização espacial
Estes três últimos dados serão variáveis globais que atualizaremos periodicamente. Como há uma variação muito menor destes dados no tempo, optamos por medi-los eles com menos frequência, evitando o desperdício de processamento.
A criação da string será feito então com o método build_data_string() da classe CPDigiMain. Ela irá nos retornar esta string com os dados de um evento em formato adequado para armazenamento local e para envio para o CPDataHub. Então, através do método queue_data() (CPDigiQueueManager) iremos enviar essa string para uma lista de espera. Ela é um ponto intermediário entre a detecção do evento e seu envio para o server. Essa lista será processada ao final do loop, como veremos. Também usaremos então o método store_data() (CPDigiStorage) para realizar o armazenamento da string dentro do cartão SD.
Depois disto, há a checagem dos timers dos sensores. Neste ponto, caso o flag de evento fosse falso, teríamos pulado diretamente para esta parte. Aqui, checamos se o tempo que se passou entre a última checagem dos sensores já é suficiente para atualizarmos seus valores. Caso sim, ocorre a leitura de seus valores e seu armazenamento em variáveis globais. Caso não, passamos à próxima ilha.
Finalmente, temos novamente uma checagem de timers, mas desta vez para o processamento da fila. Aqui, caso o tempo desde a última checagem seja suficiente, iremos executar uma rotina de tentativa de envio dos dados da fila ao servidor. Caso haja algum erro, eles permanecem armazenados e será tentada novamente o envio no próximo ciclo do loop. Caso o envio seja feito, eles são removidos da lista.
CPDigiMain
Classe dedicada às funções essenciais para a lógica de funcionamento do CPDigi, sua configuração inicial, logging, testes e quaisquer métodos que não pertençam a outras classes.
Métodos públicos
CPDigiMain(Storage*,QueueManager*)
- Descrição:
- Método construtor da classe. Utiliza dois ponteiros como argumento: o primeiro é para um objeto do tipo Storage, que é a classe responsável pelo armazenamento dos dados no cartão SD, o segundo é para um objeto do tipo QueueManager, que é a classe responsável pela administração da fila de dados que serão enviados ao servidor.
- Esses dois ponteiros serão membros privados da classe e usaremos eles para apontarmos para qual objeto do tipo Storage ou QueueManager estamos referenciando nos métodos em que eles são necessários (assim não precisamos passar esses ponteiros como argumentos)
- Método construtor da classe. Utiliza dois ponteiros como argumento: o primeiro é para um objeto do tipo Storage, que é a classe responsável pelo armazenamento dos dados no cartão SD, o segundo é para um objeto do tipo QueueManager, que é a classe responsável pela administração da fila de dados que serão enviados ao servidor.
- Pinos:
- CS_Pin (pino de conexão com o cartão SD)
- Variáveis globais: Nenhuma
- Funções/Classes externas:
- Storage (CPDigiStorage)
- QueueManager (CPDigiQueueManager)
void process_event()
- Descrição:
- Processa o evento armazenado na memória, garantindo que este seja armazenado de forma persistente e alocado na fila para envio ao CPDataHub e incrementa o valor de ID.
- Pinos: nenhum
- Variáveis globais: Nenhuma
- Funções/Classes externas:
- build_data_string(), (CPDigiMain)
- queue_data(), (CPDigiQueue)
- store_data(), (CPDigiStorage)
- incrementEventID(), (CPDigiMain)
int getLastEventID()
- Descrição:
- Retorna o identificador único do evento atual (eventID). (As funções GetEventID e IncrementEventID estão considerando que cada evento observado por um dispositivo será identificado pelo seu ID, um inteiro que identifica quantos eventos foram observados.)
- Pinos: nenhum
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma (?)
int incrementEventID()
- Descrição:
- Incrementa o identificador único do evento. O retorno pode ser booleano para indicar o status do incremento, ou pode ser um inteiro correspondente ao valor do eventID após o incremento. Neste último caso o erro pode ser identificado por um eventID negativo, tipicamente -1.
- Pinos: Nenhum
- Variáveis globais: Nenhuma
- Funções/Classes externas:
- getLastEventID(), (CPDigiMain)
bool logMessage(data_source source, *char message)
- Descrição:
- Adiciona uma mensagem ao arquivo de log.
- Pinos:
- CS_Pin (comunicação serial do cartão SD)
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
- TODO: Implementar a estrutura de data_source
char* build_data_string()
- Descrição:
- Monta uma string que contém a totalidade das informações que caracterizam o evento. E retorna o endereço da localização que guarda o char.
- Pinos: nenhum
- Variáveis globais:
-
int: pmt_signal
- será uma variável global pois é gerada dentro do interrupt
-
int: event_time
- será uma variável global pois é gerada dentro do interrupt
-
float: temperature
- será atualizada periodicamente, evitando assim que tenha que ser obtida no interrupt
-
float: humidity
- será atualizada periodicamente, evitando assim que tenha que ser obtida no interrupt
-
?: GPSPosition
- será atualizada periodicamente, evitando assim que tenha que ser obtida no interrupt
-
int: pmt_signal
- Funções/Classes externas: nenhuma
bool loadConfig()
- Descrição:
- Carrega as configurações do detector. Todo: definir formato e localização das configurações
- Pinos: Nenhum
- Variáveis globais: Nenhuma
- Funções/Classes externas:
- Funções relacionadas à leitura de cartão SD, caso esse seja usado para armazenar o arquivo de inicialização
- Funções de leitura de EPROM, caso esse seja usado para armazenar o arquivo de inicialização (mais confiável, pois não haveria problema alterar o cartão SD)
void setup()
- Descrição:
- Configura o dispositivo: atribuição dos pinos, carrega configurações, executa teste
- Pinos: Todos que necessitam de definição e inicialização
- Variáveis globais:
- Possivelmente usará as variáveis globais de setup que serão geradas no loadConfig()
- Funções/Classes externas:
- Todas as funções de inicialização dos headers (se houver)
TODO: Assim que estiver melhor definido todos os métodos, explicitar quais são as funções externas em si
int selfTest()
- Descrição:
- Realiza teste de comunicação com os periféricos do CPDigi, acesso à leitura e escrita no cartão SD, leitura de todos os sensores.
- Pinos:
- DHT_Pin (Sensor de temperatura e umidade)
- GPS_Pin
- CS_Pin (Comunicação do Cartão SD)
- Variáveis globais: Nenhuma
- Funções/Classes externas: ?
CPDigiCritical:
Header dedicado às funções cujo funcionamento exige grande exatidão e rapidez
void interrupt_call()
- Descrição:
- Rotina de interrupção que será chamada assim que houver trigger do CPAmp. Fará a leitura do valor analógico do S&H e do tempo no GPS e levantará um flag de evento.
- Pinos: Nenhum
- Variáveis globais: Nenhuma
- Funções/Classes externas:
- readCPAmp(), (CPDigiCPAmpIface)
- readGPS(), (CPDigiSensors)
void interrupt_Setup()
- Descrição: * Faz a definição do pino, da função de interrupção e das configurações internas necessárias para o ESP8266
- Pinos:
- Trigger_Pin: Pino no qual chega o sinal de trigger
- Variáveis globais: nenhuma
- Funções/Classes externas: Nenhuma
int syncClockGPS()
- Descrição:
- Retorna o tempo lido pelo GPS
- Pinos:
- GPS_Pin
- Variáveis globais:
- event_time
- Funções/Classes externas: Nenhuma
CPDigiSensors
Classe de configuração e leitura dos sensores ambientais
Métodos públicos
CPDigiSensors(int dhtpin, int dhttype)
- Descrição: * Construtor da classe. Irá criar uma classe do tipo DHT usando dhtpin e dhttype usando a função "new" e colocando esse novo ponteiro gerado dentro do membro privado "mDHT" * Então usara de "mDHT->begin()" para inicializar o sensor DHT * Como usamos a função "new" para criar um ponteiro, poderemos utilizar o mesmo construtor para criar um novo DHT sem interferir com o criado anteriormente
- Pinos: * DHTPin
- Variáveis globais: Nenhuma
- Funções/Classes externas: * dht.begin() * Essa função faz parte da biblioteca do sensor DHT criado pela Adafruit, o qual pode ser baixado diretamente pela IDE Arduino. Para que ela funcione, devemos ter previamente incluído esta biblioteca e criado o objeto 'dht'
void updateTemp(&float temp)
- Descrição: Atualiza com o valor de temperatura lido no sensor DHT a variável colocada como argumento
- Pinos:
- DHT_Pin
- Variávei globais: temp
- Funções/Classes externas:
- mDHT (ponteiro do objeto do tipo DHT declarado como membro privado)
- mDHT->readTemperature()
- mDHT (ponteiro do objeto do tipo DHT declarado como membro privado)
void updateHumidity()
- Descrição:
- Realiza o update periódico do valor de umidade, armazenando-o em uma variável global
- Pinos:
- DHT_Pin
- Variávei globais: umid
- Funções/Classes externas:
-
mDHT (ponteiro do objeto do tipo DHT declarado como membro privado)
- mDHT->updateHumidity()
-
void updateLocation(float &location)
- Descrição:
- Realiza o update periódico da localização, armazenando-a em uma variável global
- Pinos:
- GPS_Pin
- Variávei globais: Nenhuma
- Funções/Classes externas: Nenhuma
void updateClockNTP(float &systime)
- Descrição:
- Realiza o update do tempo do sistema através do protocolo NTP e o armazena em uma variável global
- Pinos: GPS_Pin
- Variávei globais: systime
- Funções/Classes externas:
- Possível classe privada dedicada ao GPS
CPDigiStorage
Controle do armazenamento no cartão SD.
Comentário: devem ser necessários métodos diferentes para armazenar os dados de forma persistente e para métodos com dados efêmeros para processamento da fila. O desenvolvimento desta etapa deve ser feita conjuntamente de acordo com a biblioteca de gerenciamento da fila de eventos.
Métodos públicos
Storage(uint8_t Pino)
- Descrição:
- Construtor da classe, define o pino CS de comunicação com o cartão SD (membro privado);
- Pinos:
- CS_Pin (Comunicação com o cartão SD)
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
bool store_data(char* data_message)
- Descrição:
- Armazena o string de dados no cartão SD.
- Argumentos:
- data_message é o resultado da função build_data_string()
- Retorno: indica o sucesso ou falha do armazenamento. Em caso de falha um alarme deverá ser ativado.
- Pinos: CS_Pin (comunicação serial do cartão SD)
- Variáveis globais: Nenhuma
- Funções/Classes externas: Funções de biblioteca de uso do cartão SD
bool createFile(char* filename, char* data_message)
- Descrição:
- Cria o arquivo indicado por 'filename' contendo a linha de texto fornecido, se existente.
- Pinos:
- CS_Pin
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
bool deleteFile(char* filename)
- Descrição:
- Apaga um arquivo
- Pinos:
- CS_Pin
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
bool appendToFile(char* filename, char* data_message)
- Descrição:
- Adiciona uma linha de texto no fim de um arquivo.
- Pinos:
- CS_Pin
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
bool pathHasFiles(char* path)
- Descrição:
- Identifica se um caminho do cartão SD contém arquivos.
- Pinos:
- CS_Pin
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
bool fileExists(char* path)
- Descrição: *Identifica se um arquivo ou caminho do cartão SD existe.
- Pinos:
- CS_Pin
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
char* readLine(char* path, int line_number)
- Descrição:
- Retorna uma linha de texto do arquivo.
- Pinos:
- CS_Pin
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
TODO: funções para listar arquivos e/ou retornar nome do primeiro arquivo de um diretório
- Descrição: * Para ser utilizado no processamento da fila.
CPDigiDataHubIface
Métodos públicos
DataHub()
- Descrição:
- Construtor da classe, irá realizar o setup do DataHub
- Pinos: Nenhum
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
bool isDataHubReachable()
- Descrição: * Verifica se existe conexão com o servidor DataHub. Também é válido testar a validade das credenciais do dispositivo (usuário e senha / ou assinatura do dispositivo). Pode ser incluído nesta função ou criar uma função dedicada para tal.
- Pinos: Nenhum
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
bool sendEvent(eventID or filename)
- Descrição: * Envia um evento para o DataHub. Em caso de sucesso, espera-se que a função que remove evento da fila seja chamada.
- Pinos: Nenhum
- Variávei globais: DataHubStatus (obtido a partir de isdatahubreachable())
- Funções/Classes externas: Nenhuma
TODO: estudar e implementar as mudanças necessárias para a implementação do HASH como método de identificação do evento
bool sendMultipleEvents()
- Descrição: * envia múltiplos eventos para o DataHub. Essa função pode ser necessária caso a conexão com o DataHub seja perdida por longos períodos.
- Pinos: Nenhum
- Variáveis globais: DataHubStatus (obtido a partir de isdatahubreachable())
- Funções/Classes externas:
- sendEvent(eventID or filename), <CPDigiDataHubIface.h>
bool sendStatus()
- Descrição: * Envia status do dispositivo ao DataHub
- Pinos: Nenhum
- Variáveis globais: DataHubStatus (obtido a partir de isdatahubreachable())
- Funções/Classes externas: Nenhuma
CPDigiQueueManager
Gerenciador da fila de envio de dados a serem enviados para o CPDataHub. Para sua implementação será necessário definir um modelo para a fila e forma de implementação:
- Modelos usuais de fila: FIFO e FILO
- Definir implementação utilizando o sistema de arquivos do cartão SD para armazenamento da fila. Possibilidades:
- 1 evento por arquivo em diretório spool
- 1 linha por evento em arquivo spool
Métodos públicos
QueueManager()
- Descrição:
- Construtor da classe, irá criar a fila e fazer as configurações necessárias para seu funcionamento.
- Pinos: Nenhum
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
void queue_event(char* data_message)
- Descrição:
- Envia o dado atual ao final da lista de dados
- Argumentos:
- data_message é o resultado da função build_data_string()
- Pinos: Nenhum
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
void process_queue()
- Descrição:
- Verifica se existem eventos na fila para envio de dados ao CPDataHub. Caso positivo aciona os métodos para envio e remoção dos eventos da fila.
- Pinos: Nenhum
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
void popEvent(eventId or filename)
- Descrição: Remove o evento da fila
- Pinos:
- CS_Pin
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
CPDigiCPAmpIface
Classe dedicada à comunicação entre o CPDigi e o CPAmp.
Métodos públicos
CPAmp(int, DataPin, int SnHResetPin, int time_to_reset)
- Descrição:
- Construtor da classe. Tem como argumentos: o pino de leitura do CPAmp, o pino de reset do CPAmp e o valor de tempo necessário para o Reset do Sample & Hold do CPAMP.
- Dentro do arquivo .ino, esse valor está definido como SnH_Reset
- Construtor da classe. Tem como argumentos: o pino de leitura do CPAmp, o pino de reset do CPAmp e o valor de tempo necessário para o Reset do Sample & Hold do CPAMP.
- Pinos:
- DataPin
- SnHResetPin
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
int readCPAmp()
- Descrição:
- Lê e retorna o valor analógico mantido pelo circuito Sample and Hold a uma variável global
- Pinos:
- DataPin
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
void reset_SnH()
- Descrição:
- Reseta o Sample and Hold por meio de um pulso. O tempo de ativação do pulso é ditado pela variável time_to_reset do construtor e armazenado como um membro privado.
- Pinos: SnHResetPin (digital output)
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
CPDigiStatusDisplay
Classe dedicada à comunicação de indicativos para o usuário, como: sem sinal do CPAmp, sem comunicação com o DataHub, sem cartão SD...
Métodos públicos
StatusDisplay();
- Descrição:
- Construtor da classe
- Pinos:
- Possíveis pinos de saída para algum sinal (luminoso, sonoro, etc) de comunicação ao usuário
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
void enableAlarm()
- Descrição:
- Habilita os avisos
- Pinos: Todos os pinos dos LEDs relacionados aos alarmes (ou qualquer outro meio de comunicação)
- Variáveis globais: Nenhuma
- Funções/Classes externas: Nenhuma
void disableAlarm()
Podem existir indicativos para casos específicos: sem sinal do CPAMP já X segundos, sem comunicação com o DATAHUB, problema com cartão SD: sem espaço, sem cartão...