///
/// eForth1 Servo Demo
///
/// Select one of the demos, feed it into ef_setup(example#) 
///   
#include <Servo.h>
#include <eForth1.h>

#define DEMO demo3       /** selected, demo1, demo2, or demo3 */

/// Demo1: swing servo #3
PROGMEM const char demo1[] = 
": sv3 3 0 CALL ;\n"  // call C function #0 (see below) to control servo #3
"45 sv3 200 DELAY 135 sv3 300 DELAY 90 sv3\n"
;
/// Demo2: move all servos in sync
PROGMEM const char demo2[] = 
": sync 7 FOR DUP I 0 CALL NEXT DROP ;\n"     // sync 8 servos
": rnd CLOCK DROP ABS 180 MOD ;\n"            // randomize servo angle
": sweep rnd sync ;\n"                        // 8 servos in action
"' sweep 500 0 TMISR\n"                       // make sweep as ISR[0] at 500ms period
"1 TIMER\n"                                   // timer on
;
/// Demo3: move servo arms each with different amplitude
PROGMEM const char demo3[] =
"CREATE w 8 ALLOT\n"                                         // array[8] to keep angles
": xx ( -- ) 7 FOR I DUP 1+ 10 * SWAP w + C! NEXT ; xx\n"    // init each angle
": w@ ( n -- c w ) 90 SWAP w + C@ ;\n"                       // fetch servo angle by id
": ang= ( ph n -- ) SWAP OVER w@ ROT 1 CALL SWAP 0 CALL ;\n" // set servo angle
"VARIABLE x\n"                                               // step control
": step 7 FOR DUP I ang= NEXT DROP ;\n"                      // set all servo angles
": swing x @ DUP 1+ x ! step ;\n"                            // 1 timer tick forward
"' swing 100 0 TMISR\n"                                      // swing every 100ms as timer ISR[0]
"1 TIMER\n"                                                  // turn timer on
;

Servo sv[8];
/// servo arm angle setting ( angle servo# -- )
void servo() {
  int p = vm_pop();  ///> servo#
  int a = vm_pop();  ///> angle
  sv[p].write(a);
}
/// sinusoidal wave arm position calc ( center amp phase -- angle )
void cyclic() {
  const float PERIOD PROGMEM = 2.0 * PI / 256.0;  ///> default 256 step per cycle
  float v = sin(PERIOD * vm_pop());               ///> directional vector
  float d = vm_pop() * v;                         ///> delta = amplitude * dir_vector
  int   r = static_cast<int>(vm_pop() + d + 0.5); ///> final arm angle
  vm_push(r);
}

void setup() {
  Serial.begin(115200);
  while (!Serial);

  for (int i=0; i<8; i++) {
    sv[i].attach(4 + i);
  }

  ef_setup(DEMO);           ///> initiate eForth1

  vm_cfunc(0, servo);       ///> register servo write function
  vm_cfunc(1, cyclic);      ///> register cyclic control function
}

void loop() {
  ef_run();                 ///> invoke eForth1 VM outer interpreter
}

7
6
5
4
3
2
1
0