Sendo os 3 pacotes iniciais, apenas apoio, e o libfreenect-dev realmente a lib necessária.
Hello World da Biblioteca
Neste primeiro projeto, pouca coisa faremos, apenas iremos compilar identificando o device.
#include <stdio.h>
#include <stdlib.h>
#include <libfreenect.h>
freenect_context *f_ctx;
freenect_device *f_dev;
int user_device_number = 0; // Normalmente 0 se você tiver apenas um Kinect
void depth_cb(freenect_device *dev, void *v_depth, uint32_t timestamp) {
// Callback para dados de profundidade - não usado neste exemplo
}
void rgb_cb(freenect_device *dev, void *rgb, uint32_t timestamp) {
// Salva uma imagem RGB capturada pelo Kinect
FILE *image = fopen("output_image.ppm", "wb");
if (image == NULL) {
printf("Erro ao abrir o arquivo para escrita\n");
return;
}
fprintf(image, "P6\n# Kinect RGB test\n640 480\n255\n");
fwrite(rgb, 640*480*3, 1, image);
fclose(image);
printf("Imagem salva como output_image.ppm\n");
// Depois de salvar a imagem, podemos sair do loop principal
freenect_stop_video(dev);
freenect_close_device(dev);
freenect_shutdown(f_ctx);
exit(0);
}
int main() {
if (freenect_init(&f_ctx, NULL) < 0) {
printf("freenect_init() falhou\n");
return 1;
}
if (freenect_open_device(f_ctx, &f_dev, user_device_number) < 0) {
printf("Não foi possível abrir o dispositivo\n");
freenect_shutdown(f_ctx);
return 1;
}
freenect_set_depth_callback(f_dev, depth_cb);
freenect_set_video_callback(f_dev, rgb_cb);
freenect_set_video_mode(f_dev, freenect_find_video_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_RGB));
freenect_start_video(f_dev);
while (freenect_process_events(f_ctx) >= 0) {
// Processa eventos do Kinect até que a captura de imagem seja concluída
}
return 0;
}
Neste exemplo o programa pega o kinect e tira uma foto, salvando na maquina local.
Vamos entender o código.
A freenect_init inicia a api.
A próxima função freenect_open_device, abre o device conforme o número que estiver descrito. Isso permite abrir mais de um kinect na mesma maquina.
As funções freenect_set_depth_callback e freenect_set_video_callback criam funções de callback, para controle, se voce não sabe o que é leia este artigo:
A função freenect_set_video_mode indica os parâmetros de resolução.
Por ultimo a função freenect_start_video, dá inicio ao kinect que aciona o callback quando pronto.
Perceba aqui que o pulo do gato neste makefile, é a inclusão da pasta /usr/lib/x86_64-linux-gnu que é onde a lib se encontra. Bem como a /usr/include/libfreenect que é onde o header se encontra.
Compilando o projeto
Para compilar esse projeto, é necessário apenas rodar o script na pasta src do ubuntu:
make all
Compilando o projeto
Rodando o programa
Agora iremos rodar o programa, isso é a parte mais simples.
Ao rodar, ele captura uma foto, e salva, conforme apresentado.
O srvOuve, é um projeto de minha autoria, que permite criar aplicação de Voz para Texto. Neste projeto, iremos utilizar várias abordagens diferentes, para criar uma aplicação para atender essa finalidade.
Neste primeiro projeto finalizado, criamos um serviço de voz para texto que precisa ser online.
O projeto srvOuve, permite utilizar diversos serviços diferentes, ouvindo tanto online como offline, unificando assim a forma de obter esses serviços em um único canal.
Permitindo criar integrações mais ageis.
No exemplo do vídeo usamos o MNote como ferramenta de integração. Onde ele recebe o texto “escutado” pelo srvOuve e repassa ao CHATGPT, permitindo assim que esse responda, e depois convertendo em texto de voz, através do srvFalar, outro projeto de minha autoria.
SCons é um projeto open source, criado para auxiliar na compilação e montagem de projetos.
Uma definição simples sobre SCons é que é um utilitário de montagem de software (Compilação), criado em python, pode ser utilizado para montar aplicações C/C++ de forma rápida e dinâmica.
Pré requisitos
Python 3.7.1 ou superior
Instalação do SCons
Para instalar o SCons basta rodar o script abaixo:
python -m pip install scons
A instalação tem resultado final como apresentado.
Documentação
A documentação oficial do SCons pode ser vista em:
O objetivo deste artigo é apresentar uma visão geral sobre este protocolo.
Histórico
Criado em 1987 a ISO8583 descreve o intercâmbio entre requisições bancárias.
Funcionamento
Sem entrar muito no detalhe do funcionamento.
Basicamente a imagem abaixo, ilustra o funcionamento do protocolo em linhas gerais.
De forma geral, o PDV ou POS solicita a operadora uma dada solicitação.
Por exemplo:
inicio de pagamento com cartão de crédito.
No corpo da solicitação, irão alguns dados identificadores da solicitação.
A operadora, pode conforme o tipo da solicitação, perguntar algumas coisas, como senha, tipo de cartão entre outras coisas.
Ou mesmo solicitar a visualização de outras.
A esta solicitação (chamamos de ação), que deve ser respondida pelo PDV ou POS.
A operadora pode realizar quantas perguntas forem necessárias para atendimento de suas necessidades.
Ao fim a operadora envia a resposta final, dando por encerrado a operação.
Em linhas bem gerais é assim que funciona o protocolo ISO 8583.
Estaremos entrando em detalhes, mais adiante.
Porem para entendimento geral, é um protocolo mestre/escravo, onde após a solicitação inicial, a operadora passa a solicitar informações, que devem ser respondidas.
Identificadores de tipo de mensagens
O identificador de tipo de mensagem é um campo numérico de 4 dígitos que especifica o tipo da mensagem que deve ser processado.
V: número de versão da ISO 8583 (0 indica que é ISO 8583:1987; 1 indica ISO 8583:1992).
n: Classe da Mensagem conforme a tabela abaixo: | 0 Reserved for ISO use | 1 Authorization | 2 Financial | | 3 File action | 4 Reversal/Chargeback | 5 Reconciliation | | 6 Administration | 7 Fee collection | 8 Network management | | 9 Reserved for ISO use | | |
X: Função da Mensagem conforme tabela: | 0 Request | 1 Request response | 2 Advice | | 3 Advice response | 4 Notification | 5 – 9 Reserved for ISO use |
Y: Origem da Transação | 0 Acquirer | 1 Acquirer repeat | 2 Card issuer | | 3 Card issuer repeat | 4 Other | 5 Other repeat | | 6 –9 Reserved for ISO use | | |
Simulando PDV e Simulando Autorizadora
Eu vasculhando a internet achei o site da neapay, conforme referência.
Baixei um download simulator_ISSUER_ISO8583_host_auth_PRO.
A aplicação trabalha com JAVA, e é uma boa pedida quem deseja testar e aprender mais sobre o protocolo.
Temos também a variável executada, que será utilizada na marcação dos itens executados.
Sessão Crítica
O controle da sessão crítica é feita nas funções IniciaSessaoCritica e TerminaSessaoCritica, conforme fonte abaixo:
int IniciaSessaoCritica()
{
int rc;
int cont = 0;
while ( (rc = pthread_mutex_lock(&mutex))!=0)
{
usleep(100); /*Aguarda um pouco*/
cont++;
printf("Sessao critica não conseguida\n");
if (cont>3) break;
}
return rc;
}
int TerminaSessaoCritica()
{
int rc;
int cont = 0;
while ( (rc = pthread_mutex_unlock(&mutex))!=0)
{
usleep(100); /*Aguarda um pouco*/
cont++;
printf("Sessao critica não liberada\n");
if (cont>3) break;
}
return rc;
}
Ambas as funções controlam a sessão criada mutex, declarada, conforme fonte abaixo:
Para cada sessão critica, deve-se criar uma variável de controle. Como usaremos apenas a fila, como variável de troca de dados, utilizaremos uma única sessão critica.
Criando a thread da recepção
Agora iremos dar inicio a criação da thread da recepção, na qual incluiremos o inicio da thread.
Neste segmento do código, podemos acompanhar que criamos a thread com pthread_create, passando o ponteiro da função que será criada a thread threadRecepcao. Desta forma a função threadRecepcao, não mais seguirá na thread pai. O ultimo parâmetro é utilizado para passagens de argumentos, no nosso caso, não será usado.
Por fim a função da thread
/*thread function definition*/
void* threadRecepcao(void* args)
{
for(int cont = 0;cont<=MAXITEMS;cont++)
{
printf("Criando pacote nro %d\n",cont);
if(IniciaSessaoCritica()==0)
{
int Valor = (rand()% 100);
fila[cont] = Valor; /*Grava Valor na fila*/
printf("Registrou na fila[%d] = %d\n",cont,Valor);
TerminaSessaoCritica();
usleep(1000);
} else {
printf("Falha na Recepcao nro:\n",cont);
}
}
printf("Recepcao terminou atendimento\n");
}
Podemos observar que a threadRecepção requisita a sessão crítica para movimentar a fila, apenas depois alocando valor para ela. Também podemos perceber que após seu uso, o mesmo é descartado.
Criando o Controlador
O controlador, é executado, em seguida, ordenando as informações.
void ordenacao()
{
int i, x;
bool flgordenado = false;
while((!flgordenado)&&(!flgTerminou))
{
//flgordenado = true;
for (i=0; i<=MAXITEMS-1; i++)
{
if ((fila[i]!=0)&&(fila[i+1]!=0))
{
if(fila[i]>fila[i+1])
{
x = fila[i];
fila[i] = fila[i+1];
fila[i+1] = x;
flgordenado = false;
//printf("Ordenando os pacote nro %d\n",i);
}
} else {
//printf("Posicao vazia %d\n",i);
flgordenado = false;
}
}
}
}
/*thread function definition*/
void* threadControlador(void* args)
{
int oldValue, newValue;
int flgOrdenado = false;
printf("Iniciou o controlador\n");
while(!flgTerminou) /*Faz enquanto nao terminar e nao ordenao*/
{
if(IniciaSessaoCritica()==0)
{
ordenacao();
TerminaSessaoCritica();
//usleep(200);
}
}
printf("Terminou ordenação de todos os itens\n");
}
Neste bloco temos duas funções:
A thread em si é a threadControlador, que chama a função de ordenação ordenacao.
A ordenação só para quando for atendida duas condições:
Tiver terminado as demais threads, indicado pelo flag flgTerminou e quando tiver sido totalmente ordenado flgordenado.
Executor
A thread do Executor, pode ser vista conforme apresentado a seguir:
/*thread function definition*/
void* threadExecutor(void* args)
{
int oldValue, newValue;
bool flgExecutado = false;
printf("Iniciou o controlador\n");
int posicao = 0;
//while(!flgExecutado)
while((!flgExecutado)&&(!flgTerminou))
{
//printf("Pesquisando Posicao %d\n",posicao);
//printf("Entrou na sessao critica\n");
if (fila[posicao]==0) /*Fila nao foi preenchida*/
{
printf("posicao vazia %d\n",posicao);
posicao = posicao;
} else
{
executada[posicao] = fila[posicao];
printf("Executou[%d] = %d\n",posicao,fila[posicao]);
if(posicao==MAXITEMS-1)
{
printf("Chegou ao fim\n ");
flgExecutado= true; /*Finaliza executor*/
} else
{
posicao ++;
}
}
//printf("terminou while\n");
}
flgTerminouExecucao = true;
printf("Terminou ordenação de todos os itens\n");
}
Ela irá rodar até que duas condições sejam satisfeitas:
flgExecutado – Controla a execução de todas as tarefas da lista
flgTerminou – Controla o fim de todas as demais threads do sistema
Testando programa
Compilando programa
A compilação em um Raspberry PI ocorreu com sucesso.
Executando o programa
root@raspberrypi:/home/mmm/projetos/Threads-para-Raiz/c# ./threads
Bem vindo ao programa das threads
Este programa faz parte do artigo:
http://maurinsoft.com.br/index.php/2022/07/02/threads-para-raiz-parte-1/
Inicializando vetor
Iniciando Recepcao
Iniciando Controlador
Registrou na fila[0] = 80
Registrou na fila[1] = 11
Registrou na fila[2] = 76
Registrou na fila[3] = 71
Registrou na fila[4] = 27
Registrou na fila[5] = 23
Registrou na fila[6] = 33
Registrou na fila[7] = 68
Registrou na fila[8] = 32
Registrou na fila[9] = 92
Recepcao terminou atendimento
Iniciou o controlador
Iniciando Executor
Status:Iniciou o controlador
Executou[0] = 11
Executou[1] = 23
Executou[2] = 27
Executou[3] = 32
Executou[4] = 33
Executou[5] = 68
Executou[6] = 71
Executou[7] = 76
Executou[8] = 80
Executou[9] = 92
Chegou ao fim
Terminou ordenação de todos os itens
Status:Terminou ordenação de todos os itens
Fila ordenada:11 23 27 32 33 68 71 76 80 92
Fila executada:11 23 27 32 33 68 71 76 80 92
Como a execução ficou um pouco longa, resolvi jogar como código.
Conclusão
Podemos perceber que a execução de threads pode ser facilitada com uso de flags externos, que facilitam a comunicação entre os processos. Pudemos ver tambem, que a programação em threads é de fato, um estado de arte da programação C, pois envolve alem de um algoritmo bem desenvolvido, a elaboração de estratégias pensando em que uma thread não sabe exatamente quando a outra irá cumprir suas atividades.
Desta forma cada thread tem que ser pensada em aguardar e esperar as informações das threads que colaboraram com esta.
Desta forma o controle interno das informações é bem mais complicado.
Pudemos ver por ultimo o uso dos sinalizadores, que visão identificar o uso de uma sessão crítica do sistema. Que nada mais é que um recurso compartilhado.
Espero que tenham gostado do artigo.
Em caso de dúvidas ou sugestões, fico a disposição como sempre.
Neste primeiro artigo, iremos estabelecer um projeto, que iremos desenvolver nos demais artigos.
Objetivo
A intenção deste projeto é apresentar solução em diversos linguagens de controle de threads com compartilhamento de informações entre elas.
Proposta de projeto
Imagine que temos 3 funcionários em um departamento público.
Recepção de Protocolo – Ele recebe os protocolos de serviço dos clientes.
Controlador de Serviço – Ele recebe os protocolos da recepção, colocando em ordem numérica em uma fila de execução. Por controlar e ordenar, sua atividade demora tempo mediano.
Executor de Serviço – Ele pega o serviço, por executar o serviço é o mais demorado de todos.
Tempo de execução
Ao analisarmos o departamento, fizemos a seguinte constatação:
A recepção de protocolo, é o departamento mais rápido.
O Controlador de Serviço tem um tempo médio que é o dobro da recepção.
Executor de Serviço – Demora o dobro do tempo do controlador de serviço.
Agora que temos o projeto, podemos no próximo artigo começar sua implementação.
Cython é uma ferramenta de integração Entre Python e C/C++, permitindo criar interfaces integráveis entre as duas linguagens.
O uso do cython tende a auxiliar ambos os programadores dos dois mundos.
Para os programadores C/C++ o uso do python permite criar funções mais dinâmicas e rápidas de serem construídas. Permitindo acesso a tecnologias que o programador C demoraria mais para construir nas interfaces nativas.
Para o programador Python, permite utilizar todo o poder o C e C++ integrado com códigos rápidos e ágeis do Python.
Estaremos neste artigo, instalando o cython na máquina, e no próximo criando um case para que possamos utiliza-lo.
Abordaremos apenas a instalação do cython, pois entendemos que os demais ambientes são de responsábilidade dos desenvolvedores.
Instalação do Cython no Linux
Para instalar o cython é necessário ter o python 3.7 ou superior.
Caso tenha uma versão menor, será necessário atualizar sua versão.