Intel Bong com Edison

Intel Bong usando o buzzer do Grove Kit e a biblioteca UPM compilando direto no Intel Edison

Eu quero emitir alertas sonoros no meu projeto de controle IoT e para isso eu precisava entender como a classe buzzer da biblioteca UPM funciona, dava para fazer tudo usando apenas a MRAA afinal é apenas um PWM em um terminal, mas vale a pena usar a UPM pois já vou usar para coisas mais pesadas como controle de periféricos i2c por exemplo.

Outro motivo para esse pequeno tutorial é que a UPM tem vários recursos e bons exemplos mas não encontrei nenhum lugar explicando como compilar apenas usando os recursos do próprio Edison com uma simples linha de comando ou no máximo com um pequeno Makefile. Isso é muito útil quando estamos em uma aula ou trabalhando em um projeto pequeno e não é interessante subir um ambiente de desenvolvimento completo.

E por fim eu queria fazer uma pequena homenagem a Intel pela ajuda que eles dão aos Makerspaces e o apoio ao software livre. Daí surgiu a ideia de fazer o bong, aquele som que a Intel toca quando aparece o logo, usando o Edison e o buzzer… e claro falhei miseravelmente! O buzzer simplesmente não consegue reproduzir as notas, falei com alguns amigos músicos, um deles já até tinha tentado a mesma proeza e mesmo assim não consegui melhorar muito o resultado final. Se você conseguir um resultado melhor por favor faça um patch para o código, ele esta hospedado no GitHub.

Tocando

É simples tocar usando um buzzer, basta conectar o componente em uma porta e ficar alterando a frequência PWM. A UPM facilita essa tarefa com a função playSound da classe Buzzer que passa a frequência e já espera o tempo correto.

Nesse exemplo eu conectei o buzzer no terminal D6.

#include <unistd.h>
#include <buzzer.h>

int main(void) {

    int chord[] = {294, 294, 392, 294, 440, 0};
    int time[]  = {400, 150, 150, 150, 300, 0};

    upm::Buzzer* sound = new upm::Buzzer(6);

    int i=0;
    while (chord[i]) {
        int t = time[i]*1000;
        sound->playSound(chord[i], t );
    	usleep(t/4);
	i++;
    }
    usleep(100000);
    delete sound;

    return 0;
}

O programa é bem simples, apenas um loop que corre o vetor com as frequências e os tempos. Um truque no final é dar tempo para a UPM parar o ultimo som antes do objeto ser removido da memória com o comando delete, isso é importante porque a ultima nota pode continuar tocando indefinidamente se a UPM não tiver tempo de parar o PWM.

Compilando

Compilar esse código é relativamente simples, basta colocar o fonte no arquivo main.cpp e executar o comando abaixo, isso tudo no próprio Edison.

gcc -Wall -O2 $(pkg-config --cflags --libs upm-buzzer) -lstdc++ main.cpp -o intelBong

O Edison já vem com as bibliotecas instaladas e com os pacotes de desenvolvimento o que esse comando faz é simplesmente usar pkg-config para pegar o diretório contendo os includes e as libs onde a UPM esta instalada. Outro truque é que passamos uma referencia para a stdlib++ já que a UPM é escrita em C++, se estivéssemos usando apenas a MRAA isso não seria necessário.

Makefile

Para ficar um pouco mais arrumado escrevi um pequeno Makefile…

CFLAGS += `pkg-config --cflags upm-buzzer`
LDFLAGS += `pkg-config --libs upm-buzzer`

all:
	gcc -Wall -O2 $(CFLAGS) $(LDFLAGS) -lstdc++ main.cpp -o intelBong

clean:
	rm -f intelBong

Espero que aproveite o Intel Bong mais desafinado e longe dos tempos corretos. :D

Wrapper para Golang

E agora o mesmo executável só que escrito em Go, apenas porque eu gosto de Go.

Criando o wrapper

Primeiro vamos criar o wrapper para as funções do buzzer que vmaos usar.

Este é o cabeçalho buzzer_go.hpp:

#ifndef __BUZZER_GO_H__
#define __BUZZER_GO_H__

#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

void initSound(int p);
void playSound(int c, int t);
void deleteSound(void);

#ifdef __cplusplus
}
#endif
#endif

E agora a implementação buzzer_go.cpp:

#include <buzzer.h>
#include "buzzer_go.hpp"

upm::Buzzer* sound;

void initSound(int p) {
    sound = new upm::Buzzer(p);
}

void playSound(int c, int t) {
    sound->playSound(c, t);
}

void deleteSound(void) {
    delete sound;
}

Agora o nosso código em Go quase igual ao seu equivalente em C++, eu chamei o arquivo de intelBong.go

package main

/*
	#cgo LDFLAGS: -lstdc++ buzzer_go.a
	#cgo pkg-config: upm-buzzer
	#include "buzzer_go.hpp"
*/
import "C"

import "time"

func main() {
	C.initSound(6) // D6

	c := []int{294, 294, 392, 294, 440, 0}
	t := []int{400, 150, 150, 150, 300, 0}

	for i := 0; c[i] > 0; i++ {
		aux := t[i] * 1000
		C.playSound(C.int(c[i]), C.int(aux))
		time.Sleep(time.Duration(aux) / 4 * time.Microsecond)
	}
	time.Sleep(1 * time.Second)
	C.deleteSound()
}

Makefile

Finalmente adicionamos a compilação da implementação em go no nosso Makefile

CFLAGS += `pkg-config --cflags upm-buzzer`
LDFLAGS += `pkg-config --libs upm-buzzer`

all:
	gcc -Wall -O2 $(CFLAGS) $(LDFLAGS) -lstdc++ main.cpp -o intelBong

buzzer_go:
	gcc -c -Wall -O2 $(CFLAGS) $(LDFLAGS) -lstdc++ buzzer_go.cpp
	ar rvs buzzer_go.a buzzer_go.o
	go build intelBong.go

clean:
	rm -f buzzer_go.o buzzer_go.a intelBong

Compilando

Para compilar a versão Go é só executar o make passando buzzer_go como parâmetro:

make buzzer_go

Pronto, agora você pode usar o buzzer com Go também :D

comments powered by Disqus