777 lines
25 KiB
C
777 lines
25 KiB
C
/**
|
|
*
|
|
*
|
|
* blink1control-tool --rgb 255,0,0
|
|
* blink1control-tool --list
|
|
* blink1control-tool --version
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <stdarg.h> // vararg stuff
|
|
#include <getopt.h> // for getopt_long()
|
|
#include <unistd.h> // usleep
|
|
#include <time.h>
|
|
|
|
#include <curl/curl.h>
|
|
|
|
#include "json.h" // https://github.com/udp/json-parser
|
|
|
|
|
|
char baseUrl[100] = "http://127.0.0.1:8934/"; // kinda hacky in many ways
|
|
|
|
char progname[] = "blink1control-tool";
|
|
|
|
// start from blink1-lib.h
|
|
#define blink1_max_devices 16
|
|
|
|
#define cache_max 16
|
|
#define serialstrmax (8 + 1)
|
|
#define pathstrmax 128
|
|
|
|
#define blink1mk2_serialstart 0x20000000
|
|
|
|
#define blink1_report_id 1
|
|
#define blink1_report_size 8
|
|
#define blink1_buf_size (blink1_report_size+1)
|
|
// end from blink1-lib.h
|
|
|
|
int brightness = 0;
|
|
|
|
int millis = 300;
|
|
int delayMillis = 500;
|
|
int numDevicesToUse = 0;
|
|
int ledn = 0;
|
|
|
|
char deviceIds[blink1_max_devices][10];
|
|
|
|
uint8_t cmdbuf[blink1_buf_size];
|
|
uint8_t rgbbuf[3];
|
|
int verbose;
|
|
int quiet=0;
|
|
|
|
char urlbuf[200];
|
|
|
|
struct curlMemoryStruct {
|
|
char *memory;
|
|
size_t size;
|
|
};
|
|
|
|
|
|
// printf that can be shut up
|
|
void msg(char* fmt, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args,fmt);
|
|
if( !quiet ) {
|
|
vprintf(fmt,args);
|
|
}
|
|
va_end(args);
|
|
}
|
|
|
|
//
|
|
static size_t
|
|
curlWriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
|
{
|
|
size_t realsize = size * nmemb;
|
|
struct curlMemoryStruct *mem = (struct curlMemoryStruct *)userp;
|
|
|
|
mem->memory = realloc(mem->memory, mem->size + realsize + 1);
|
|
if(mem->memory == NULL) { /* out of memory! */
|
|
printf("not enough memory (realloc returned NULL)\n");
|
|
return 0;
|
|
}
|
|
|
|
memcpy(&(mem->memory[mem->size]), contents, realsize);
|
|
mem->size += realsize;
|
|
mem->memory[mem->size] = 0;
|
|
|
|
return realsize;
|
|
}
|
|
|
|
|
|
// do the actual fetch using curl lib
|
|
char* curl_fetch( char* baseUrl, char* urlbuf)
|
|
{
|
|
CURL *curl_handle;
|
|
CURLcode res;
|
|
|
|
const int urlmaxsize = 1024; //
|
|
char urlstr[urlmaxsize];
|
|
// combine baseUrl to urltsr, making sure not to double-up forward-slashes
|
|
if( baseUrl[strlen(baseUrl) - 1] == '/' ) { // ends in a slash
|
|
urlbuf++;
|
|
}
|
|
snprintf(urlstr, urlmaxsize, "%s%s", baseUrl, urlbuf);
|
|
|
|
msg("curl_fetch: %s\n", urlstr);
|
|
|
|
struct curlMemoryStruct chunk;
|
|
|
|
chunk.memory = malloc(1); /* will be grown as needed by the realloc above */
|
|
chunk.size = 0; /* no data at this point */
|
|
chunk.memory[0] = '\0';
|
|
curl_handle = curl_easy_init(); /* init the curl session */
|
|
curl_easy_setopt(curl_handle, CURLOPT_URL, urlstr); /* specify URL to get */
|
|
/* send all data to this function */
|
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, curlWriteMemoryCallback);
|
|
/* we pass our 'chunk' struct to the callback function */
|
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
|
|
/* some servers don't like requests that are made without a user-agent
|
|
field, so we provide one */
|
|
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "blink1control-tool/1.0");
|
|
res = curl_easy_perform(curl_handle); /* get it! */
|
|
if(res != CURLE_OK) { /* check for errors */
|
|
fprintf(stderr, "curl_fetch failed: %s\n", curl_easy_strerror(res));
|
|
return NULL;
|
|
}
|
|
else {
|
|
// Now, our chunk.memory points to a memory block that is chunk.size
|
|
// bytes big and contains the remote file.
|
|
if( verbose > 1 ) {
|
|
msg("%lu bytes retrieved\n", (long)chunk.size);
|
|
for( int i=0; i<chunk.size; i++ ){
|
|
msg("%c",chunk.memory[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
curl_easy_cleanup(curl_handle); /* cleanup curl stuff */
|
|
//if(chunk.memory)
|
|
// free(chunk.memory);
|
|
//return 0;
|
|
return chunk.memory;
|
|
}
|
|
|
|
//
|
|
void blink1control_printIds()
|
|
{
|
|
char* js = curl_fetch( baseUrl, "/blink1/id" );
|
|
if( js==NULL ) return; // FIXME:
|
|
json_value* jv = json_parse( js, strlen(js));
|
|
|
|
if( jv->type != json_object ) {
|
|
printf("bad response from Blink1Control\n");
|
|
free(js);
|
|
return;
|
|
}
|
|
for( int i=0; i< jv->u.object.length; i++ ) {
|
|
char* name = jv->u.object.values[i].name;
|
|
json_value* jjv = jv->u.object.values[i].value;
|
|
|
|
if( strcmp(name,"blink1_serialnums")==0 ) {
|
|
if( jjv->u.array.length==0 ) {
|
|
printf("no blink(1) devices found\n");
|
|
free(js);
|
|
return;
|
|
}
|
|
for( int j=0; j < jjv->u.array.length; j++ ) {
|
|
json_value* jjjv = jjv->u.array.values[j];
|
|
//printf("id: %s\n", (int) jjjv->u.integer);
|
|
char* serialnum = jjjv->u.string.ptr;
|
|
printf("id:%d - serialnum:%s %s\n", j, serialnum, "");
|
|
//(blink1_isMk2ById(i)) ? "(mk2)":"");
|
|
}
|
|
}
|
|
}
|
|
free(js);
|
|
}
|
|
|
|
//
|
|
int blink1control_fadeToRGBN( int tmillis, int r, int g, int b, char* idstr, int ledn)
|
|
{
|
|
char idarg[100] = "";
|
|
if( idstr != NULL ) {
|
|
sprintf(idarg, "id=%s",idstr);
|
|
}
|
|
sprintf(urlbuf,
|
|
"/blink1/fadeToRGB?rgb=%%23%2.2x%2.2x%2.2x&time=%2.2f&ledn=%d&%s",
|
|
r,g,b, (tmillis/1000.0), ledn, idarg);
|
|
if( verbose > 0 ) msg("url: %s -- %s\n",baseUrl, urlbuf);
|
|
|
|
char* js = curl_fetch( baseUrl, urlbuf );
|
|
|
|
free(js);
|
|
|
|
return 0; // FIXME:
|
|
}
|
|
|
|
// simple cross-platform millis sleep func
|
|
void blink1_sleep(uint16_t millis)
|
|
{
|
|
#ifdef WIN32
|
|
Sleep(millis);
|
|
#else
|
|
usleep( millis * 1000);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Using a brightness value, update an r,g,b triplet
|
|
* Modifies r,g,b in place
|
|
*/
|
|
void blink1_adjustBrightness( uint8_t brightness, uint8_t* r, uint8_t* g, uint8_t* b)
|
|
{
|
|
if( brightness ) {
|
|
*r = (*r * brightness) >> 8;
|
|
*g = (*g * brightness) >> 8;
|
|
*b = (*b * brightness) >> 8;
|
|
}
|
|
}
|
|
|
|
// parse a comma-delimited string containing numbers (dec,hex) into a byte arr
|
|
static int hexread(uint8_t *buffer, char *string, int buflen)
|
|
{
|
|
char *s;
|
|
int pos = 0;
|
|
memset(buffer,0,buflen); // bzero() not defined on Win32?
|
|
while((s = strtok(string, ", ")) != NULL && pos < buflen){
|
|
string = NULL;
|
|
buffer[pos++] = (char)strtol(s, NULL, 0);
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
// integer-only hsbtorgb
|
|
// from: http://web.mit.edu/storborg/Public/hsvtorgb.c
|
|
static void hsbtorgb( uint8_t* hsb, uint8_t* rgb)
|
|
{
|
|
uint8_t h = hsb[0];
|
|
uint8_t s = hsb[1];
|
|
uint8_t v = hsb[2];
|
|
|
|
unsigned char region, fpart, p, q, t;
|
|
uint8_t r,g,b;
|
|
|
|
if(s == 0) { // color is grayscale
|
|
r = g = b = v;
|
|
return;
|
|
}
|
|
|
|
region = h / 43; // make hue 0-5
|
|
fpart = (h - (region * 43)) * 6; // find remainder part, make it from 0-255
|
|
|
|
// calculate temp vars, doing integer multiplication
|
|
p = (v * (255 - s)) >> 8;
|
|
q = (v * (255 - ((s * fpart) >> 8))) >> 8;
|
|
t = (v * (255 - ((s * (255 - fpart)) >> 8))) >> 8;
|
|
|
|
// assign temp vars based on color cone region
|
|
switch(region) {
|
|
case 0: r = v; g = t; b = p; break;
|
|
case 1: r = q; g = v; b = p; break;
|
|
case 2: r = p; g = v; b = t; break;
|
|
case 3: r = p; g = q; b = v; break;
|
|
case 4: r = t; g = p; b = v; break;
|
|
default: r = v; g = p; b = q; break;
|
|
}
|
|
rgb[0]=r;
|
|
rgb[1]=g;
|
|
rgb[2]=b;
|
|
}
|
|
|
|
//
|
|
static void usage(char *myName)
|
|
{
|
|
fprintf(stderr,
|
|
"Usage: \n"
|
|
" %s <cmd> [options]\n"
|
|
"where <cmd> is one of:\n"
|
|
" --blink <numtimes> Blink on/off (use --rgb to blink a color)\n"
|
|
" --random, --random=<num> Flash a number of random colors \n"
|
|
" --glimmer, --gimmer=<num> Glimmer a color with --rgb (num times)\n"
|
|
" --running, --running=<num> Do running animation (num times)\n"
|
|
" --rgb=<red>,<green>,<blue> Fade to RGB value\n"
|
|
" --rgb=[#]RRGGBB Fade to RGB value, as hex color code\n"
|
|
" --hsb=<hue>,<sat>,<bri> Fade to HSB value\n"
|
|
" --rgbread Read last RGB color sent (post gamma-correction)\n"
|
|
" --on | --white Turn blink(1) full-on white \n"
|
|
" --off Turn blink(1) off \n"
|
|
" --red Turn blink(1) red \n"
|
|
" --green Turn blink(1) green \n"
|
|
" --blue Turn blink(1) blue \n"
|
|
" --cyan Turn blink(1) cyan (green + blue) \n"
|
|
" --magenta Turn blink(1) magenta (red + blue) \n"
|
|
" --yellow Turn blink(1) yellow (red + green) \n"
|
|
" --setpattline <pos> Write pattern RGB val at pos (--rgb/hsb to set)\n"
|
|
" --getpattline <pos> Read pattern RGB value at pos\n"
|
|
" --savepattern Save color pattern to flash (mk2)\n"
|
|
" --play <1/0,pos> Start playing color sequence (at pos)\n"
|
|
" --play <1/0,start,end,cnt> Playing color sequence sub-loop (mk2)\n"
|
|
" --servertickle <1/0>[,1/0] Turn on/off servertickle (w/on/off, uses -t msec)\n"
|
|
" --running Multi-LED effect (uses --led & --rgb)\n"
|
|
" --list List connected blink(1) devices \n"
|
|
" Nerd functions: (not used normally) \n"
|
|
" --fwversion Display blink(1) firmware version \n"
|
|
" --version Display blink1control-tool version info \n"
|
|
"and [options] are: \n"
|
|
" -U <url> --baseurl <url> Use url instead of 'http://localhost:8934/'\n"
|
|
" -d dNums --id all|deviceIds Use these blink(1) ids (from --list) \n"
|
|
" -g -nogamma Disable autogamma correction\n"
|
|
" -b b --brightness b Set brightness (0=use real vals, 1-255 scaled)\n"
|
|
" -m ms, --millis=millis Set millisecs for color fading (default 300)\n"
|
|
" -q, --quiet Mutes all stdout output (supercedes --verbose)\n"
|
|
" -t ms, --delay=millis Set millisecs between events (default 500)\n"
|
|
" -l <led>, --led=<led> Set which RGB LED in a blink(1) mk2 to use\n"
|
|
" -v, --verbose verbose debugging msgs\n"
|
|
"\n"
|
|
"Examples \n"
|
|
" blink1control-tool -m 100 --rgb=255,0,255 # fade to #FF00FF in 0.1 seconds \n"
|
|
" blink1control-tool -t 2000 --random=100 # every 2 seconds new random color\n"
|
|
" blink1control-tool --rgb=0xff,0,00 --blink 3 # blink red 3 times\n"
|
|
" blink1-tool --rgb=FF9900 # make blink1 pumpkin orange\n"
|
|
" blink1-tool --rgb=#FF9900 # make blink1 pumpkin orange\n"
|
|
"\n"
|
|
,myName);
|
|
}
|
|
|
|
// local states for the "cmd" option variable
|
|
enum {
|
|
CMD_NONE = 0,
|
|
CMD_LIST,
|
|
CMD_RGB,
|
|
CMD_HSB,
|
|
CMD_RGBREAD,
|
|
CMD_SETPATTLINE,
|
|
CMD_GETPATTLINE,
|
|
CMD_SAVEPATTERN,
|
|
CMD_OFF,
|
|
CMD_ON,
|
|
CMD_RED,
|
|
CMD_GRN,
|
|
CMD_BLU,
|
|
CMD_CYAN,
|
|
CMD_MAGENTA,
|
|
CMD_YELLOW,
|
|
CMD_BLINK,
|
|
CMD_GLIMMER,
|
|
CMD_PLAY,
|
|
CMD_STOP,
|
|
CMD_GETPLAYSTATE,
|
|
CMD_RANDOM,
|
|
CMD_RUNNING,
|
|
CMD_VERSION,
|
|
CMD_FWVERSION,
|
|
CMD_SERVERDOWN,
|
|
CMD_TESTTEST,
|
|
};
|
|
|
|
//
|
|
int main(int argc, char** argv)
|
|
{
|
|
//int openall = 0;
|
|
//int nogamma = 0;
|
|
int16_t arg=0;
|
|
|
|
//int rc;
|
|
uint8_t tmpbuf[100];
|
|
//char serialnumstr[serialstrmax] = {'\0'};
|
|
|
|
srand( time(NULL) * getpid() );
|
|
memset( cmdbuf, 0, sizeof(cmdbuf));
|
|
|
|
static int cmd = CMD_NONE;
|
|
|
|
// parse options
|
|
int option_index = 0, opt;
|
|
char* opt_str = "aqvhm:t:d:U:gl:b:";
|
|
static struct option loptions[] = {
|
|
{"baseurl", required_argument, 0, 'U'},
|
|
{"all", no_argument, 0, 'a'},
|
|
{"verbose", optional_argument, 0, 'v'},
|
|
{"quiet", optional_argument, 0, 'q'},
|
|
{"millis", required_argument, 0, 'm'},
|
|
{"delay", required_argument, 0, 't'},
|
|
{"id", required_argument, 0, 'd'},
|
|
{"led", required_argument, 0, 'l'},
|
|
{"ledn", required_argument, 0, 'l'},
|
|
//{"nogamma", no_argument, 0, 'g'},
|
|
{"brightness", required_argument, 0, 'b'},
|
|
{"help", no_argument, 0, 'h'},
|
|
{"list", no_argument, &cmd, CMD_LIST },
|
|
{"rgb", required_argument, &cmd, CMD_RGB },
|
|
{"hsb", required_argument, &cmd, CMD_HSB },
|
|
{"rgbread", no_argument, &cmd, CMD_RGBREAD},
|
|
{"savepattline",required_argument,&cmd, CMD_SETPATTLINE },//backcompat
|
|
{"setpattline",required_argument, &cmd, CMD_SETPATTLINE },
|
|
{"getpattline",required_argument, &cmd, CMD_GETPATTLINE },
|
|
{"savepattern",no_argument, &cmd, CMD_SAVEPATTERN },
|
|
{"off", no_argument, &cmd, CMD_OFF },
|
|
{"on", no_argument, &cmd, CMD_ON },
|
|
{"white", no_argument, &cmd, CMD_ON },
|
|
{"red", no_argument, &cmd, CMD_RED },
|
|
{"green", no_argument, &cmd, CMD_GRN },
|
|
{"blue", no_argument, &cmd, CMD_BLU},
|
|
{"cyan", no_argument, &cmd, CMD_CYAN},
|
|
{"magenta", no_argument, &cmd, CMD_MAGENTA},
|
|
{"yellow", no_argument, &cmd, CMD_YELLOW},
|
|
{"blink", required_argument, &cmd, CMD_BLINK},
|
|
{"glimmer", optional_argument, &cmd, CMD_GLIMMER},
|
|
{"play", required_argument, &cmd, CMD_PLAY},
|
|
{"stop", no_argument, &cmd, CMD_STOP},
|
|
{"playstate", no_argument, &cmd, CMD_GETPLAYSTATE},
|
|
{"random", optional_argument, &cmd, CMD_RANDOM },
|
|
{"running", optional_argument, &cmd, CMD_RUNNING },
|
|
{"version", no_argument, &cmd, CMD_VERSION },
|
|
{"fwversion", no_argument, &cmd, CMD_FWVERSION },
|
|
{"servertickle", required_argument, &cmd,CMD_SERVERDOWN },
|
|
{"testtest", no_argument, &cmd, CMD_TESTTEST },
|
|
{NULL, 0, 0, 0}
|
|
};
|
|
while(1) {
|
|
opt = getopt_long(argc, argv, opt_str, loptions, &option_index);
|
|
if (opt==-1) break; // parsed all the args
|
|
switch (opt) {
|
|
case 0: // deal with long opts that have no short opts
|
|
switch(cmd) {
|
|
case CMD_RGB:
|
|
// parse hex color code like "#FF00FF"
|
|
if( optarg[0] == '#' || strlen(optarg)==6 ) {
|
|
optarg = (optarg[0] == '#') ? optarg+1 : optarg;
|
|
uint32_t poop = strtol(optarg, NULL, 16);
|
|
rgbbuf[0] = (poop >> 16) & 0xff;
|
|
rgbbuf[1] = (poop >> 8) & 0xff;
|
|
rgbbuf[2] = (poop >> 0) & 0xff;
|
|
} else {
|
|
hexread(rgbbuf, optarg, sizeof(rgbbuf));
|
|
}
|
|
break;
|
|
case CMD_HSB:
|
|
hexread(tmpbuf, optarg, 4);
|
|
hsbtorgb( tmpbuf, rgbbuf );
|
|
cmd = CMD_RGB; // haha!
|
|
break;
|
|
case CMD_SETPATTLINE:
|
|
case CMD_GETPATTLINE:
|
|
case CMD_BLINK:
|
|
case CMD_PLAY:
|
|
case CMD_SERVERDOWN:
|
|
hexread(cmdbuf, optarg, sizeof(cmdbuf)); // cmd w/ hexlist arg
|
|
break;
|
|
case CMD_RANDOM:
|
|
case CMD_RUNNING:
|
|
case CMD_GLIMMER:
|
|
arg = (optarg) ? strtol(optarg,NULL,0) : 0;// cmd w/ number arg
|
|
break;
|
|
case CMD_ON:
|
|
rgbbuf[0] = 255; rgbbuf[1] = 255; rgbbuf[2] = 255;
|
|
break;
|
|
case CMD_OFF:
|
|
rgbbuf[0] = 0; rgbbuf[1] = 0; rgbbuf[2] = 0;
|
|
break;
|
|
case CMD_RED:
|
|
rgbbuf[0] = 255;
|
|
break;
|
|
case CMD_GRN:
|
|
rgbbuf[1] = 255;
|
|
break;
|
|
case CMD_BLU:
|
|
rgbbuf[2] = 255;
|
|
break;
|
|
case CMD_CYAN:
|
|
rgbbuf[1] = 255; rgbbuf[2] = 255;
|
|
break;
|
|
case CMD_MAGENTA:
|
|
rgbbuf[0] = 255; rgbbuf[2] = 255;
|
|
break;
|
|
case CMD_YELLOW:
|
|
rgbbuf[0] = 255; rgbbuf[1] = 255;
|
|
break;
|
|
} // switch(cmd)
|
|
break;
|
|
case 'g':
|
|
//nogamma = 1;
|
|
break;
|
|
case 'b':
|
|
brightness = strtol(optarg,NULL,10);
|
|
break;
|
|
case 'a':
|
|
//openall = 1;
|
|
break;
|
|
case 'm':
|
|
millis = strtol(optarg,NULL,10);
|
|
break;
|
|
case 't':
|
|
delayMillis = strtol(optarg,NULL,10);
|
|
break;
|
|
case 'l':
|
|
ledn = strtol(optarg,NULL,10);
|
|
break;
|
|
case 'q':
|
|
if( optarg==NULL ) quiet++;
|
|
else quiet = strtol(optarg,NULL,0);
|
|
break;
|
|
case 'v':
|
|
if( optarg==NULL ) verbose++;
|
|
else verbose = strtol(optarg,NULL,0);
|
|
if( verbose > 3 ) {
|
|
fprintf(stderr,"going REALLY verbose\n");
|
|
}
|
|
break;
|
|
case 'd':
|
|
if( strcmp(optarg,"all") == 0 ) {
|
|
numDevicesToUse = 0; //blink1_max_devices; //FIXME
|
|
}
|
|
else { // if( strcmp(optarg,",") != -1 ) { // comma-separated list
|
|
char* pch;
|
|
//int base = 0;
|
|
pch = strtok( optarg, " ,");
|
|
numDevicesToUse = 0;
|
|
while( pch != NULL ) {
|
|
//int base = (strlen(pch)==8) ? 16:0;
|
|
strcpy( deviceIds[numDevicesToUse++], pch );
|
|
pch = strtok(NULL, " ,");
|
|
}
|
|
// verbose
|
|
for( int i=0; i<numDevicesToUse; i++ ) {
|
|
msg("deviceId[%d]: %s\n", i, deviceIds[i]);
|
|
}
|
|
}
|
|
break;
|
|
case 'U':
|
|
strncpy(baseUrl, optarg, 100);
|
|
break;
|
|
case 'h':
|
|
usage( progname );
|
|
exit(1);
|
|
break;
|
|
}
|
|
} // while(1)
|
|
|
|
if(argc < 2){
|
|
usage( progname );
|
|
//exit(1);
|
|
}
|
|
|
|
char idstr[100] = "";
|
|
|
|
for( int i=0; i< numDevicesToUse; i++ ) {
|
|
sprintf(idstr, "%s,", deviceIds[i]);
|
|
}
|
|
//printf("idstr: %s\n",idstr);
|
|
|
|
curl_global_init(CURL_GLOBAL_ALL);
|
|
|
|
if( cmd == CMD_VERSION ) {
|
|
// FIXME: do something here
|
|
msg("blink1control-tool version "BLINK1_VERSION"\n");
|
|
}
|
|
else if( cmd == CMD_RGB || cmd == CMD_ON || cmd == CMD_OFF ||
|
|
cmd == CMD_RED || cmd == CMD_BLU || cmd == CMD_GRN ||
|
|
cmd == CMD_CYAN || cmd == CMD_MAGENTA || cmd == CMD_YELLOW ) {
|
|
|
|
uint8_t r = rgbbuf[0];
|
|
uint8_t g = rgbbuf[1];
|
|
uint8_t b = rgbbuf[2];
|
|
|
|
blink1_adjustBrightness( brightness, &r, &g, &b);
|
|
msg("set dev:%s to rgb:0x%2.2x,0x%2.2x,0x%2.2x over %d msec\n",
|
|
idstr,r,g,b,millis);
|
|
blink1control_fadeToRGBN( millis, r,g,b, idstr, ledn );
|
|
}
|
|
else if( cmd == CMD_BLINK ) {
|
|
uint8_t n = cmdbuf[0];
|
|
uint8_t r = rgbbuf[0];
|
|
uint8_t g = rgbbuf[1];
|
|
uint8_t b = rgbbuf[2];
|
|
if( r == 0 && b == 0 && g == 0 ) {
|
|
r = g = b = 255;
|
|
}
|
|
blink1_adjustBrightness( brightness, &r, &g, &b);
|
|
msg("blink %d times rgb:%x,%x,%x: \n", n,r,g,b);
|
|
for( int i=0; i<n; i++ ) {
|
|
blink1control_fadeToRGBN( millis, r,g,b, idstr, ledn );
|
|
blink1_sleep(delayMillis);
|
|
blink1control_fadeToRGBN( millis, 0,0,0, idstr, ledn );
|
|
blink1_sleep(delayMillis);
|
|
}
|
|
}
|
|
else if( cmd == CMD_RANDOM ) {
|
|
//int cnt = blink1_getCachedCount();
|
|
if( arg==0 ) arg = 1;
|
|
msg("random %d times: \n", arg);
|
|
for( int i=0; i<arg; i++ ) {
|
|
uint8_t r = rand()%255;
|
|
uint8_t g = rand()%255;
|
|
uint8_t b = rand()%255 ;
|
|
//uint8_t id = rand() % blink1_getCachedCount();
|
|
|
|
blink1_adjustBrightness( brightness, &r, &g, &b);
|
|
msg("%d: %d/%d : %2.2x,%2.2x,%2.2x \n",
|
|
i, 0, 0, r,g,b);
|
|
//i, id, blink1_getCachedCount(), r,g,b);
|
|
|
|
uint8_t n = (ledn!=0) ? (1 + rand() %ledn) : 0;
|
|
blink1control_fadeToRGBN( millis, r,g,b, idstr, n );
|
|
blink1_sleep(delayMillis);
|
|
}
|
|
}
|
|
else if( cmd == CMD_GLIMMER ) {
|
|
uint8_t n = arg;
|
|
uint8_t r = rgbbuf[0];
|
|
uint8_t g = rgbbuf[1];
|
|
uint8_t b = rgbbuf[2];
|
|
if( r == 0 && b == 0 && g == 0 ) {
|
|
r = g = b = 127;
|
|
if( n == 0 ) n = 3;
|
|
}
|
|
blink1_adjustBrightness( brightness, &r, &g, &b);
|
|
msg("glimmering %d times rgb:#%2.2x%2.2x%2.2x: \n", n,r,g,b);
|
|
for( int i=0; i<n; i++ ) {
|
|
blink1control_fadeToRGBN( millis,r,g,b, idstr, 1);
|
|
blink1control_fadeToRGBN( millis,r/2,g/2,b/2, idstr, 2);
|
|
blink1_sleep(delayMillis/2);
|
|
blink1control_fadeToRGBN( millis,r/2,g/2,b/2, idstr, 1);
|
|
blink1control_fadeToRGBN( millis,r,g,b, idstr, 2);
|
|
blink1_sleep(delayMillis/2);
|
|
}
|
|
// turn them both off
|
|
blink1control_fadeToRGBN( millis, 0,0,0, idstr, 1);
|
|
blink1control_fadeToRGBN( millis, 0,0,0, idstr, 2);
|
|
}
|
|
else if( cmd == CMD_LIST ) {
|
|
//int count = 0;
|
|
printf("blink(1) list: \n");
|
|
//for( int i=0; i< count; i++ ) {
|
|
//printf("id:%d - serialnum:%s %s\n", i, blink1_getCachedSerial(i),
|
|
// (blink1_isMk2ById(i)) ? "(mk2)":"");
|
|
//}
|
|
|
|
blink1control_printIds();
|
|
}
|
|
|
|
curl_global_cleanup(); // we're done with libcurl, so clean it up
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
// parse output. look for:
|
|
// - is valid json
|
|
// - presence of 'status'
|
|
// - presence of command name in status (doesn't work for on/off)
|
|
|
|
//char* theJson = chunk.memory;
|
|
//int resultCode;
|
|
//jsmn_parser jsparser;
|
|
//jsmntok_t jstokens[128]; // a number >= total number of tokens
|
|
|
|
//jsmn_parser parser;
|
|
//jsm_init(&parser);
|
|
|
|
//jsmntok_t tokens[10];
|
|
|
|
// js - pointer to JSON string
|
|
// tokens - an array of tokens available
|
|
// 10 - number of tokens available
|
|
//jsmn_init_parser(&parser, js, tokens, 10);
|
|
//jsmn_init(&parser);
|
|
//resultCode = jsmn_parse(&parser, theJson, 100, jstokens, 256);
|
|
|
|
char URL[] = "http://127.0.0.1:8934/blink1/id";
|
|
char *KEYS[] = { "blink1_serialnums", "blink1_id", "status", "blink1control_version", "blink1control_config" };
|
|
|
|
char *js = json_fetch(URL);
|
|
jsmntok_t *tokens = json_tokenise(js);
|
|
|
|
// The GitHub user API response is a single object. States required to
|
|
// parse this are simple: start of the object, keys, values we want to
|
|
// print, values we want to skip, and then a marker state for the end.
|
|
|
|
typedef enum { START, KEY, PRINT, SKIP, STOP } parse_state;
|
|
parse_state state = START;
|
|
|
|
size_t object_tokens = 0;
|
|
|
|
for (size_t i = 0, j = 1; j > 0; i++, j--)
|
|
{
|
|
jsmntok_t *t = &tokens[i];
|
|
|
|
// Should never reach uninitialized tokens
|
|
log_assert(t->start != -1 && t->end != -1);
|
|
|
|
if (t->type == JSMN_ARRAY || t->type == JSMN_OBJECT)
|
|
j += t->size;
|
|
|
|
switch (state)
|
|
{
|
|
case START:
|
|
if (t->type != JSMN_OBJECT)
|
|
log_die("Invalid response: root element must be an object.");
|
|
|
|
state = KEY;
|
|
object_tokens = t->size;
|
|
|
|
if (object_tokens == 0)
|
|
state = STOP;
|
|
|
|
if (object_tokens % 2 != 0)
|
|
log_die("Invalid response: object must have even number of children.");
|
|
|
|
break;
|
|
|
|
case KEY:
|
|
object_tokens--;
|
|
|
|
if (t->type != JSMN_STRING)
|
|
log_die("Invalid response: object keys must be strings.");
|
|
|
|
state = SKIP;
|
|
|
|
for (size_t i = 0; i < sizeof(KEYS)/sizeof(char *); i++)
|
|
{
|
|
if (json_token_streq(js, t, KEYS[i]))
|
|
{
|
|
printf("%s: ", KEYS[i]);
|
|
state = PRINT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case SKIP:
|
|
if (t->type != JSMN_STRING && t->type != JSMN_PRIMITIVE)
|
|
log_die("Invalid response: object values must be strings or primitives.");
|
|
|
|
object_tokens--;
|
|
state = KEY;
|
|
|
|
if (object_tokens == 0)
|
|
state = STOP;
|
|
|
|
break;
|
|
|
|
case PRINT:
|
|
if (t->type != JSMN_STRING && t->type != JSMN_PRIMITIVE) {
|
|
// log_die("Invalid response: object values must be strings or primitives.");
|
|
}
|
|
|
|
char *str = json_token_tostr(js, t);
|
|
puts(str);
|
|
|
|
object_tokens--;
|
|
state = KEY;
|
|
|
|
if (object_tokens == 0)
|
|
state = STOP;
|
|
|
|
break;
|
|
|
|
case STOP:
|
|
// Just consume the tokens
|
|
break;
|
|
|
|
default:
|
|
log_die("Invalid state %u", state);
|
|
}
|
|
}
|
|
*/
|