-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathradio.cpp
executable file
·142 lines (114 loc) · 6.45 KB
/
radio.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <iostream>
#include <chrono>
#include <stdio.h>
#include <stdlib.h>
#include <cstring> // Para uso da rotina memset
#include <cerrno> // Para o uso da rotina de indicacao de erro strerror() e da constante errno
#include <QByteArray>
#include "radio.hpp"
/* o trecho: vector_robos(v) serve para acoplar o vector com os robos a classe de transmissao */
Radio::Radio(std::vector<Robo>& v) : vector_robos(v) {
/* Setando o baundrate de input e output do radio iguais */
this->serial.setBaudRate(Radio::VELOCIDADE_SERIAL, QSerialPort::AllDirections);
/* setando qual o caminho que se encontra / que foi montado o rádio */
this->serial.setPortName(this->caminho_dispositivo);
/* tentando abrir o dispositivo para apenas escrita */
if (!serial.open(QIODevice::WriteOnly)) {
std::cerr << "Erro " << errno << " @Radio->open: " << std::strerror(errno) << std::endl;
exit(1); /* Nao permite que o programa rode se nao foi possivel configurar a porta serial */
}
/* Dois bytes para cada robo (um para cada roda) mais um, inicial, que indica o inicio de uma nova sequência (header). */
this->num_bytes_enviados = 2 * this->vector_robos.size() + 1;
/* allocando o array que será enviado aos robos. sempre terá o primeiro byte fixo, logo, setamos ele aqui. */
this->dados_envio = (char*) malloc(this->num_bytes_enviados);
this->dados_envio[0] = this->caractere_inicial;
}
Radio::~Radio() {
/* indicando que a thread deve parar sua execução */
this->comunicacao_terminada = true;
/* checando se é possivel unir a thread de comunicacao à principal. */
if (this->thread_envio->joinable())
Radio::terminaComunicacao();
/* desalocando o array de dados enviados pela serial */
free(this->dados_envio);
/* fechando a serial */
this->serial.close();
}
void Radio::enviaDados() {
/* preenchendo o vetor de dados das rodas com os valores de velocidade dos robos */
for(int i = 0; i < this->vector_robos.size(); i++) {
/* deslocamos para esquerda os ultimos 4 bits para que eles sejam os primeiros do byte. Para os robos que receberao, apenas os primeiros 4 bytes sao importantes para os robos. */
this->dados_envio[2 * i + 1] = this->vector_robos[i].getVelocidadeAtualRobo().rodaEsq;
this->dados_envio[2 * i + 2] = this->vector_robos[i].getVelocidadeAtualRobo().rodaDir;
}
qint64 bytesWritten = this->serial.write(QByteArray(this->dados_envio, this->num_bytes_enviados));
/* espera o envio de, pelo menos, um byte para desbloquear a função. Caso não o faça (timeout/erro) retorná falso. */
if(this->serial.waitForBytesWritten() == false) {
std::cerr << "Error " << errno << " @Radio::enviaDados->write " << std::strerror(errno) << std::endl;
return;
}
}
void Radio::recebeDados() {
bool okay_para_escrever; /* indica se já podemos passar para a fase de escrita na serial (true) ou não (false) */
/* esperamos até receber o caracter this->caractere_inicial do arduino para prosseguir. */
do {
okay_para_escrever = true;
/* aguarda e indica se a serial pode (true) ou não ser lida (false)*/
if (this->serial.waitForReadyRead() == false) {
std::cerr << "Error " << errno << " @Radio::recebeDados->read " << "Possivel timeout da serial. "
<< std::strerror(errno) << std::endl;
okay_para_escrever = false;
}
else {
/* faz a leitura da serial de 1 char / byte (que chega na forma de um QByteArray) */
QByteArray char_validacao = this->serial.read(1);
/* verificando se recebemos alguma informação e se recebemos a informação correta (um this->caractere_inicial char)*/
if (char_validacao.isEmpty()) {
std::cerr << "Error " << "Recebemos dados vazios durante a leitura da serial."
<< " @Radio::recebeDados->read " << std::endl;
okay_para_escrever = false;
} else if ((unsigned char) char_validacao[0] != this->caractere_recebido_okay) {
std::cerr << "Error " << "Recebemos dados nao validos da serial." << "Esperado: "
<< (int) this->caractere_recebido_okay << " Recebido: " << (int) char_validacao[0]
<< " @Radio::recebeDados->read " << std::endl;
okay_para_escrever = false;
}
}
} while(!okay_para_escrever);
}
void Radio::comecaComunicacao() {
/* se é a primeira chamada desta função, prepara os parametros para a execução da thread. */
if(!this->comunicacao_pronta) {
this->comunicacao_pausada = false; /* indicando que a thread agora esta ativa. */
this->comunicacao_pronta = true; /* indicando que já ajustamos os parametros que precisavamos. (não vamos mais executar esse trecho de novo) */
this->thread_envio = new std::thread(&Radio::comecaComunicacao, this); /* instanciando a thread. */
return; /* saimos pois já fizemos a configuração, a thread agora está rodando até que solicitemos sua parada. */
}
/* enquanto a comunicacao não é terminanda, faz o envio dos dados para a serial*/
while(!this->comunicacao_terminada) {
/* se a comunicação não está em pausa, pode fazer o envio dos dados, senão apenas espera. */
if(!this->comunicacao_pausada) {
// devemos receber os dados do arduino primeiro antes de enviar dados para ele (no, momento, não estamos fazendo uso da comunicação bidirecional, por isso mantenha a linha abaixo comentada)
//Radio::recebeDados();
// enviamos os dados ao ardunino (estamos certmos de que ele poderá recebe-los)
Radio::enviaDados();
}
else {
/* evitando que esta thread ocupe 100% de uma CPU, colocamos um delay para checagem se a comunicação foi reinicializada. */
std::this_thread::sleep_for(std::chrono::milliseconds(this->THREAD_SLEEP_TIME));
}
}
}
void Radio::terminaComunicacao() {
/* indicando que a thread deve terminar sua execução */
this->comunicacao_terminada = true;
this->thread_envio->join();
}
void Radio::pausaComunicacao() {
/* indicando que a thread deve parar de enviar os dados durante sua execução */
this->comunicacao_pausada = true;
}
void Radio::recomecaComunicacao() {
/* indicando que a thread deve voltar a enviar os dados durante sua execução */
this->comunicacao_pausada = false;
}