//////////////     polytask.h      ////////////
//--------- some elements of 'basic'---------//
#define ext_up_to 1
#define ext_dn_to -1
#define For(var,from,dir,to)\
   for(var=from;var!=to+ext_##dir; var+=ext_##dir)
#define Func     
#define end_func 
#define Proc     
#define end_proc 
#define end_(rem)
#define Loop while(1)
#define Next 
// poly_var(5,int x,y;) use x,y in poly __
#define poly_var(mem,...) /*- - - - - - */\
    const int max_poly=mem-1;             \
    typedef struct                        \
         {void *PC; uint16_t cs; int para;\
            __VA_ARGS__;}p_var;           \
    static p_var p_A[mem];                \
    static uint8_t  p_cur;                \
    static uint8_t  p_tmp;                \
    static bool init_done
// poly_intit{ autostarts} ____________________
#define poly_init /*- - - - - - - - - - - -  */\
    for (;!init_done;init_done=!init_done)
/* ________ variable 'frame' */
#define sP_(s,var) p_A[s]. var
#define P_(var) sP_(p_cur,var)
// poly_schedule[polys} _______________
#define poly_schedule                  \
  For(p_cur,0,up_to,max_poly)          \
  {  if (P_(PC)!=NULL) goto *(P_(PC)); \
	next_poly:;                     } \
 if(!init_done)
// polyPoly(0,..) 0:free;p_tmp=id _______
#define startPoly(slot,name,_para)       \
 if(slot<=max_poly)                      \
 { if(slot!=0){p_tmp=slot;}              \
   else For(p_tmp,max_poly,dn_to,0)      \
           if(sP_(p_tmp,PC)==NULL) break;\
   if(p_tmp>=0)                          \
   {  sP_(p_tmp,PC)  =p_adr(name);       \
      sP_(p_tmp,para)=_para;       }  }

// stopPoly(3) _________________________
#define stopPoly(slot) sP_(slot,PC)=NULL
// stopPolys(-1) __________________
#define stopPolys(mod )            \
   For(p_tmp,0,up_to,max_poly mod) \
      sP_(p_tmp,PC)=NULL
/* _________ poly 'frame' ______________ */
#define POLY(name) p_conc(name): while(1)
#define poly_end P_(PC)=NULL;goto next_poly;
#define poly_rep p_yield;
#define poly_to(name)P_(PC)=p_adr(name);goto next_poly;
/* ________  time sharing ___*/
// p_yield save PC; return __
#define p_yield /* - - - - */\
    {P_(PC)=p_adr(__LINE__); \
     goto next_poly;         \
     p_label(__LINE__);     }   
#define P_Wait(cond) while(not(cond)) p_yield;
#define P_Wait_cs(_cs) P_(cs)=centis+_cs; P_Wait(centis==P_(cs))
/* __________ name'helper'______*/ 
#define p_conc(name) poly_ ##name 
#define p_label(name) p_conc(name):
#define p_adr(name)  &&p_conc(name)
//maybe 'simplified' language 
#define P_For(var,from,dir,to) For(P_(var),from,dir,to)
#define P_Until(cond) p_yield;if(cond) break;
#define P_Switch_to(name) {poly_to(name)}
//////////////////////////////////////////////
//////////////////////////////////////////////

#define ana1 A1
//---------- some led ----------//
//Project by MOHD SOHAIL// (Board)
// 15+18 lost in Kutupalong 2021(Aug)
#define pinsCount 12                      
int pins_a[] = {2,3,4,5,6,7,8,9,10,11,12,13};    
uint8_t pins_cur[pinsCount];
uint8_t pins_des[pinsCount];

Proc void w_pin(uint8_t num,uint8_t val,int8_t sw){
   switch(sw){
   case -1: pins_des[num-1]=000; pins_cur[num-1]=val;break;
   case  0: pins_des[num-1]=val;                     break;
   case  1: pins_des[num-1]=val; pins_cur[num-1]=val;break;
   }
end_proc;}
Func void pin_update(){int i;
   For(i,0,up_to,pinsCount-1)
   {  if(pins_cur[i]!=pins_des[i])
        if(pins_cur[i]>pins_des[i]) pins_cur[i]--;
        else                        pins_cur[i]++;
     if(pins_cur[i]==0)
          digitalWrite(pins_a[i], LOW);
     else digitalWrite(pins_a[i], HIGH);
//     analogWrite(pins_a[i],pins_cur[i]*16);   
   }
end_func;}
// macro test:num:poly_var 
#define P_test_pin(num,duration) \
   {w_pin(P_(num),2,-1); P_Wait_cs(duration);   };
               
//---------- some buttons ----------//
#define btn1 A2
#define btn2 A0
enum { btn_press=1*256,btn_repeat=4*256,
       btn_short=2*256,btn_long  =3*256};
uint8_t btn_scan; 
Func int button(){
  static uint8_t time;
  uint8_t scan;    
  int     tmp_return;
  scan=1*(digitalRead(btn1)==LOW)+
       2*(digitalRead(btn2)==LOW);
  if(scan!=btn_scan)
  { if(time<20) tmp_return=btn_scan+btn_short;
    else        tmp_return=btn_scan+btn_long;
    btn_scan=scan;    time=0;                }
  else switch(time++) {
       case  1:tmp_return=scan + btn_press;break;
       case 30:tmp_return=scan + btn_repeat;break;
       case 50:time=29;
       default:tmp_return=0;  }
  return tmp_return;
end_(button);}


 /////////////////////////////////////
Proc void do_Poly(uint16_t centis) {
  poly_var(8,int A,B,C);  
  poly_init{
     startPoly(0,btn,NULL);
     startPoly(0,blink,25);
     startPoly(1,on,20);
  /*end init/autostart*/}
  poly_schedule{
// ---
  POLY(blink){
  	 w_pin(12,3,-1); 
      P_Wait_cs(P_(para));
  poly_rep;}
// ---
  POLY(on){
  	 P_For(A,1,up_to,pinsCount-1){
           w_pin(P_(A),55,-1); 
           P_Wait_cs(3);
      Next;}
  poly_to(p_max);}
// ---
  POLY(p_max){
  	 P_For(A,1,up_to,pinsCount-1) 
        P_test_pin(A,P_(para)); 
  poly_rep;}
// ---
  POLY(p_1_8){
  	 P_For(A,1,up_to,8) P_test_pin(A,P_(para)); 
  poly_to(p_7_2);}
// ---
  POLY(p_7_2){
      P_For(A,7,dn_to,2) P_test_pin(A,P_(para));
  poly_to(p_1_8);}
// ---
  POLY(prg_1){  poly_rep;}
// ---
  POLY(prg_2){  poly_end;}
//--- 
  POLY(flash){// poly_prg_1
   P_For(A,1,up_to,5) w_pin(P_(A),5,-1); 
   P_Wait_cs(5);                           
   P_For(A,5,up_to,9) w_pin(P_(A),5,-1); 
  poly_end;}
//---  
  POLY(btn){
    switch (button()){
    case 1+btn_press :Serial.println("1-Press stop 1");
         stopPoly(1);break;
    case 1+btn_repeat:Serial.println("1-Repeat flash 1 ");
         startPoly(1,flash,40);break;
    case 1+btn_short :Serial.println("1-short kn slow");
         startPoly(1,p_1_8,10);break;
    case 1+btn_long  :Serial.println("1-long  kn fast");
         startPoly(1,p_7_2,5);break;
    case 2+btn_press :Serial.println("2-Press ");
         break;
    case 2+btn_repeat:Serial.println("2-Repeat ");
         break;
    case 2+btn_short :Serial.println("2-short add max ");
         startPoly(0,p_max,5);break;
    case 2+btn_long  :Serial.println("2-long stop polys ");
         stopPolys(-2);break;
    end_(switch)} P_Wait_cs(1);
  poly_rep;}
 /*end of polys*/}
  int ana_val;static int ana_val_;  
  ana_val = analogRead(ana1)/16+1;
  if(ana_val!=ana_val_)
  {  sP_(1,para)=ana_val;
     Serial.print("slide:"); Serial.println(ana_val); 
     ana_val_=ana_val;}
  
end_(do_poly);} 

Proc void setup() {int i;
  for (i=0; i<pinsCount; i=i+1) pinMode(pins_a[i], OUTPUT);      
  pinMode(btn1, INPUT_PULLUP); pinMode(btn2, INPUT_PULLUP);
  pinMode(ana1, INPUT);
  Serial.begin(38400);
end_proc;}

Func void loop() {
  static long millis_upd;
  if(millis()>=millis_upd)
  {  millis_upd=millis()+20; pin_update();}
 
  uint16_t centis;//intended use:'slow' poly
  static long millis_cent;
  if(millis()>=millis_cent)
  {  millis_cent=millis()+10; centis++;}
  do_Poly(centis);
end_proc;}