Author Topic: Periodically send keystroke for fixed amount of time after power on?  (Read 3536 times)

DoktorJ

  • Newbie
  • *
  • Posts: 14
Hi all... I'm no good at Arduino programming, but I backed the original DigiSpark (way back when!) and actually managed to do something useful with it.

Now I have a new application for one, but figuring out how to implement it seems to be above my comprehension level. I built a pfSense router using an Intel Atom board, and 99% of the time it works great. However, if there's been a power failure the board has a serious issue: it stops the boot process and asks if I want to enable fast boot on the next boot-up (despite the fact that I've disabled fast boot in the BIOS in the first place).

Since this is a router and not a desktop computer, I don't regularly have a keyboard or monitor hooked up to it... so I was thinking, if I could program a DigiSpark to periodically send an "N" keypress (maybe once every 5 seconds, for about 30 seconds) and leave that plugged into the router, it would circumvent that horrendous blasphemy of engineering and design that is the fast boot prompt. Seriously, the board was designed to be an embedded systems board, i.e. something that should not have to be baby-sat and have a keyboard attached to it all the time just in case there's a power failure -- it's supposed to be robust, and keep on working through such things.

What would be the easiest way to go about this -- I'm figuring the logic would be something along the lines of "at power on, start a 5 second delay cycle, and at the end of each delay, send the "N" keypress and increment a counter... when the counter reaches 6, stop the loop and go to sleep."

KASA

  • Newbie
  • *
  • Posts: 34
Hi!
I wrote you this program:
Code: [Select]
#include "DigiKeyboard.h"

boolean doLoop = true;

void setup() {   
  pinMode(0, OUTPUT); //LED on Model B
  pinMode(1, OUTPUT); //LED on Model A  or Pro           

}



void loop() {

  if(doLoop == true){
    DigiKeyboard.delay(5000);   // <-- use DigiKeyboard.delay here (documentation says thgis tells the computer the "Keyboard" is still connected)
    //                  /\
    //ENTER DELAY AFTER THE 5 SECOND BOOT DELAY HERE

    for(int i=0; i<5; i++) {
      //           /\
      //  How many times do you want to enter "N" ?
      DigiKeyboard.update();
      DigiKeyboard.sendKeyStroke(KEY_N);
      DigiKeyboard.delay(5000);   // <-- use DigiKeyboard.delay here (documentation says thgis tells the computer the "Keyboard" is still connected)
      //                             /\
      //        DELAY BETWEEN KEYSTROKES  (ms)
    }
  }

// WARNING: ALL DELAYS ARE IN MILLISECONDS -> 1000ms = 1s

  else{
    digitalWrite(0, HIGH);   // turn the LED on (HIGH is the voltage level)
    digitalWrite(1, HIGH);
    DigiKeyboarddelay(10000);
  }

  doLoop = false;
 
}


USE DigiKeyboard.delay( DELAY TIME ); PLEASE! If you don't do this windows has problems and doesn't recognize the Keyboard.

the "if" loop in the "loop" checks if the boolean variable (boolean means 1 or 0, true or false) called "doLoop" is true.
At the start of the program it is because it is set to true at the start.

The "for" loop is basically what you had in mind. The counter is the variable "i". it starts at 0 (as said in the "for" loop line, the loop gets repeated as long as the second condition is met at the start, which is "i" has to be smaller than 5 (i<5). The third field is what should be done at the end of each cycle which is i++ which is short for i=i+1 in C (so basically increment i).

After the for loop doLoop is set to false.
Now it goes back to the beginning of "loop".
Because "doLoop" got set to false it doesn't run the "if" loop which contains the  "for" loop but instead goes to the "else" loop which just contains a 10000 ms delay (10 seconds).
Because doLoop is never touched again the DigiSpark is now just doing delay over and over because I don't know any way to set it to a real Idle state, but if anyone knows a way answer here.

Oh I just remembered you can just place the whole code in the Setup loop and it will only run once. But it should be ok like it is now.

It works for me. If it doesn't for you just tell me.
BTW you should really learn C/C++ (the Arduino language) , it isn't really hard.

Bye
KASA
« Last Edit: May 03, 2017, 11:34:27 am by KASA »

DoktorJ

  • Newbie
  • *
  • Posts: 14
Thanks for sharing this! Sadly I can't seem to find my Digispark -- I have a vague idea where it is, but that is currently in a box buried under other boxes as part of our move, and I haven't had time to dig it out.

Guess I just have to order another one!

One more question: The USB ports on my Atom board seem to have power even in "standby" state. Is there anything either inherent to the Digispark or the DigiKeyboard library, or that I can add, to ensure that this doesn't start up until the device is officially recognized as a keyboard?

I don't want it to wake up after a power outage and start sending off its keystrokes before the router itself has even fired up!

If not, I can probably just bump the initial delay more, as the Atom board is set to power on after power loss (at least they got that much right about an embedded system)... but if I can get it to wait more gracefully to be told "yes, you're a keyboard" before trying to be a keyboard, that would be nice.

I do want to learn more about Arduino programming, I have many project ideas, but sadly my time is perpetually in short supply, so I haven't been able to study it much (and don't yet have the time to do the projects either). Hoping that will change soon though, got some stuff in the works towards that end...

KASA

  • Newbie
  • *
  • Posts: 34
He:
https://digistump.com/board/index.php/topic,2389.0.html
says this isnt possible but I may have found a way!

Here are two important functions:
https://digistump.com/wiki/digispark/tricks
I would try to check if the clock was calibrated at bootup, which means it is connected, and if it isnt reboot.
Do that until it indicates the clock was calibrated at bootup which means the usb connection is active.
I dont have a way to test if this works but I may write the code later.

The only problem is that your Digispark may be set to have the clock at 16,5 mhz even if not connected to usb which would make this way impossible.

When you get your new Digispark I will be finished  ;D

EDIT: Try this if you find your digispark:
Code: [Select]
#include "DigiKeyboard.h"
#include <avr/boot.h>

boolean doLoop = true;

void setup() {   
  pinMode(0, OUTPUT); //LED on Model B
  pinMode(1, OUTPUT); //LED on Model A  or Pro           

}



void loop() {
 
  DigiKeyboard.delay(500); //some delay, I dont know if this is needed but maybe the Digispark needs some time to calibrate the clock

  if(is_clock_calibrated() == 0){
    reboot();
  }

  else{

    if(doLoop == true){
      digitalWrite(0, HIGH);   // turn the LED on (HIGH is the voltage level)
      digitalWrite(1, HIGH);
     
      DigiKeyboard.delay(5000);   // <-- use DigiKeyboard.delay here (documentation says thgis tells the computer the "Keyboard" is still connected)
      //                  /\
      //ENTER DELAY AFTER THE 5 SECOND BOOT DELAY HERE

      for(int i=0; i<5; i++) {
        //           /\
        //  How many times do you want to enter "N" ?
        DigiKeyboard.update();
        DigiKeyboard.sendKeyStroke(KEY_N);
        DigiKeyboard.delay(5000);   // <-- use DigiKeyboard.delay here (documentation says this tells the computer the "Keyboard" is still connected)
        //                             /\
        //        DELAY BETWEEN KEYSTROKES  (ms)
      }
    }

    // WARNING: ALL DELAYS ARE IN MILLISECONDS -> 1000ms = 1s

    else{
      digitalWrite(0, LOW);   // turn the LED on (HIGH is the voltage level)
      digitalWrite(1, LOW);
      DigiKeyboard.delay(10000);
    }

    doLoop = false;
  }
 
}





byte read_factory_calibration(void) {
  byte SIGRD = 5; // for some reason this isn't defined...
  byte value = boot_signature_byte_get(1);
  return value;
}
 
boolean is_clock_calibrated(void) {
  return read_factory_calibration() != OSCCAL;
}


void reboot(void) {
  noInterrupts(); // disable interrupts which could mess with changing prescaler
  CLKPR = 0b10000000; // enable prescaler speed change
  CLKPR = 0; // set prescaler to default (16mhz) mode required by bootloader
  void (*ptrToFunction)(); // allocate a function pointer
  ptrToFunction = 0x0000; // set function pointer to bootloader reset vector
  (*ptrToFunction)(); // jump to reset, which bounces in to bootloader
}

The LED on the Digispark schould turn on when the Atom Board connects with it, max 5s later (if the digispark reboots because it gets no connection and 1ms later the Atom Board turns on, the Bootloader waits 5s to start the program so the delay should be from 0-5s.)

EDIT2: Sadly this doesnt work for me. I think they changed the default clock rate to 16.5mhz so the is_clock_calibrated will return true even if it isnt connected to usb  :'(
Maybe you can change that back but I dont know how.



Maaaaaaybeeee you could connect an USB data pin to any other Input pin and check if there is any data coming in but that would need some diving into the usb documentation, I may look into it later but for now, I would just try how long the boot time of the Atom is and adjust the delay or let the digispark send "n" as long as it is powered (if the atom board is ok with receiving "n" while it is running and that doesnt change some settings)

EDIT3: Connecting any USB Pin to any other Input pin prevents the PC from recognising the Digispark as a USB device...

I don't see a simple solution for this but maybe you'll find something, I'll keep looking too.
Let me know if you find a solution!

Another Idea! Does your board have a PS2 connector? Maybe you could connect the power pin of these to an IO pin on the Digispark, the PS2 voltage should be off if the board is off.


Ok I think I'm stupid... you want it to recognize the keyboard recognition and not just bootup, right? I don't think that's possible. If it was possible, the Rubber Ducky would certainly have it and it doesn't so I see no way to do this... I would just try to time the delay right...

KASA
« Last Edit: May 14, 2017, 03:30:39 pm by KASA »

DoktorJ

  • Newbie
  • *
  • Posts: 14
Hmmmm, would it be possible to make it sniff the USB pin, and once it detects data, "disconnect" and change into keyboard mode? Or does the
Code: [Select]
#include "DigiKeyboard.h" bit automatically put it in keyboard mode?

KASA

  • Newbie
  • *
  • Posts: 34
do you want to sniff the USB pin with software or with another Io pin? Another IO pin doesn't work, that prevents the Digispark from getting recognized by windows. Do you know a way to sniff it by software? I would just keep it simple and adjust delay and maybe how many times the Digispark prints "n".