Create a gist now

Instantly share code, notes, and snippets.

Digispark and nodejs - talking to the Digispark Arduino-compatible microcontroller via USB with the node-hid library
/*
* Accept control commands via USB.
*
* Commands start with '!' and end with '.'
* Commands have three parts: action, pin, value: !AAPPVV.
*
* E.g. '!01p101.' is DigitalWrite, Pin1, value = 1
*
* Note: This is currently *very* crude. Much improvement could be made.
* I think the use of strncpy is eating a lot of memory. Refactor?
*/
#define START '!'
#define END '.'
#include <DigiUSB.h>
bool debug = false;
int index = 0;
char messageBuffer[12];
char cmd[3];
char pin[3];
char val[5];
void setup() {
pinMode(1, OUTPUT);
// Blink three times to signal ready.
for(index = 0; index < 3; index++) {
digitalWrite(1, HIGH);
delay(100);
digitalWrite(1, LOW);
delay(100);
}
DigiUSB.begin();
}
void loop() {
if(DigiUSB.available()) {
char x = DigiUSB.read();
if (x == START) index = 0; // start
else if (x == END) process(); // end
else messageBuffer[index++] = x;
}
DigiUSB.refresh();
delay(10);
}
/*
* Deal with a full message and determine function to call
*/
void process() {
index = 0;
strncpy(cmd, messageBuffer, 2);
cmd[2] = '\0';
strncpy(pin, messageBuffer + 2, 2);
pin[2] = '\0';
if (atoi(cmd) > 90) {
strncpy(val, messageBuffer + 4, 2);
val[2] = '\0';
} else {
strncpy(val, messageBuffer + 4, 3);
val[4] = '\0';
}
if (debug) {
DigiUSB.println(messageBuffer);
}
int cmdid = atoi(cmd);
DigiUSB.println(cmd);
DigiUSB.println(pin);
DigiUSB.println(val);
switch(cmdid) {
case 0: sm(pin,val); break;
case 1: dw(pin,val); break;
// case 2: dr(pin,val); break;
case 3: aw(pin,val); break;
// case 4: ar(pin,val); break;
case 99: toggleDebug(val); break;
default: break;
}
}
/*
* Toggle debug mode
*/
void toggleDebug(char *val) {
if (atoi(val) == 0) {
debug = false;
DigiUSB.println("goodbye");
} else {
debug = true;
DigiUSB.println("hello");
}
}
/*
* Set pin mode
*/
void sm(char *pin, char *val) {
if (debug) DigiUSB.println("sm");
int p = getPin(pin);
if(p == -1) { if(debug) DigiUSB.println("badpin"); return; }
if (atoi(val) == 0) {
pinMode(p, OUTPUT);
} else {
pinMode(p, INPUT);
}
}
/*
* Digital write
*/
void dw(char *pin, char *val) {
if (debug) DigiUSB.println("dw");
int p = getPin(pin);
if(p == -1) { if(debug) DigiUSB.println("badpin"); return; }
pinMode(p, OUTPUT);
if (atoi(val) == 0) {
digitalWrite(p, LOW);
} else {
digitalWrite(p, HIGH);
}
}
/*
* Digital read
*/
/*
void dr(char *pin, char *val) {
if (debug) DigiUSB.println("dr");
int p = getPin(pin);
if(p == -1) { if(debug) DigiUSB.println("badpin"); return; }
pinMode(p, INPUT);
int oraw = digitalRead(p);
char m[7];
sprintf(m, "%02d::%02d", p,oraw);
DigiUSB.println(m);
}
*/
/*
* Analog read
*/
/*
void ar(char *pin, char *val) {
if(debug) DigiUSB.println("ar");
int p = getPin(pin);
if(p == -1) { if(debug) DigiUSB.println("badpin"); return; }
pinMode(p, INPUT); // don't want to sw
int rval = analogRead(p);
char m[8];
sprintf(m, "%s::%03d", pin, rval);
DigiUSB.println(m);
}
*/
void aw(char *pin, char *val) {
if(debug) DigiUSB.println("aw");
int p = getPin(pin);
pinMode(p, OUTPUT);
if(p == -1) { if(debug) DigiUSB.println("badpin"); return; }
analogWrite(p,atoi(val));
}
int getPin(char *pin) { //Converts to P0-P5, and returns -1 on error
int ret = -1;
if(pin[0] == 'P' || pin[0] == 'p') {
switch(pin[1]) {
case '0': ret = 0; break;
case '1': ret = 1; break;
case '2': ret = 2; break;
case '3': ret = 3; break;
case '4': ret = 4; break;
case '5': ret = 5; break;
default: break;
}
} else {
ret = atoi(pin);
if(ret == 0 && (pin[0] != '0' || pin[1] != '0')) {
ret = -1;
}
}
return ret;
}
var HID = require('./build/Release/HID.node');
var device,ds,char;
var devices = HID.devices(0x16c0, 0x05df); // look for digisparks
if (devices.length > 0) {
console.log(devices);
console.log('Attaching to first entry.');
device = devices[0];
console.log('USB Path:', device.path);
ds = new HID.HID(device.path);
ds.setNonBlocking(1); // blocking is bad, mkay?
ds.write(new Buffer("!990011.")); // turn debug on
console.log('analogWrite P1 25...');
var cmd = "!03p125.";
// Buffer is an array of bytes, like write() wants.
ds.write(new Buffer(cmd));
while (1) {
var buff = new Buffer(ds.getFeatureReport(0,254));
console.log("using getFeatureReport: ", buff.toString());
if (! buff.length) break;
}
console.log('analogWrite P0 45...');
cmd = "!03p245.";
// Buffer is an array of bytes, like write() wants.
ds.write(new Buffer(cmd));
//*
ds.read(function(err, data){
if (err) {
console.log("Error! ", err);
} else {
console.log("using ds.read: ", data);
}
});
//*/
//**/ ds.read(onRead);
} else {
console.log('No Digispark found.');
}
function onRead(err, data) {
if(err) {
console.log('Err! :-(');
} else {
if (1 || data.length) {
console.log('DATA: ' + data);
}
ds.read(onRead);
}
}
@kilianc
kilianc commented Sep 14, 2013

I think the use of strncpy is eating a lot of memory. Refactor?

I agree.
Why don't you just move pointers around?

Does the DigiUsb require a \0ed string?

@kilianc
kilianc commented Sep 14, 2013

In that case why don't you change the protocol to: AA\0PP\0VV\0
Also, what happens if I want to write to pin 11 ?

This way you can use non fixed length messages.
If you don't like the \0 as tokenizer you could use something else like | and then strtok that will return pointers and replace the token with \0 for you :)

@dougalcampbell
Owner

Yes, this code is still in a crude state of hackage from @ecto's original version, because I was trying to get it to fit in the Digispark's 6K available flash. But I haven't refactored it yet to actually handle command parsing in a more sane way. For one thing, I could whittle down the command and pin parameters to a single character each. I might also be able to get the value as a single raw byte, and just put the onus on computer at the other end of the USB connection to package the data accordingly.

There might be a good case here for a tiny module on the node side to provide convenience functions for packing/unpacking the data packets.

It's just one of those things to work on in my "Copious Free Time".

@mrpeu
mrpeu commented Jan 4, 2015

Hi Dougal,
what is your status on this?

@nischelwitzer

hi dougal,

looks cool.

this would be cool solutions for the digispark.

i am now trying to run you programm with digitspark but without success.
which drivers for the digispark have you used on windows?
I have tried serveral without success. with the digiusb monitor.exe it works.

can you post the binary node-hid module?

i can compile it with gyp but can find a lot usb devices but not the digispark.

thanks,
alex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment