libvcomm  1.0
 All Data Structures Files Functions Variables Typedefs Macros Groups Pages
blaster.c
/** @file blaster.c
* blaster.c
*
* Simple IRvoodoo command-line blaster program.
* Program uses GNU dbm database (http://www.gnu.org.ua/software/gdbm/) for
* database and libvcomm for communication.
*
* Installation:
* Build dependencies:
* libudev, libgdbm, libvcomm
*
* To compile:
* gcc -I<path to .h file> -L<path to libraries> -o blaster blaster.c -lgdbm -lvcomm -ludev
*
* @date 17.10.2012
* @author Tarmo Kople <tarmo@flycom.ee>
*/
#include <gdbm.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <ctype.h>
#include <stdint.h>
#include <vcomm.h>
#define FALSE 0
#define TRUE 1
// database
GDBM_FILE myDB;
datum daKey, daVal;
int dbRet;
// IRvoodoo handle
hid_device *vhandle;
void usage(void) {
fprintf(stderr, "\nUsage: blaster [options]\n"
"Options:\n"
" -b <event name> Blast event\n"
" -n <event name> Add new event\n"
" -d <event name> Delete event\n"
" -l List events\n"
"\n");
}
/**
* Initialize blaster
*
* open connection to IRvoodoo
* open or create gdbm database for blast commands
*/
void initBlaster() {
// open connection IRvoodoo
int resp;
if ((resp = Vopen(&vhandle, 0))) {
switch (resp) {
fprintf(stderr, "Error: could not find IRvoodoo\n");
break;
fprintf(stderr,
"Error: could not open IRvoodoo,\ncheck device permissions!\n");
break;
fprintf(stderr, "Error: libvcomm argument error\n");
break;
default:
fprintf(stderr, "Error: %d has occured !\n", resp);
break;
}
// give up
exit(EXIT_FAILURE);
}
// open database
myDB = gdbm_open("events.gdb", 512, GDBM_WRCREAT | GDBM_NOLOCK | GDBM_SYNC,
0664, NULL);
if (myDB == NULL) {
fprintf(stderr, "ERROR: Could not open the DB file.\n");
exit(EXIT_FAILURE);
}
printf("DB opened.\n");
}
/**
* Handle communication error.
* (just print error & exit with EXIT_FAILURE)
*/
void comm_err() {
fprintf(stderr, "Error: communication error !\n");
exit(EXIT_FAILURE);
}
/**
* Cleanup, called automatically on exit
*
* Close IRvoodoo connection
* Close database
*/
void closeBlaster() {
if (vhandle) {
Vclose(&vhandle);
}
if (myDB) {
gdbm_close(myDB);
}
}
/**
* Add new blast event to gdbm database.
*
* Clear IRvoodoo's last decoded IRcode -> capture new IRcode -> save to dgbm database
*
* @param evname
*/
void new_event(char *evname) {
initBlaster();
/*
* Create new empty IRcode
*/
ircode_t ircode;
memset(&ircode, 0, sizeof(ircode));
// disable output buffering (needed for capture process printing)
setbuf(stdout, NULL);
printf("Got event name: %s\n", evname);
/*
* Clear IRvoodoo's last decoded IRcode, since we are waiting new IRcode
*/
if (Vclear_last(&vhandle))
comm_err();
/*
* Start capturing process.
* Stop on new IRcode or on timeout.
*/
printf("Waiting for IRcode. Press remote key !!!\n");
int maxtryes = 15;
if (Vget_ircode(&vhandle, &ircode))
comm_err();
while (ircode.protocol == 0 && maxtryes-- > 0) {
printf(".");
// No IRcode, sleep 1 s, wait for user to press remote key
sleep(1);
if (Vget_ircode(&vhandle, &ircode))
comm_err();
}
printf("\n");
if (maxtryes == -1) {
// timeout, give up
printf("Timeout !\n");
exit(EXIT_SUCCESS);
}
/*
* Success
*/
// add database entry event_name -> ircode
daKey.dptr = evname;
daKey.dsize = strlen(evname) + 1;
daVal.dptr = (char *) &ircode;
daVal.dsize = sizeof(ircode);
dbRet = gdbm_store(myDB, daKey, daVal, GDBM_REPLACE);
if (!dbRet) {
// print IRcode structure out as two 32 bit integers
printf("Event \"%s\" -> \"%08X %08X\" added successfully ! \n", evname,
*(uint32_t *) &ircode, *(((uint32_t *) &ircode) + 1));
}
exit(EXIT_SUCCESS);
}
/**
* Open database and list all available events
*/
void list_events() {
initBlaster();
ircode_t *ircode;
datum daVal;
datum evname = gdbm_firstkey(myDB);
while (evname.dptr) {
datum nextev;
daVal = gdbm_fetch(myDB, evname);
ircode = (ircode_t *) daVal.dptr;
// print IRcode structure out as two 32 bit integers
printf("Event \"%s\" -> \"%08X %08X\"\n", evname.dptr,
*(uint32_t *) ircode, *(((uint32_t *) ircode) + 1));
nextev = gdbm_nextkey(myDB, evname);
evname = nextev;
}
exit(EXIT_SUCCESS);
}
/**
* Delete event from gdbm database by name
* @param evname event name to delete
*/
void delete_event(char *evname) {
initBlaster();
daKey.dptr = evname;
daKey.dsize = strlen(evname) + 1;
if (gdbm_delete(myDB, daKey) < 0) {
printf("ERROR: Event \"%s\" not found\n", (char *) daKey.dptr);
} else {
printf("Event '%s' deleted.\n", (char *) daKey.dptr);
}
exit(EXIT_SUCCESS);
}
/**
* Find event from gdbm database and send it to IRvoodoo (blast).
*
* @param evname event name to blast
*/
void blast_event(char *evname) {
initBlaster();
cmdstat_t cmdstat;
/*
* Find event by name
*/
daKey.dptr = evname;
daKey.dsize = strlen(evname) + 1;
daVal = gdbm_fetch(myDB, daKey);
if (daVal.dptr == NULL) {
printf("ERROR: Event \"%s\" not found\n", (char *) daKey.dptr);
exit(EXIT_SUCCESS);
}
printf("Sending event: '%s' ...\n", (char *) daKey.dptr);
/*
* Send IRcode to IRvoodoo
*/
if (Vset_ircode(&vhandle, (ircode_t *) daVal.dptr, &cmdstat)) comm_err();
/*
* Check response from IRvoodoo
*/
if (cmdstat.type == RESP_OK) {
// OK
printf("Event successfully blasted !\n");
} else if (cmdstat.type == RESP_ERR) {
// Error
switch (cmdstat.err_code) {
printf("Error: IR protocol not supported !\n");
break;
default:
printf("Error: %d !\n", cmdstat.err_code);
break;
}
} else {
// Unknown
printf("Error: Unknown response from IRvoodoo !\n");
}
exit(EXIT_SUCCESS);
}
int main(int argc, char *argv[]) {
vhandle = NULL;
// set exit hook for cleanup
atexit(closeBlaster);
int c;
while ((c = getopt(argc, argv, "b:n:d:lh")) != -1)
switch (c) {
case 'b':
blast_event(optarg);
break;
case 'n':
new_event(optarg);
break;
case 'd':
delete_event(optarg);
break;
case 'l':
list_events();
break;
case 'h':
usage();
exit(EXIT_SUCCESS);
break;
case '?':
if (isprint(optopt))
fprintf(stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
break;
}
usage();
exit(EXIT_SUCCESS);
}