MicroLog.MyPower.CZ

… designed for freedom of automation.

Uživatelské nástroje

Nástroje pro tento web


source

Toto je starší verze dokumentu!


Microlog2 Source

Pozor! Tato verze je pracovní a není plně funkční.

microlog2.ino
// ---[ INFO ]----------------------------------------
 
// MyPower.CZ Microlog
// Version 2.0
// Date: 05/2013
 
// created by MyPower.CZ
// Licence: free for non-commercial use
 
// ---[ VERSION ]-------------------------------------
 
#define MPWMicroLogVersion     "2.01"
 
// ---[ INCLUDE ]-------------------------------------
 
#include <SPI.h>
#include <EEPROM.h>
#include <Ethernet.h>
#include <utility/w5100.h>
 
// ---[ BUILT-IN CONFIG ]-----------------------------
 
int sendInterval = 30; // sec default: 120
int sendRetry    = 30; // sec default: 30
byte maxErrors   = 3;  // default: 3
 
byte NETmac[]    = { 0xF6, 0x88, 0x00, 0x00, 0x00, 0x01 };
 
// ---[ MODS ]----------------------------------------
 
// mod MyPowerLog
#define modMyPowerLog    1         // 1=on 0=off
#define modMyPowerHost   "log.mypower.dev"
#define modMyPowerFVEID  "mojefve"
 
// mod StausLed
#define modStatusLed     1         // 1=on 0=off
#define modStatusLedPin  40        // default: 40
 
// mod SerialLog
#define modSerialLog     1         // 1=on 0=off
#define modSerialForce   1         
 
// mod WebServer
#define modWebServer     1         // 1=on 0=off
#define modWebServerPort 80        // default: 80
 
// mod Display
#define modDisplay       1         // 1=on 0=off
#define modDisplayType   1602      // typ displaye
 
// ---------------------------------------------------
 
byte lxLed=0;
byte lxTime=0;
long lxSeconds=0;
long lxSendIndex=0;
byte lxHttpOk=0;
byte lxHttpErrors=0;
 
// ---------------------------------------------------
 
#define dLCDKeyPad1602   1602
 
// ---------------------------------------------------
 
//  TTT GG E   
// 0000 0000
 
#define xpinOPTdefault   B00000000
#define xpinOPTenabled   B00000001
 
#define xpinOPTtypeMask  B01110000
 
#define xpinOPTsample    B00000000
#define xpinOPTavg       B00010000
#define xpinOPTeffective B00100000
#define xpinOPTmin       B00110000
#define xpinOPTmax       B01000000
#define xpinOPTres1      B01010000
#define xpinOPTres2      B01100000
#define xpinOPTdefault   B01110000
 
#define xpinOPTgroupMask B00001100
 
#define xpinOPTsampleG0  B00000000
#define xpinOPTsampleG1  B00000100
#define xpinOPTsampleG2  B00001000
#define xpinOPTsampleG3  B00001100
 
// ----------------------------------------------------
 
// EEPROM
 
//      0 - 40  PIN0 CONF
//     41 - 81  PIN1 CONF
//    82 - 122  PIN2 CONF
//   123 - 163  PIN3 CONF
//   164 - 204  PIN4 CONF
//   205 - 245  PIN5 CONF
//   246 - 286  PIN6 CONF
//   287 - 327  PIN7 CONF
//   328 - 368  PIN8 CONF
//   369 - 409  PIN9 CONF
//   410 - 450  PIN10 CONF
//   451 - 491  PIN11 CONF
//   492 - 532  PIN12 CONF
//   533 - 573  PIN13 CONF
//   574 - 614  PIN14 CONF
//   615 - 656  PIN15 CONF
//   657 - 683  DeviceConf
//  684 - 2047  Display program
// 2048 - 2057  MyPower Serial Number
 
struct tPinConf {
char xname[21];char xunit[6];byte xopt;
signed long xmin,xmax;int xmin10000,xmax10000;
byte chsum;
};
 
struct tMpwAccess {
  byte sn[10];
  unsigned long mpwtime;
  unsigned long mpwtimeAtMS;
  };
 
#define xdcOptBuiltIn      0x00;
#define xdcOptActive       0x01;
 
struct tSampledPin {
  int pin; byte smpHi8[128]; byte smpLo2[32];
  unsigned long smpSqr,smpAvg; int smpMin, smpMax, smpCount;
};
 
struct tPinValue { 
  int smpVal,smpSqr,smpAvg,smpMin,smpMax;
};
 
struct tSamplerStruct { 
tPinValue tPinValues[NUM_ANALOG_INPUTS];
tSampledPin tPinSamples[4];
byte tPinTimes[128];
unsigned long tPinMicros;
};
 
tSamplerStruct xSamplerStruct;
 
struct tDeviceConf {
char xfveid[21];
int xsendInterval;
int xsendRetry;
byte xmaxErrors;
byte xdcOpt;
byte chsum;
};
 
struct int64 { word hh,hl,lh,ll; boolean msf; };
 
// ---------------------------------------------------
 
#if modWebServer == 1
EthernetServer server(modWebServerPort);
#endif
 
#if (modDisplay == 1)
byte lcdCurrentPage=0xFF;
byte lcdMaxPage=0;
 
#if (modDisplayType == dLCDKeyPad1602)
struct tDispStats { int xvarscount; int xvarram; };
char _lcdlbuf[17];
char * _lcdweblbuf0=NULL;
char * _lcdweblbuf1=NULL;
tDispStats * _lcdwebdispstats=NULL;
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 14, 5, 6, 7);
void lcdPrintRight(char * str) { int x=16-strlen(str); lcdPrintAt(str,(x<0?0:x)); }
void lcdPrintCenter(char * str) { int x=8-(strlen(str)/2); lcdPrintAt(str,(x<0?0:x)); }
void lcdPrintLeft(char * str) { lcdPrintAt(str,0); }
void lcdPrintAt(char * str,int x) { 
  int ix=strlen(str);for (int i=0;((i+x<sizeof(_lcdlbuf)-1) && (i<ix));i++) if (x>=0) _lcdlbuf[i+x]=str[i]; }
void lcdClear() { lcd.clear(); }
void lcdClearLine() { int i; for (i=0;i<sizeof(_lcdlbuf)-1;i++) _lcdlbuf[i]=32; _lcdlbuf[i]=0; }
void lcdPrintLine(int y) { 
  if ((_lcdweblbuf0!=NULL) && (_lcdweblbuf1!=NULL))
    { char * p=_lcdweblbuf0; if (y==1) p=_lcdweblbuf1;strcpy(p,_lcdlbuf); }
  else { lcd.setCursor(0,y); lcd.print(_lcdlbuf); } }
void lcdInit() { lcd.begin(16, 2); lcdClear(); }
#endif
 
#endif
 
 
// -- [SETUP] ----------------------------------------------
 
void setup()
{
#if modStatusLed == 1
pinMode(modStatusLedPin, OUTPUT); SetLiveLed(HIGH);
#endif
 
#if ((modSerialLog == 1) || (modSerialForce == 1))
Serial.begin(9600);
#endif
 
#if ((modSerialLog == 1) || (modDisplay == 1))
char sn1[]="MyPower.CZ";
char sn2[]="MicroLOG";
 
#if (modSerialLog == 1)
XLog(sn1);XLog(sn2);
XLog(MPWMicroLogVersion);
#if (modMyPowerLog == 1)
XLog("+mpwlog");
#endif
#if (modDisplay == 1)
XLog("+disp");
#endif
XLog("DHCP?");
#endif
 
#if (modDisplay == 1)
lcdInit();lcdCurrentPage=0xFF;
lcdClearLine();lcdPrintCenter(sn1);lcdPrintLine(0);
lcdClearLine();lcdPrintLeft(sn2);lcdPrintRight(MPWMicroLogVersion);lcdPrintLine(1);
#endif
 
#endif
 
pinMode(10, OUTPUT);digitalWrite(10,HIGH);
int xret=Ethernet.begin(NETmac);
W5100.setRetransmissionTime(0x07FF);
W5100.setRetransmissionCount(2); 
if (xret == 0) {
#if modSerialLog == 1
  XLog("No dhcp.");
#endif
  FlashError(4);
  }
else
  {
#if modSerialLog == 1
  char xtext[100];
  char cf[]="%d.%d.%d.%d";
  IPAddress xaddr;
  XLog("IP,MASK,GW,DNS");
  xaddr=Ethernet.localIP();
  for (byte i=0;i<4;i++) {
    if (i==1) xaddr=Ethernet.subnetMask();else
    if (i==2) xaddr=Ethernet.gatewayIP();else
    if (i==3) xaddr=Ethernet.dnsServerIP();   
    sprintf(xtext,cf,xaddr[0],xaddr[1],xaddr[2],xaddr[3]);
    XLog(xtext);
    }
#endif
  }
 
#if modWebServer == 1
server.begin();
#if modSerialLog == 1
char c[30]="";sprintf(c,"+www@%d",modWebServerPort);XLog(c);
#endif
#endif
#if modSerialLog == 1
XLog("Done.");
#endif
}
 
 
 
// -- [LOOP] ----------------------------------------------
 
void loop()
{
FlashLiveLed();
CalculateSeconds();
#if modMyPowerLog == 1
SendDataToMyPower();
#endif
#if modWebServer == 1
WebServer();
#endif
#if (modDisplay == 1)
#if (modDisplayType == dLCDKeyPad1602)
DisplayDetectButton();
#endif
#endif
SamplerRun();
}
 
void softReset() { asm volatile ("  jmp 0"); } 
 
#if modSerialLog == 1
void XLog(char * xmsg) { Serial.println(xmsg); }
void XLogRam() { Serial.print("> RAM:"); Serial.println(freeRam()); }
void XLog2(char * xmsg,char * xpre) { Serial.print(xpre);Serial.println(xmsg); }
#endif
 
#if (modDisplay == 1)
void CalcDisplayConfEpromSpace(int * xa,int * la) {
* xa=(sizeof(tPinConf)*NUM_ANALOG_INPUTS)+sizeof(tDeviceConf);
* la=2047; }
#endif
 
 
void SetLiveLed(byte xs) { 
#if modStatusLed==1
digitalWrite(modStatusLedPin,xs);
#endif
}
 
void FlashLiveLed() {
unsigned long i=((millis()/100)%10);
byte qlxLed=( ((i==1)) || ((lxHttpOk==2) && ( (i==3) || (i==5) )) )?HIGH:LOW;
if (qlxLed!=lxLed) { SetLiveLed(qlxLed); lxLed=qlxLed; }
}
 
void CalculateSeconds() {
byte smx=0x7F; int qlxTime=((millis()/1000)&smx);
if (qlxTime!=lxTime) { OneSecondActions();
  lxSeconds+=(lxTime>qlxTime)?(qlxTime+smx+1-lxTime):(qlxTime-lxTime); lxTime=qlxTime; }
}
 
void OneSecondActions() {
#if (modDisplay == 1)
DrawDisplayPage();
#endif
}
 
#if modMyPowerLog==1
void SendDataToMyPower()
{
char xtext[200]; 
int xsi=sendInterval;
int xsiorig=xsi;
int xsr=sendRetry;
if (lxHttpOk==2) xsi=xsr;
if (xsi<30) xsi=30;
long qlxSendIndex=lxSeconds;
if ((lxSendIndex+xsi<=qlxSendIndex) || (lxHttpOk==0))
  {
  lxHttpOk=2;
  lxSendIndex=lxSeconds;
  EthernetClient client;  
  SetLiveLed(HIGH);
#if modSerialLog == 1
  XLogRam();XLog("> Connecting");
#endif
  if ( (client.connect(modMyPowerHost, 80)) && (client.connected()) )
    {
#if modSerialLog == 1
    XLog("> Connected");
#endif
    sprintf(xtext,"GET / HTTP/1.0\r\nHost: %s\r\nUser-Agent: MPWmicrolog/%s\r\nCookie: fveid=%s; ",
      modMyPowerHost,MPWMicroLogVersion,modMyPowerFVEID);
    client.write((byte*)xtext,strlen(xtext));  
    strcpy(xtext,"AIN=");
    boolean xf=false;
    char p[10];
    for (int xpin=0;xpin<NUM_ANALOG_INPUTS;xpin++) {
      if (xf) strcat(xtext,"."); else xf=true;
      sprintf(p,"%d",SamplerAnalogRead(xpin));
      strcat(xtext,p);
      }
    client.write((byte*)xtext,strlen(xtext));   
 
    strcpy(xtext,"; ");
    client.write((byte*)xtext,strlen(xtext));
 
    for (int xp=0;xp<NUM_ANALOG_INPUTS;xp++)
      {
 
      tPinValue * qPinValue;
      qPinValue=&xSamplerStruct.tPinValues[xp];
      sprintf(xtext,"A%d=V:%d,S:%d,A:%d,M:%d,X:%d,C:",xp,
        qPinValue->smpVal,
        qPinValue->smpSqr,
        qPinValue->smpAvg,
        qPinValue->smpMin,
        qPinValue->smpMax);
      client.write((byte*)xtext,strlen(xtext));
 
      tPinConf pconf;            
      boolean isvalid=ReadPinConf(&pconf,xp);            
      if (!isvalid)
        strcat(xtext,"-");
      else
        { 
        sprintf(xtext,"%X/%ld.%d/%ld.%d/",pconf.xopt,pconf.xmin,
          pconf.xmin10000,pconf.xmax,pconf.xmax10000);
        client.write((byte*)xtext,strlen(xtext));
        xtext[0]=0;
        char xf[]="%02X";
        char xh[3];
        byte * p;
        p=(byte*)pconf.xname;
        for (int i=0;i<strlen(pconf.xname);i++) {
          sprintf(xh,xf,p[i]); strcat(xtext,xh); }
        client.write((byte*)xtext,strlen(xtext));
        strcpy(xtext,"/");
        p=(byte*)pconf.xunit;
        for (int i=0;i<strlen(pconf.xunit);i++) {
          sprintf(xh,xf,p[i]); strcat(xtext,xh); }
        }              
      strcat(xtext,"; ");
      client.write((byte*)xtext,strlen(xtext));
      }
 
    strcpy(xtext,"\r\n\r\n");
    client.write((byte*)xtext,strlen(xtext));
 
    int lbufpos=0;
    boolean ishead=true;
    xtext[0]=0;
    unsigned long xmstart=millis();
    while (client.connected())
      {
      if (millis()-xmstart>3000) { break; }
      if (client.available()) 
        {
        byte qbuf[200];
        int qlen=client.readBytes((char*)qbuf,sizeof(qbuf)-2);
        for (int i=0;i<qlen;i++) {
          char c = qbuf[i];
          if (c=='\n') {
            if (xtext[0]=='\r') ishead=false; else
            if (!ishead) ParseHTTPResult(xtext);
            lbufpos=0;
            xtext[0]=0;
            }
          else {
            if (lbufpos<sizeof(xtext)-2) {
              xtext[lbufpos]=c; lbufpos++; xtext[lbufpos]=0;
              }
            }
          }
        }
      }
    if (lbufpos>0) ParseHTTPResult(xtext);
    client.stop();
    }
  if (lxHttpOk==1) 
    {
#if modSerialLog == 1
    XLog("> OK");
    sprintf(xtext,"> Waiting (%d seconds) ...",xsiorig);
    XLog(xtext);
#endif
    lxHttpErrors=0;
    }
  else 
    {
    lxHttpErrors++;
#if modSerialLog == 1
    sprintf(xtext,"> ERR (%d/%d)",lxHttpErrors,maxErrors);
    XLog(xtext);
#endif
    if (lxHttpErrors>=maxErrors) FlashError(3);
#if modSerialLog == 1
    else
    sprintf(xtext,"> Retry @ %d seconds ...",xsr);
    XLog(xtext);
#endif
    }
  SetLiveLed(LOW);
  }
}
 
void ParseHTTPResult(char * xtext) { 
if (strcmp(xtext,"result:OK")==0) lxHttpOk=1;
#if modSerialLog == 1
XLog2(xtext,"# ");
#endif
}
#endif
 
void FlashError(byte xcount)
{
#if modSerialLog == 1
char xtext[50];
sprintf(xtext,"Error %d.",xcount);
XLog(xtext);
XLog("Flashing err (10x) & restarting.");
#endif
xcount*=2;
for (int i=0;i<10;i++) {
  byte x=0;
  for (int i=0;i<xcount;i++) {
    SetLiveLed((!((x++)&1))?HIGH:LOW);
    delay(250);
    }
  delay(1000);
  }
#if modSerialLog == 1
XLog("Reset");
XLog("---");
#endif
delay(1000);
softReset();
}
 
int freeRam() {
extern unsigned int __heap_start;
extern void *__brkval;
int free_memory; int stack_here;
if (__brkval == 0) free_memory = (int) &stack_here - (int) &__heap_start;
else free_memory = (int) &stack_here - (int) __brkval; 
return (free_memory);
}
 
 
byte calcPchsum(byte xpin, struct tPinConf * pconf) {
byte*xconf=(byte*)pconf; byte xqs=pconf->chsum;
pconf->chsum=0; byte chs=0; for (int i=0;i<sizeof(tPinConf);i++) chs+=(xpin+3)+xconf[i]+i;
pconf->chsum=xqs; return chs&0xFF; }
 
boolean ReadPinConf(struct tPinConf * pconf,int xpin)
{
boolean xret=false;
if (xpin<NUM_ANALOG_INPUTS)
  {
  byte * pcx=(byte*)pconf;
  int sp=sizeof(tPinConf);
//  int xs=(xpin*sp);
  int xs=GetEpromPinAddr(xpin);
  for (int ax=0;ax<sp;ax++) pcx[ax]=EEPROM.read(ax+xs);
  xret=(calcPchsum(xpin, pconf)==pconf->chsum);
  }
return xret;
}
 
int GetEpromPinAddr(int xpin)
{
boolean xret=-1;
if (xpin<NUM_ANALOG_INPUTS)
  xret=(xpin*sizeof(tPinConf));
return xret;
}
 
 
// -- [WEB SERVER] ----------------------------------------------
 
 
#if modWebServer == 1
 
#define xWEBhome   0x00
#define xWEBcfgp   0x01
#define xWEBcfg    0x02
#define xWEBmpw    0x03
#define xWEBpins   0x04
 
#define xCFGnone   0x00
#define xCFGk      0x10
#define xCFGv      0x20
#define xCFGs      0x30
 
#define xACTnone   0x00
#define xACThw     0x01
#define xACTas     0x02
#define xACTdp     0x03
#define xACTdd     0x04
#define xACTdb     0x05
#define xACTsp     0x06
 
#define xACTwas    0x0E
#define xACTwdp    0x0F
 
#define xKEYnone        0x00
#define xKEYcmd         0x10
#define xKEYpin         0x20
#define xKEYDispButt    0x30
 
#define xPinOptNone     0x00
#define xPinOptEnabled  0x01
#define xPinOptName     0x02
#define xPinOptMin      0x03
#define xPinOptMax      0x04
#define xPinOptUnit     0x05
#define xPinOptType     0x06
#define xPinOptGroup    0x07
#define xPinCmdWrite    0xF0
 
void WebServer_pf(char * xstr,signed long * xsl,int * xsl10000) {
int im; *xsl=0;*xsl10000=0; char * p=xstr; char * p10k=p;
for (int i=0;i<strlen(xstr);i++) if (p10k[0]=='.') { p10k[0]=0;p10k++;break; } else p10k++;
boolean hm=(p[0]=='-'); if (hm) { p++; } im=strlen(p);
for (int i=0;i<im;i++) { *xsl*=10; if ((p[i]>='0') && (p[i]<='9')) *xsl+=(p[i]-'0'); }
im=strlen(p10k);
for (int i=0;i<4;i++) { *xsl10000*=10; if ((i<im) && ((p10k[i]>='0') && (p10k[i]<='9'))) 
  *xsl10000+=(p10k[i]-'0'); }
if (hm) *xsl=0-*xsl;
}
 
void WebServer_wp(byte xpin, struct tPinConf * pconf) {
if (xpin<NUM_ANALOG_INPUTS) {
  byte*xconf=(byte*)pconf; pconf->chsum=calcPchsum(xpin,pconf);
//  int ax=xpin*sizeof(tPinConf);
  int ax=GetEpromPinAddr(xpin);
  for (int ii=0;ii<sizeof(tPinConf);ii++)
    if (EEPROM.read(ax+ii) != xconf[ii])
      EEPROM.write(ax+ii,xconf[ii]);
  }
}
 
 
byte WebServer_pb(char * xstr) {
byte cb=0; for (int i=0;i<strlen(xstr);i++) { cb*=10; char c=xstr[i];
  if ((c>='0') && (c<='9')) cb+=c-'0'; }
return cb;
}
 
word WebServer_c(char * lbuf,char c,word xmode, byte * datastruct, unsigned long * xparam) {
byte qmode=xmode&0x0F; byte qsubmode=xmode&0xF0; byte qsaction=(xmode>>8)&0x0F; byte wkey=(xmode>>8)&0xF0;
if (qmode==xWEBhome) {
  if (strncmp(lbuf,"GET ",4)==0) {
    char * p=lbuf+5;
    if (strcmp(p,"cfg")==0) qmode=xWEBcfgp; else
    if (strcmp(p,"pin")==0) qmode=xWEBpins; else
    if (strcmp(p,"mpw")==0) qmode=xWEBmpw;
    if (qmode!=xWEBhome) lbuf[0]=0;
    }
  }
else if (qmode==xWEBcfgp) {
  if (c=='?')
    { qsubmode=xCFGk; lbuf[0]=0; }
  else if ((c=='&') || (c==' '))
    { WebServer_p(lbuf,&qsubmode,&wkey,&qsaction,datastruct,xparam); qsubmode=xCFGk; lbuf[0]=0; } 
  else if (c=='=')
    { WebServer_p(lbuf,&qsubmode,&wkey,&qsaction,datastruct,xparam); 
      if (qsubmode!=xCFGs) { qsubmode=xCFGv; strcpy(lbuf,"\n"); } else  { lbuf[0]=0; }  }
  if (c==' ') { qmode=xWEBcfg; WebServer_e(&qsaction,xparam); } else
  if (qsubmode==xCFGv) WebServer_h(lbuf); else
  if (qsubmode==xCFGs) WebServer_s(lbuf,&qsaction,xparam);
  }
return ((qmode|qsubmode)|((qsaction|wkey)<<8));
}
 
void WebServer_e(byte * qsaction, unsigned long  * xparam)
{
#if modDisplay == 1
if (*qsaction==xACTwdp)
  {
  byte chsum=((*xparam)&0xFF);
  int xaddr=((*xparam>>8)&0xFFFF);
  int xa,la;CalcDisplayConfEpromSpace(&xa,&la);
  int raddr=xaddr+xa+1;
  if (raddr<la) if (EEPROM.read(raddr)!=0) EEPROM.write(raddr,0);   
  if (EEPROM.read(la)!=0) EEPROM.write(la,0);
  if (EEPROM.read(xa)!=chsum) EEPROM.write(xa,chsum);
  }
#endif
}
 
void WebServer_s(char * lbuf,byte * qsaction,unsigned long * xparam)
{
#if modDisplay == 1
if (*qsaction==xACTwdp)
  {
  if (strlen(lbuf)==2)
    {
    byte d=0;
    for (byte ii=0;ii<2;ii++) {
      char c=lbuf[ii];
      d=(d<<4)+(((c>='0') && (c<='9'))?(c-'0'):(((c>='A') && (c<='F'))?(c-'A'+10):0));
      }
    lbuf[0]=0;
    if (d==0) d=32;
    byte chsum=((*xparam)&0xFF);
    int xaddr=((*xparam>>8)&0xFFFF);
    int xa,la;CalcDisplayConfEpromSpace(&xa,&la);
    int raddr=xaddr+xa+1;
    if (raddr<la)
      {
      if (EEPROM.read(raddr)!=d) EEPROM.write(raddr,d);
      chsum+=((d&0xFF)+(xaddr+1))&0xFF;     
      xaddr++;
      } 
    *xparam=(chsum|((unsigned long)xaddr<<8));
    }
  }
#endif
}
 
void WebServer_h(char * lbuf)
{
int cx=strlen(lbuf);
char * p=lbuf+cx;
while ((p>=lbuf) && (p[0]!='\n')) p--;
if ((p>=lbuf) && (lbuf+cx-p==3)) {
  byte d=0;
  for (byte ii=1;ii<3;ii++) {
    d=d<<4; char c=p[ii];
    if ((c>='0') && (c<='9')) d+=c-'0';
    if ((c>='A') && (c<='F')) d+=c-'A'+10;
    }
  byte pr='\\';
  if (d==pr) { p[0]=pr;p[1]=pr;p++; } 
  if (d==0) { p[0]=pr;p[1]='0';p++; } 
  else p[0]=d;
  p++;p[0]='\n';p[1]=0;
  }
}
 
void WebServer_p(char * xstr,byte * qsubmode,byte * wkey,byte * qsaction, byte * datastruct, 
  unsigned long * xparam)
{
int ix=strlen(xstr);
if (ix>0){ ix--;xstr[ix]=0; }
if (* qsubmode==xCFGk)
  {
 
#if modDisplay == 1   
  if (*qsaction==xACTdb)
    {
    if (strcmp(xstr,"bid")==0) { *wkey=xKEYDispButt; }
    }    
  else
  if (*qsaction==xACTwdp)
    {
    if (strcmp(xstr,"src")==0) { *qsubmode=xCFGs; *xparam=0; }
    }
  else
#endif
  if (*qsaction==xACTwas)
    {
    char * p=xstr;
    if (p[0]=='A')
      {
      p++;
      char * px=p;
      for (int ii=1;ii<strlen(xstr);ii++)
        if (p[0]=='.') { p[0]=0;p++;break; } else p++;
      byte xpinopt=xPinOptNone;
      if (strcmp(p,"ena")==0) xpinopt=xPinOptEnabled; else
      if (strcmp(p,"nam")==0) xpinopt=xPinOptName; else
      if (strcmp(p,"min")==0) xpinopt=xPinOptMin; else
      if (strcmp(p,"max")==0) xpinopt=xPinOptMax; else
      if (strcmp(p,"uni")==0) xpinopt=xPinOptUnit; else
      if (strcmp(p,"typ")==0) xpinopt=xPinOptType; else
      if (strcmp(p,"grp")==0) xpinopt=xPinOptGroup; else
      if (strcmp(p,"~w")==0) xpinopt=xPinCmdWrite;
      *xparam&=0xFFFFFF00;
      *xparam|=xpinopt;
      }   
    *wkey=xKEYpin;
    }
  else
  if (strcmp(xstr,"cmd")==0) *wkey=xKEYcmd; 
  else
    *wkey=xKEYnone;
  }
else
if (* qsubmode==xCFGv)
  {
  if (ix>0){ ix--;xstr[ix]=0; }
 
#if modDisplay == 1   
  if (*wkey==xKEYDispButt)
    {
    DisplayPressButton(xstr);
    }
  else
#endif
 
  if (*wkey==xKEYpin) 
    {
    byte xpk=((*xparam)&0xFF);
    tPinConf * pconf;
    pconf=(tPinConf*)datastruct;
 
if (xpk==xPinOptEnabled) {
  if (strcmp(xstr,"1")==0)
    pconf->xopt|=xpinOPTenabled;
  }
else
if (xpk==xPinOptName)
  strncpy(pconf->xname,xstr,sizeof(pconf->xname)-1);
else
if (xpk==xPinOptMin) {
  signed long xsl=0;int xsl10000=0;
  WebServer_pf(xstr,&xsl,&xsl10000);
  pconf->xmin=xsl;pconf->xmin10000=xsl10000;
  }
else if (xpk==xPinOptMax) {
  signed long xsl=0;int xsl10000=0;
  WebServer_pf(xstr,&xsl,&xsl10000);
  pconf->xmax=xsl;pconf->xmax10000=xsl10000;
  }
else
if (xpk==xPinOptUnit)
  strncpy(pconf->xunit,xstr,sizeof(pconf->xunit)-1);
else
if (xpk==xPinOptType)
  {
  char w=xstr[0];
  pconf->xopt&=~xpinOPTtypeMask;
  if (w=='s') pconf->xopt|=xpinOPTsample; else
  if (w=='a') pconf->xopt|=xpinOPTavg; else
  if (w=='e') pconf->xopt|=xpinOPTeffective; else
  if (w=='m') pconf->xopt|=xpinOPTmin; else
  if (w=='x') pconf->xopt|=xpinOPTmax;
  }
else
if (xpk==xPinOptGroup)
  {
  char w=xstr[0];
  pconf->xopt&=~xpinOPTgroupMask;
  if (w=='0') pconf->xopt|=xpinOPTsampleG0; else
  if (w=='1') pconf->xopt|=xpinOPTsampleG1; else
  if (w=='2') pconf->xopt|=xpinOPTsampleG2; else
  if (w=='3') pconf->xopt|=xpinOPTsampleG3;
  }
else
if (xpk==xPinCmdWrite) {
    WebServer_wp(WebServer_pb(xstr),(tPinConf*)datastruct);
    for (int ii=0;ii<sizeof(tPinConf);ii++) datastruct[ii]=0;
  }
 
    }
  else
  if (*wkey==xKEYcmd) 
    {
    if (strcmp(xstr,"was")==0) *qsaction=xACTwas;else
    if (strcmp(xstr,"wdp")==0) *qsaction=xACTwdp;else
    if (strcmp(xstr,"hw")==0) *qsaction=xACThw;else
    if (strcmp(xstr,"as")==0) *qsaction=xACTas;else
    if (strcmp(xstr,"dp")==0) *qsaction=xACTdp; else
    if (strcmp(xstr,"sp")==0) *qsaction=xACTsp; else
    if (strcmp(xstr,"dd")==0) *qsaction=xACTdd; else 
    if (strcmp(xstr,"db")==0) *qsaction=xACTdb;    
    }
  }
}
 
void WebServer() {
  EthernetClient client = server.available();
  if (client) {
    boolean cl = true;
    char xln[200]="";
    word xmode=xWEBhome;
    unsigned long xparam=0;
    int cx=sizeof(tPinConf);
    byte xDataStruct[cx];
    for (int ii=0;ii<cx;ii++) xDataStruct[ii]=0; 
    int ix=0;
    SetLiveLed(HIGH);
    while (client.connected()) {
      if (client.available()) 
        {
        char c=client.read();
        if (c=='\n') { xln[0]=0; }
        ix=strlen(xln);
        if (ix<sizeof(xln)) { xln[ix]=c;ix++;xln[ix]=0; }
        xmode=WebServer_c(xln,c,xmode,xDataStruct,&xparam);
        byte qmode=xmode&0x0F;
        byte qsubmode=xmode&0xF0; 
        byte qsaction=(xmode>>8)&0x0F; 
        if (c == '\n' && cl) {
          client.write("HTTP/1.1 200 OK\nContent-Type: text/html\nConnnection: close\n\n");
          if (qmode==xWEBpins) {
            for (int ain = 0; ain < NUM_ANALOG_INPUTS; ain++) {
              if (ain>0) client.write(",");
              sprintf(xln,"A%d:%d",ain,SamplerAnalogRead(ain));
              client.write((byte*)xln,strlen(xln));
              }
            } 
          else
          if (qsaction==xACThw)
            {
            sprintf(xln,"~HW\nt:%lX\nc:%d.",millis(),NUM_ANALOG_INPUTS);
            client.write((byte*)xln,strlen(xln));
            char cq[]="%d.%d.%d.%d.%d.%d.%d.%d";
            sprintf(xln,cq,(int)modStatusLedPin,(int)sendInterval,(int)sendRetry,(int)maxErrors,
            (int)lxHttpErrors,(int)modSerialLog,(int)modDisplay,(modDisplay==1)?(int)modDisplayType:(int)0);
            client.write((byte*)xln,strlen(xln));
            sprintf(xln,".%lu\nf:%s\nh:%s\nx:%d\nr:",(long)lxSeconds,modMyPowerFVEID,modMyPowerHost,(int)modMyPowerLog);
            client.write((byte*)xln,strlen(xln));
            sprintf(xln,cq,(int)freeRam(),(int)ARDUINO,(int)RAMEND,(int)XRAMEND,
            (int)E2END,(int)FLASHEND,(int)SPM_PAGESIZE,(int)E2PAGESIZE);
            client.write((byte*)xln,strlen(xln));
            sprintf(xln,"\nv:%s\nm:%02X%02X%02X%02X%02X%02X\nn:",MPWMicroLogVersion,
            NETmac[0],NETmac[1],NETmac[2],NETmac[3],NETmac[4],NETmac[5],NETmac[6]);
            client.write((byte*)xln,strlen(xln));          
            char cf[]="%d.%d.%d.%d";
            IPAddress xaddr;
            xaddr=Ethernet.localIP();
            for (byte i=0;i<4;i++)
              {
              if (i==1) xaddr=Ethernet.subnetMask();else
              if (i==2) xaddr=Ethernet.gatewayIP();else
              if (i==3) xaddr=Ethernet.dnsServerIP();   
              sprintf(xln,cf,xaddr[0],xaddr[1],xaddr[2],xaddr[3]);
              if (i<3) strcat(xln,"/");
              client.write((byte*)xln,strlen(xln));          
              }
            sprintf(xln,"\nw:%d/%ld",(int)modWebServer,(long)modWebServerPort);
            client.write((byte*)xln,strlen(xln));          
            }
          else
          if ((qsaction==xACTas) || (qsaction==xACTwas))
            {
            if (qsaction==xACTwas)
              client.write("~WAS\n");
            else
              client.write("~AS\n");
            for (int xp=0;xp<NUM_ANALOG_INPUTS;xp++)
              {
              tPinConf pconf;            
              boolean isvalid=ReadPinConf(&pconf,xp);            
              sprintf(xln,"A%d:",xp);
              client.write((byte*)xln,strlen(xln));
              if (!isvalid)
                strcat(xln,"-");
              else
                { 
                sprintf(xln,"%X/%ld.%d/%ld.%d/",pconf.xopt,pconf.xmin,
                  pconf.xmin10000,pconf.xmax,pconf.xmax10000);
                client.write((byte*)xln,strlen(xln));
                xln[0]=0;
                char xf[]="%02X";
                char xh[3];
                byte * p;
                p=(byte*)pconf.xname;
                for (int i=0;i<strlen(pconf.xname);i++) {
                  sprintf(xh,xf,p[i]); strcat(xln,xh); }
                client.write((byte*)xln,strlen(xln));
                strcpy(xln,"/");
                p=(byte*)pconf.xunit;
                for (int i=0;i<strlen(pconf.xunit);i++) {
                  sprintf(xh,xf,p[i]); strcat(xln,xh); }
                strcat(xln,"/");
                client.write((byte*)xln,strlen(xln));                 
                sprintf(xln,"%d",SamplerAnalogRead(xp));
                }              
              strcat(xln,"\n");
              client.write((byte*)xln,strlen(xln));
              }
            }
          else
          if (qsaction==xACTsp)
            {
            client.write("~SP\n");
            byte qindex=0;
            while (true)
              {
              qindex++;
              byte qpins[4];
              SamplerGet4PinGroup(qpins,&qindex);
              SamplerExec(qpins,&xSamplerStruct,4);
              sprintf(xln,"MS:%lX\nL:%lX\nT:",millis(),xSamplerStruct.tPinMicros);
              client.write((byte*)xln,strlen(xln));
              for (int x=0;x<128;x++)
                {
                sprintf(xln,"%02X",(int)xSamplerStruct.tPinTimes[x]);
                client.write((byte*)xln,strlen(xln));
                }
              client.write("\n");
              for (int p=0;p<4;p++)
                {
                tSampledPin * qSampledPin=&xSamplerStruct.tPinSamples[p];
                int qpin=qSampledPin->pin;
                if (qpin<NUM_ANALOG_INPUTS)
                  {
                  sprintf(xln,"S%d:S=%lu,A=%lu,M=%d,X=%d,C=%d:",qpin,
                    qSampledPin->smpSqr,
                    qSampledPin->smpAvg,
                    qSampledPin->smpMin,
                    qSampledPin->smpMax,
                    qSampledPin->smpCount);
                  client.write((byte*)xln,strlen(xln));
                  for (int x=0;x<128;x++)
                    {
                    sprintf(xln,"%02X",(int)qSampledPin->smpHi8[x]);
                    client.write((byte*)xln,strlen(xln));
                    }
                  client.write("/");
                  for (int x=0;x<32;x++)
                    {
                    sprintf(xln,"%02X",(int)qSampledPin->smpLo2[x]);
                    client.write((byte*)xln,strlen(xln));
                    }
                  client.write("\n");
                  }
                }
              if (qindex==0) break;              
              }
            for (int x=0;x<NUM_ANALOG_INPUTS;x++)
              {
              tPinValue * qPinValue;
              qPinValue=&xSamplerStruct.tPinValues[x];
              sprintf(xln,"A%d:V=%d,S=%d,A=%d,M=%d,X=%d\n",x,
                qPinValue->smpVal,
                qPinValue->smpSqr,
                qPinValue->smpAvg,
                qPinValue->smpMin,
                qPinValue->smpMax);
              client.write((byte*)xln,strlen(xln));
              }
            }
          else
          if ((qsaction==xACTdp) || (qsaction==xACTwdp))
            {
            if (qsaction==xACTwdp)
              client.write("~WDP\n");
            else
              client.write("~DP\n");
#if modDisplay == 1
            sprintf(xln,"T:%d\n",(int)modDisplayType);
            client.write((byte*)xln,strlen(xln));
            int xa,la;
            CalcDisplayConfEpromSpace(&xa,&la);            
            int xs=la-xa;
            sprintf(xln,"B:%d\nD:",xs-1);
            client.write((byte*)xln,strlen(xln));
            byte chsum=0;
            byte rchsum=EEPROM.read(xa);
            for (int i=1;i<xs;i++) 
              {
              int xv=EEPROM.read(xa+i);
              if (xv==0) break;
              chsum+=((xv&0xFF)+i)&0xFF;
              sprintf(xln,"%02X",xv);
              if ((i-1)%10==9) strcat(xln,"\nD:");
              client.write((byte*)xln,strlen(xln));
              }      
            sprintf(xln,"\nR:%02X\nC:%02X",rchsum,chsum);
            client.write((byte*)xln,strlen(xln));
            if (EEPROM.read(la)!=0) EEPROM.write(la,0);
            client.write("\n");
#endif
            }
          else
 
#if ((modDisplay == 1) && (modDisplayType == dLCDKeyPad1602))
          if (qsaction==xACTdd)
            {
            char lcdlbuf0[17]="";
            char lcdlbuf1[17]="";
            _lcdweblbuf0=lcdlbuf0;
            _lcdweblbuf1=lcdlbuf1;
            tDispStats lcdwebdispstats;
            _lcdwebdispstats=&lcdwebdispstats;                     
            DrawDisplayPage();
            client.write("~DD\n");
            sprintf(xln,"S:%d,%d\n",(int)lcdwebdispstats.xvarscount,(int)lcdwebdispstats.xvarram);
            client.write((byte*)xln,strlen(xln));          
            sprintf(xln,"T:%d\nL1:%s\nL2:%s\n",(int)modDisplayType,lcdlbuf0,lcdlbuf1);
            client.write((byte*)xln,strlen(xln));          
            _lcdweblbuf0=NULL;
            _lcdweblbuf1=NULL;
            _lcdwebdispstats=NULL;
            }
          else
#endif
#if (modDisplay == 1)
          if (qsaction==xACTdb)
            {
            client.write("OK");              
            }
          else
#endif         
          if (qmode==xWEBcfg)  
            {
            client.write("CFG");
            }
          else
            {
            client.write("<!DOCTYPE HTML>\n<html><head><meta http-equiv=\"Content-Type\" ");
            client.write("content=\"text/html; charset=UTF-8\"><style>");
            client.write("a {color:#FFC000;} body {font-family:sans;font-size:12px;background:#101010;color:white}");
            client.write("</style></head>");
            if (qmode==xWEBhome) client.write("<meta http-equiv=\"refresh\" content=\"5\">");
            client.write("<body>");
            client.write("<b><a href=\"./\">HOME</a> | ");
            client.write("<a href=\"mpw\">TOOLS</a></b><hr>");
            if (qmode==xWEBhome) {
 
 
            for (int x=0;x<NUM_ANALOG_INPUTS;x++)
              {
              tPinValue * qPinValue;
              qPinValue=&xSamplerStruct.tPinValues[x];
              sprintf(xln,"A%d: V=%d, S=%d, A=%d, M=%d, X=%d <br>\n",x,
                qPinValue->smpVal,
                qPinValue->smpSqr,
                qPinValue->smpAvg,
                qPinValue->smpMin,
                qPinValue->smpMax);
              client.write((byte*)xln,strlen(xln));
              }
 
/*              
 
              for (int ain = 0; ain < NUM_ANALOG_INPUTS; ain++) {
                sprintf(xln,"<b>A%d:</b> %d<br>",ain,SamplerAnalogRead(ain));
                client.write((byte*)xln,strlen(xln));
                }
 
*/
              } 
            else
            if (qmode==xWEBmpw) {
              client.write("<script language=\"javascript\" src=\"http://");
              client.write(modMyPowerHost);
              client.write("/microlog-tools\"></script>");
              client.write("<div x=\"n\">Connecting to MyPower.CZ ...</div>");
              }
            client.write("<hr><font color=gray size=2><b>powered by ");
            client.write("<a href=\"http://mypower.cz\">MyPower.CZ</a> Microlog</b></font>");
            client.write("</body></html>\n");
            }
          break;
        }
        if (c == '\n') cl = true; else if (c != '\r') cl=false;
        }
      }
    SetLiveLed(LOW);
    delay(1);
    client.stop();
  }
}
#endif
 
 
 
 
// -- [DISPLAY] ----------------------------------------------
 
 
#if (modDisplay == 1)
 
#if (modDisplayType == dLCDKeyPad1602)
 
#define lcdPageSelect   0xFA
#define lcdPageLeft     0xFB
#define lcdPageRight    0xFC
#define lcdPageNone     0xFF
 
struct tDispVar {
char * xname;
signed long xval;
int xval10000;
char * xunit;
};
 
char lcdLastButton=0;
unsigned long lcdLastButtonTime=0;
 
void DisplayDetectButton()
{
char qbutt=0;
int xb=analogRead(0);
if (xb<50) qbutt='R'; else
if (xb<200) qbutt='U'; else
if (xb<400) qbutt='D'; else
if (xb<550) qbutt='L'; else
if (xb<800) qbutt='S';
if ((qbutt!=lcdLastButton) && ((millis()-lcdLastButtonTime)>200))
  {
  if ((lcdLastButton==0) && (qbutt!=0))
    DisplayPressButton(&qbutt);
  lcdLastButton=qbutt;
  lcdLastButtonTime=millis();
  }
 
}
 
void DisplayPressButton(char * xbutt)
{
char p=xbutt[0];
if (p=='X') { delay(1000); softReset(); }
else if (p=='U') { if (lcdCurrentPage==0) lcdCurrentPage=lcdMaxPage; else lcdCurrentPage--; }
else if (p=='D') { if (lcdCurrentPage>=lcdMaxPage) lcdCurrentPage=0; else lcdCurrentPage++; }
else if (p=='R') lcdCurrentPage=lcdPageRight;
else if (p=='L') lcdCurrentPage=lcdPageLeft;
else if (p=='S') lcdCurrentPage=lcdPageSelect;
DrawDisplayPage();
if (lcdCurrentPage>lcdMaxPage) { lcdCurrentPage=0; DrawDisplayPage(); }
}
 
int DisplayGetConfigVarNames(char * xnamebuf,int xbuflen,int xa,int xs)
{
boolean hasvar=false;
char cvn[30]="\n";
strcpy(xnamebuf,cvn);
int xret=0;
for (int i=1;i<=xs;i++)
  {
  char c=EEPROM.read(xa+i);
  if (hasvar)
    {
    if ((c=='.') && ((i<=xs)-2)) { i++;c=EEPROM.read(xa+i);
      if ((c>='0') && (c<='4')) i++;
      c='#';  }
    if ( (DisplayParseVariables_IsVarChar(c)) && (c!='#') )
      {
      int xq=strlen(cvn);
      if (xq<sizeof(cvn)-2) { cvn[xq]=c;xq++;cvn[xq]=0; }
      continue;
      }
    else
      {
      if (cvn[1]!='@')
        {
        strcat(cvn,"\n");
        if (strstr(xnamebuf,cvn)==NULL)
          {
          int qx=(strlen(cvn)-1);
          if (((strlen(xnamebuf)+qx)<(xbuflen-1)) && (qx>1))
            {
            char *p=cvn+1;
            strcat(xnamebuf,p);
            xret++;
            }
          }
        }
      strcpy(cvn,"\n");
      if (c=='#')
        {
        hasvar=false;
        continue;
        }
      }
    }
  if (c==0) break;
  hasvar=(c=='$');
  }
return (xret<1?1:xret);
}
 
struct tDispVar * DisplayFindVarByName(char * xname,byte * xvars, int xmaxvars) {
tDispVar * xret=NULL;
tDispVar * xvar=(tDispVar *)xvars;
for (int i=0;i<xmaxvars;i++) {
  if (strcmp(xvar->xname,xname)==0) { xret=xvar; break; }
  xvar++; }
return xret;
}
 
void DisplayInitConfigVars(char * xnamebuf,byte * xvars, int xmaxvars)
{
char * p=xnamebuf;
if (p[0]=='\n')
  {
  p++;
  tDispVar * xvar=(tDispVar *)xvars;
  char * q=p;
  int ix=strlen(p);
  int qcvars=0;
  for (int i=0;i<ix;i++)
    if (p[i]=='\n') {
      p[i]=0;
      if (q[0]!=0)
        {
        xvar->xname=q;
        xvar->xval=0;
        xvar->xval10000=0;
        xvar->xunit=NULL;    
        qcvars++;
        if (qcvars<xmaxvars) xvar++; else break;
        }
      q=p+1+i;
      }
  }
}
 
void DisplayParseConfig(byte * qWpage)
{
int xa,la;
CalcDisplayConfEpromSpace(&xa,&la);
int xs=la-xa;
byte chsum=0;
byte rchsum=EEPROM.read(xa);
for (int i=1;i<xs;i++) { int xv=EEPROM.read(xa+i);
  if (xv==0) break; chsum+=((xv&0xFF)+i)&0xFF; }      
if (rchsum==chsum) {
  byte xpage=0xFF;
  byte xpageline=0xFF;
  char xln[60]="";
  char xnamebuf[200]="\n";
  int xmaxvars=DisplayGetConfigVarNames(xnamebuf,sizeof(xnamebuf),xa,xs);
  tDispVar xvars[xmaxvars];
  if (_lcdwebdispstats!=NULL) {
    _lcdwebdispstats->xvarscount=xmaxvars;
    _lcdwebdispstats->xvarram=sizeof(xvars);
    }
  DisplayInitConfigVars(xnamebuf,(byte*)xvars, xmaxvars);
  word xflag=lcdPageNone;
  for (int i=1;i<xs;i++) {
    int xv=EEPROM.read(xa+i);
    if ((xv==0) || (xv=='\n')) {
      char * p=xln;
      while ((p[0]!=0) && (p[0]==32)) p++;
      for (int ii=0;p[ii]!=0;ii++) if ((p[ii]=='/') && (p[ii+1]=='/')) { p[ii]=0;break; }
      for (int ii=strlen(p)-1;ii>=0;ii--) if (p[ii]==32) p[ii]=0; else break;
      if (p[0]!=0) DisplayParseConfigL(p,&xpage,&xpageline,qWpage,(byte*)xvars,xmaxvars,&xflag);
      xln[0]=0;
      }
    else 
      { int xls=strlen(xln); if (xls<sizeof(xln)-1) { xln[xls]=xv;xln[xls+1]=0; } }
    if (xv==0) break;
    }
  if (xpage!=0xFF) lcdMaxPage=xpage;
  }
}
 
void DisplayParseConfigL(char * xln,byte * xpage,byte * xpageline,byte * qWpage, byte * xvars, int xmaxvars,word * xflag)
{
if (xln[0]=='#')
  {
  *xflag=lcdPageNone;
  if (xln[1]=='R') *xflag=lcdPageRight; else
  if (xln[1]=='L') *xflag=lcdPageLeft; else
  if (xln[1]=='S') *xflag=lcdPageSelect;
  (*xpage)++;
  (*xpageline)=0xFF;
  }
else
if ((*xpage)==0xFF)
  DisplayParseConfigCmdL(xln, xvars, xmaxvars, xflag);
else
if ((*xpage)!=0xFF)
  {
  if ((*xpageline)==0xFF) (*xpageline)=0; else (*xpageline)++; 
  if (((*qWpage)==(*xpage)) || ((*xflag)==(*qWpage)))
    {
    *qWpage=(*xpage);
    *xflag=lcdPageNone;
    if (*xpageline<2)
      {
      lcdClearLine();
      char * p=xln;
      for (int i=0;i<strlen(xln);i++) if (p[i]=='|') { p+=i;p[0]=0;p++;break; }
      char px[20];
      if (p==xln)
        {       
        DisplayParseVariables(px,xln,sizeof(px),xvars,xmaxvars);
        lcdPrintCenter(px);
        }
      else
        {
        DisplayParseVariables(px,xln,sizeof(px),xvars,xmaxvars);
        lcdPrintLeft(px);
        px[0]=0;
        DisplayParseVariables(px,p,sizeof(px),xvars,xmaxvars);
        lcdPrintRight(px);
        }
      lcdPrintLine(*xpageline);
      }
    }
  }
}
 
#define xVarOpNONE  0x00
#define xVarOpADD   0x01
#define xVarOpSUB   0x02
#define xVarOpMUL   0x03
#define xVarOpDIV   0x04
#define xVarOpEQ    0x05
 
void DisplayParseConfigCmdL(char * xln, byte * xvars, int xmaxvars, word * xflag)
{
byte xop=xVarOpNONE;
tDispVar constVar;
tDispVar * xr=NULL;
tDispVar * xvar=NULL;
int xconstdecs=-1;
boolean hasvar=false;
boolean hasconst=false;
char cvarname[20]="";
for (int i=0;i<=strlen(xln);i++)
  {
  char c=xln[i];
  if ((hasvar) && (!hasconst))
    {
    if (c=='.') { c=xln[i+1]; if ((c>='0') && (c<='9')) { i++; } c='#';  }
    if ( (DisplayParseVariables_IsVarChar(c)) && (c!='#'))
      {
      int xq=strlen(cvarname);
      if (xq<sizeof(cvarname)-1) { cvarname[xq]=c;xq++;cvarname[xq]=0; }
      continue;
      }
    else
      {
      char qunit[10]="";
      constVar.xname=cvarname;
      constVar.xunit=qunit;
      constVar.xval=0;
      constVar.xval10000=0;
      xvar=&constVar;
      if (cvarname[0]=='@')
        {
        char r=cvarname[1];
        char *p=cvarname+2;
        int xpin=0;
        for (int ic=0;ic<strlen(p);ic++)
          { xpin*=10; char e=p[ic]; if ((e>='0') || (e<='9')) xpin+=e-'0'; }
        xvar->xname=cvarname;
        xvar->xunit=qunit;
        xvar->xval=0;
        xvar->xval10000=0;
        DisplayFillVarByPinValue(xpin,xvar,r);
        }
      else
        xvar = DisplayFindVarByName(cvarname,xvars,xmaxvars);
 
      if ((xvar!=NULL) && (xr!=NULL) && (xop!=xVarOpNONE)) {          
        if (xop==xVarOpEQ)
          { xr->xval=xvar->xval; xr->xval10000=xvar->xval10000; }
        else
          DisplayDoVarOp(xr,xvar,xop);
        xop=xVarOpNONE;
        }     
      cvarname[0]=0;
      if (c=='#') { hasvar=false; continue; }
      }
    }
  else
  if ((!hasvar) && (hasconst))
    {
    boolean isnum=((c>='0') && (c<='9'));
    if ((c=='.') && (xconstdecs<0))
      {
      xconstdecs=0;
      continue;
      }
    else
    if ((isnum) && (xvar!=NULL))
      {
      int cn=c-'0';
      if (xconstdecs<0)
        {
        if (xconstdecs>=-9)
          {
          xconstdecs--;
          xvar->xval*=10;
          xvar->xval+=(signed long)cn;
          }
        }
      else
      if (xconstdecs<4)
        {
        xconstdecs++;
        xvar->xval10000*=10;
        xvar->xval10000+=cn;
        }
      continue;
      }
    else
      {
 
      if ((xvar!=NULL) && (xr!=NULL) && (xop!=xVarOpNONE)) {     
        if (xconstdecs>=0) while (xconstdecs<4) { xconstdecs++; xvar->xval10000*=10; }
        if (xop==xVarOpEQ)
          { xr->xval=xvar->xval; xr->xval10000=xvar->xval10000; }
        else
          DisplayDoVarOp(xr,xvar,xop);
        xop=xVarOpNONE;
        }     
 
      xvar=NULL;
      hasconst=false;
      xconstdecs=-1;
      }
    }
 
  if (c==0) break;
  hasvar=(c=='$');
  if (!hasvar) { 
 
    hasconst=((c>='0') && (c<='9'));
    if (hasconst)
      {
      constVar.xval=0;
      constVar.xval10000=0;
      xvar=&constVar;
      i--;
      continue;
      }
 
    if (c!=' ') 
      {      
      byte xlastop=xop;
      if (c=='=') xop=xVarOpEQ; else
      if (c=='+') xop=xVarOpADD; else
      if (c=='-') xop=xVarOpSUB; else
      if (c=='*') xop=xVarOpMUL; else
      if (c=='/') xop=xVarOpDIV;
      if ((xlastop==xVarOpNONE) && (xop==xVarOpEQ) && (xvar!=NULL) && (xr==NULL)) 
        { xr=xvar; xvar=NULL; }
      }
    else
      hasconst=false;
    }
  }
}
 
 
void DisplayDoVarOp(struct tDispVar * xr,struct tDispVar * xvar,byte xop)
{ 
int64 xq1,xq2,xqr;
if (xop==xVarOpMUL) {
  i64x10k2int10kH(&xq1, xr->xval,xr->xval10000);
  i64x10k2int10kH(&xq2, xvar->xval,xvar->xval10000);
} else {
  i64x10k2int10k(&xq1, xr->xval,xr->xval10000);
  i64x10k2int10k(&xq2, xvar->xval,xvar->xval10000);
  }
if (xop==xVarOpADD) i64addS(&xqr,&xq1,&xq2); else
if (xop==xVarOpSUB) i64subS(&xqr,&xq1,&xq2); else
if (xop==xVarOpDIV) { word xmod; i64divW(&xqr, &xmod, &xq1, xvar->xval); } else
if (xop==xVarOpMUL) { int64 xretH; i64mul64(&xretH, &xqr, &xq1, &xq2); }
i64int10k2x10k(&xr->xval,&xr->xval10000,&xqr);
}
 
void PrintComputedPinValue(int xpin,char * xret,int maxunitsize,char xpintype)
{
tDispVar xvar;
DisplayFillVarByPinValue(xpin,&xvar,xpintype);
signed long xval=xvar.xval;
int xval10k=xvar.xval10000;
sprintf(xret,"%ld.%04d",xval,xval10k);
}
 
void DisplayFillVarByPinValue(int xpin,struct tDispVar * xvar,char xpintype)
{
if ((xpin<NUM_ANALOG_INPUTS) && (xvar!=NULL))
  {
  tPinConf pconf;
  byte qpintype=xpinOPTdefault; 
  if ((xpintype=='A') || (xpintype=='a')) qpintype=xpinOPTavg; else
  if ((xpintype=='R') || (xpintype=='r')) qpintype=xpinOPTeffective; else
  if ((xpintype=='S') || (xpintype=='s')) qpintype=xpinOPTsample; else
  if ((xpintype=='M') || (xpintype=='m')) qpintype=xpinOPTmin; else
  if ((xpintype=='X') || (xpintype=='x')) qpintype=xpinOPTmax; 
  int pinval=SamplerAnalogReadType(xpin,qpintype);
  xvar->xval=pinval;
  xvar->xval10000=0;
  if ((xpintype>='A') && (xpintype<='Z'))
    {
    boolean isvalid = ReadPinConf(&pconf,xpin);
    if (isvalid)
      {
      int qxval10000;
      signed long qxval;
      DisplayMapPinValue(pinval,&qxval,&qxval10000,
        pconf.xmin,pconf.xmin10000,pconf.xmax,pconf.xmax10000);
      xvar->xval=qxval;
      xvar->xval10000=qxval10000;
      }
    }
  }
}
 
void DisplayMapPinValue(int pinval,signed long * qxval, int * qxval10k,
      signed long xmin, int xmin10k, signed long xmax, int xmax10k)
{
*qxval10k=0;*qxval=0;int64 qmin,qdif,qx,qml,qmx;i64nul(&qmin);i64nul(&qdif);i64nul(&qx);
i64x10k2int10k(&qmin,xmin,xmin10k);i64x10k2int10k(&qx,xmax,xmax10k);
boolean msf=qmin.msf;i64subS(&qdif,&qx,&qmin);qmin.msf=msf;i64nul(&qx);qx.ll=pinval;
msf=qdif.msf;qdif.msf=false;i64mul64(&qmx,&qml,&qx,&qdif);word xmod;
i64divW(&qmx,&xmod,&qml,1023);qmx.msf=msf;i64addS(&qml,&qmx,&qmin);
i64int10k2x10k(qxval, qxval10k, &qml);
}
 
 
boolean DisplayParseVariables_IsVarChar(char c) {
return ( ((c>='a') && (c<='z')) || ((c>='A') && (c<='Z')) || (c=='_') || 
  (c=='@') || (c=='#') || (c=='.') || ((c>='0') && (c<='9')) ); }
 
void DisplayParseVariables(char * xdst,char * xsrc, int xmaxlen, byte * xvars,int xmaxvars)
{
int ix=0;
boolean hasvar=false;
char cvarname[20]="";
byte xdecs=0xFF;
for (int i=0;i<=strlen(xsrc);i++)
  {
  char c=xsrc[i];
  if (hasvar)
    {
    if (c=='.') { c=xsrc[i+1];
      if ((c>='0') && (c<='9')) { xdecs=c-'0';i++; }
      c='#';  }
    if ( (DisplayParseVariables_IsVarChar(c)) && (c!='#'))
      {
      int xq=strlen(cvarname);
      if (xq<sizeof(cvarname)-1) { cvarname[xq]=c;xq++;cvarname[xq]=0; }
      continue;
      }
    else
      {
      char qunit[10]="";
      tDispVar pinVar;
      pinVar.xname=cvarname;
      pinVar.xunit=qunit;
      pinVar.xval=0;
      pinVar.xval10000=0;
      tDispVar * xvar=&pinVar;
      if (cvarname[0]=='@')
        {
        char r=cvarname[1];
        char *p=cvarname+2;
        int xpin=0;
        for (int ic=0;ic<strlen(p);ic++)
          { xpin*=10; char e=p[ic]; if ((e>='0') || (e<='9')) xpin+=e-'0'; }
        xvar->xname=cvarname;
        xvar->xunit=qunit;
        xvar->xval=0;
        xvar->xval10000=0;       
        DisplayFillVarByPinValue(xpin,xvar,r);
        }
      else
        xvar = DisplayFindVarByName(cvarname,xvars,xmaxvars);
 
      if (xvar!=NULL)
        {
        char pxval[50]="";
        char qsc[]=" kMGT";
        char *xsc=qsc;
        signed long xval=xvar->xval;
        int xval10k=xvar->xval10000;
        while (xval>1500)
          {
          if (xsc[1]==0) break;
          int64 xq,xr; word xmod;
          i64x10k2int10k(&xq, xval,xval10k);
          i64divW(&xr, &xmod, &xq, 1000);
          i64int10k2x10k(&xval,&xval10k,&xr);
          xsc++;
          }
        sprintf(pxval,"%ld.%04d",xval,xval10k);
        DisplayCorrectDecs(pxval,xdecs);
        if ((xsc[0]!=' ') && (xsc[0]!=0)) { xsc[1]=0; strcat(pxval,xsc); }
        for (int cc=0;cc<strlen(pxval);cc++)
          if (ix<xmaxlen-1) { xdst[ix]=pxval[cc];ix++;xdst[ix]=0; }
        }
      cvarname[0]=0;
      if (c=='#') 
        {
        hasvar=false;
        continue;
        }
      }
    }
  if (c==0) break;
  hasvar=(c=='$');
  if ((!hasvar) && (ix<xmaxlen-1)) { xdst[ix]=c;ix++;xdst[ix]=0; }
  }
}
 
void DisplayCorrectDecs(char * pxval, byte xdecs)
{
int xl=strlen(pxval);
if (xl>0) {
  if (xdecs==0xFF) { for (;;) { xl=strlen(pxval); if ((xl==0) || (pxval[xl-1]!='0')) break; pxval[xl-1]=0; } }
  else { if (xdecs>4) xdecs=4; byte qdecs=4-xdecs;
    for (byte xx=0;xx<qdecs;xx++) { xl=strlen(pxval);if (xl==0) break; pxval[xl-1]=0; } }
  xl=strlen(pxval); if (xl>0) if (pxval[xl-1]=='.') pxval[xl-1]=0;
  }
}
 
void DrawDisplayPage()
{
if (lcdCurrentPage==0xFF)
  {
  lcdClear();
  lcdCurrentPage=0;
  }
DisplayParseConfig(&lcdCurrentPage);
}
 
#endif
 
#endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// -- [SAMPLER] ----------------------------------------------
 
int SamplerAnalogRead(byte xpin) 
{
return SamplerAnalogReadType(xpin,xpinOPTdefault); 
}
 
int SamplerAnalogReadType(byte xpin,byte forcextype)
{
int xret=0;
if (xpin<NUM_ANALOG_INPUTS)
  {
  tPinValue * xpinvalue;
  xpinvalue=&xSamplerStruct.tPinValues[xpin];
  byte xtype=SamplerGetPinType(xpin);
  if (forcextype!=xpinOPTdefault) xtype=forcextype;
  if (xtype==xpinOPTavg) xret=xpinvalue->smpAvg;else 
  if (xtype==xpinOPTeffective) xret=xpinvalue->smpSqr;else 
  if (xtype==xpinOPTmin) xret=xpinvalue->smpMin;else 
  if (xtype==xpinOPTmax) xret=xpinvalue->smpMax;else
    xret=xpinvalue->smpVal;
  }
return xret;
}
 
void SamplerRun()
{
byte qpins[4];
SamplerGetNext4PinGroup(qpins); 
SamplerExec(qpins,&xSamplerStruct,4);
}
 
byte SamplerGroupindex=0;
unsigned long Stime=0;
 
void SamplerGetNext4PinGroup(byte * qpins)
{
SamplerGroupindex++;
SamplerGet4PinGroup(qpins,&SamplerGroupindex);
}
 
byte SamplerGetPinType(byte xpin)
{
byte xret=xpinOPTsample;tPinConf pconf;
if (ReadPinConf(&pconf,xpin)) xret=pconf.xopt&xpinOPTtypeMask;
return xret;
}
 
byte SamplerGetPinGroup(byte xpin)
{
byte xret=0;
byte qret=0;
tPinConf pconf;
if (ReadPinConf(&pconf,xpin)) {
  qret=pconf.xopt&xpinOPTgroupMask;
  if (qret==xpinOPTsampleG0) xret=0; else
  if (qret==xpinOPTsampleG1) xret=1; else
  if (qret==xpinOPTsampleG2) xret=2; else
  if (qret==xpinOPTsampleG3) xret=3;
  }
return xret;
}
 
void SamplerGet4PinGroup(byte * qpins,byte * qgroupindex)
{
char pgroups[4][NUM_ANALOG_INPUTS+1];
for (int x=0;x<4;x++) strcpy(pgroups[x],"");
char qch[2]="";qch[1]=0;
for (int x=0;x<NUM_ANALOG_INPUTS;x++) { qch[0]='A'+x; strcat(pgroups[SamplerGetPinGroup(x)],qch); }
char pgroups4[NUM_ANALOG_INPUTS][5];
for (int x=0;x<NUM_ANALOG_INPUTS;x++) strcpy(pgroups4[x],"");
int p4index=0;
for (int x=0;x<4;x++) {
  while (strlen(pgroups[x])>0) {
    strncpy(pgroups4[p4index],pgroups[x],4);
    pgroups4[p4index][4]=0;
    if (strlen(pgroups[x])>4) {
      char * p=(pgroups[x])+4;
      strcpy(pgroups[x],p);
      }
    else
      strcpy(pgroups[x],"");
    p4index++;
    }
  }
for (int p4s=0;p4s<NUM_ANALOG_INPUTS;p4s++) {
  int xl=strlen(pgroups4[p4s]);
  if (xl==4) continue; 
  else {
    int xr=4-xl;
    boolean xfound=false;
    while (!xfound) {
      for (int x=p4s+1;x<NUM_ANALOG_INPUTS;x++)
        if (strlen(pgroups4[x])==xr) {
          strcat(pgroups4[p4s],pgroups4[x]);
          strcpy(pgroups4[x],"");
          xfound=true;
          break;
          }
      if (xfound) break; else if (!xfound) { if (xr>0) xr--; else break; }
      }
    }
  }
byte p4count=0;
for (int x=0;x<NUM_ANALOG_INPUTS;x++) if (strlen(pgroups4[x])==0) { p4count=x;break; }
for (int x=0;x<4;x++) qpins[x]=0xFF;
byte idx=0;
if (p4count>0) {
  idx=*qgroupindex%p4count;
  *qgroupindex=idx;
  char *p=pgroups4[idx];
  int xl=strlen(p);
  if (xl>4) xl=4;
  if (xl!=0)
    for (int x=0;x<xl;x++)
      qpins[x]=(p[x])-'A';
  }
}
 
void SamplerResetPinStruct(int xpin,struct tSampledPin * xSampledPin)
{
xSampledPin->pin=xpin;
for (int x=0;x<sizeof(xSampledPin->smpHi8);x++) xSampledPin->smpHi8[x]=0;
for (int x=0;x<sizeof(xSampledPin->smpLo2);x++) xSampledPin->smpLo2[x]=0;
xSampledPin->smpSqr=0;
xSampledPin->smpAvg=0;
xSampledPin->smpMin=0x3FF;
xSampledPin->smpMax=0x000;
xSampledPin->smpCount=0;
}
 
 
void SamplerExec(byte * pins, struct tSamplerStruct * qSamplerStruct,byte xpinscount)
{
byte * xtimes=qSamplerStruct->tPinTimes;
tSampledPin * xPinSamples=qSamplerStruct->tPinSamples;
unsigned long wqms,wqme;
for (int x=0;x<xpinscount;x++) SamplerResetPinStruct(pins[x],&xPinSamples[x]);
for (int x=0;x<128;x++) xtimes[x]=0;
int qscount=sizeof(xPinSamples[0].smpHi8);
int smpCount=0;
unsigned long xxs,xms,xm1;
unsigned long qms,qm1;
int qsample=0;
int inputpin=0;
tSampledPin * qSampledPin;
int xs3=0;
int xs2=0;
xxs=micros();
xms=0;
qms=0;
while (true) { xm1=micros()-xxs; if ((xm1>>9)!=qms) break; }
xms=xm1;
 
wqms=micros();
for (int x=0;x<qscount;x++)
  {
  xs2=x>>2;
  xs3=(x&0x03)<<1;
  for (int p=0;p<xpinscount;p++)
    {
    qSampledPin=&xPinSamples[p];
    if (qSampledPin->pin<NUM_ANALOG_INPUTS) qsample=analogRead(qSampledPin->pin); else qsample=0;
    qSampledPin->smpHi8[x]=(byte)(qsample>>2);
    qSampledPin->smpLo2[xs2]|=(byte)((qsample&0x03)<<xs3);
    }
  smpCount++;  
  qms=xms>>9;
  while (true) { xm1=micros()-xxs; if ((xm1>>9)!=qms) break; }
  xtimes[x]=(byte)( (xm1-xms) - 400 );
  xms=xm1;
  }
 
wqme=micros()-wqms;
qSamplerStruct->tPinMicros=wqme;
 
for (int x=0;x<qscount;x++)
  {
  xs2=x>>2;
  xs3=(x&0x03)<<1;
  for (int p=0;p<xpinscount;p++)
    {
    qSampledPin=&xPinSamples[p];
    qsample=(((int)qSampledPin->smpHi8[x])<<2)|((qSampledPin->smpLo2[xs2]>>xs3)&0x03);
    qSampledPin->smpAvg+=qsample;
    if (qSampledPin->smpMax<qsample) qSampledPin->smpMax=qsample;
    if (qSampledPin->smpMin>qsample) qSampledPin->smpMin=qsample;
    unsigned long qs=qsample;qs*=qs;
    qSampledPin->smpSqr+=qs;
    }
  }
 
byte qpoint=64;
for (int p=0;p<xpinscount;p++)
  {
  qSampledPin=&xPinSamples[p];
  byte qxpin=qSampledPin->pin;
  if (qxpin<NUM_ANALOG_INPUTS)
    {
    qSampledPin->smpSqr=sqrt(qSampledPin->smpSqr/smpCount);
    qSampledPin->smpAvg=qSampledPin->smpAvg/smpCount;
    qSampledPin->smpCount=smpCount;
    tPinValue * xpinvalue=&qSamplerStruct->tPinValues[qxpin];
    xs3=(qpoint&0x03)<<1;
    xpinvalue->smpVal=(((int)qSampledPin->smpHi8[qpoint])<<2)|((qSampledPin->smpLo2[qpoint>>2]>>xs3)&0x03);;
    xpinvalue->smpSqr=qSampledPin->smpSqr;
    xpinvalue->smpAvg=qSampledPin->smpAvg;
    xpinvalue->smpMin=qSampledPin->smpMin;
    xpinvalue->smpMax=qSampledPin->smpMax;
    }
  }
}
 
 
 
 
 
// -- [MATH64] -------------------------------------------------
 
void i64print(struct int64 * xval,char * xstr) { 
  char x[200]="";char xm[5]="";if (xval->msf) strcpy(xm,"-");sprintf(x,"--[ %s ] --\n%s%04lX%04lX%04lX%04lX",xstr,xm,
  (long)xval->hh,(long)xval->hl,(long)xval->lh,(long)xval->ll);Serial.println(x); }
 
void i64cpy(struct int64 * xdst,struct int64 * xsrc) { xdst->hh=xsrc->hh;xdst->hl=xsrc->hl;
  xdst->lh=xsrc->lh;xdst->ll=xsrc->ll;xdst->msf=xsrc->msf; }
void i64nul(struct int64 * q1) { q1->hh=0;q1->hl=0;q1->lh=0;q1->ll=0;q1->msf=false; }
void i64shl16(struct int64 * xret) { xret->hh=xret->hl;xret->hl=xret->lh;xret->lh=xret->ll;xret->ll=0;}
int i64cmpS(struct int64 * q1, struct int64 * q2) { for (byte i=0;i<4;i++) {
  word x1=((i==0)?(q1->hh):(i==1?(q1->hl):(i==2?(q1->lh):(i==3?(q1->ll):0))));
  word x2=((i==0)?(q2->hh):(i==1?(q2->hl):(i==2?(q2->lh):(i==3?(q2->ll):0))));
  signed long s1=(signed long)x1; signed long s2=(signed long)x2;
  if (q1->msf) s1=-s1;if (q2->msf) s2=-s2; if (s1<s2) return -1;else if (s1>s2) return 1; }
return 0; }
 
void i64addS(struct int64 * xret, struct int64 * q1, struct int64 * q2) {
i64nul(xret);signed long xx; if ( ((!q1->msf) && (!q2->msf)) || ((q1->msf) && (q2->msf)) ) {
  xx=(signed long)q1->ll+(signed long)q2->ll;xret->ll=(word)(xx&0xFFFF);
  xx=(signed long)q1->lh+(signed long)q2->lh+(signed long)(xx>>16);xret->lh=(word)(xx&0xFFFF);
  xx=(signed long)q1->hl+(signed long)q2->hl+(signed long)(xx>>16);xret->hl=(word)(xx&0xFFFF);
  xx=(signed long)q1->hh+(signed long)q2->hh+(signed long)(xx>>16);xret->hh=(word)(xx&0xFFFF);
  xret->msf=((q1->msf) && (q2->msf)); }
else if ((q1->msf) && (!q2->msf)) { q1->msf=false; i64subS(xret, q2, q1); }
else if ((!q1->msf) && (q2->msf)) { q2->msf=false; i64subS(xret, q1, q2); }
}
 
void i64subS(struct int64 * xret, struct int64 * q1, struct int64 * q2) { 
i64nul(xret); if ((!q1->msf) && (q2->msf)) { q2->msf=false; i64addS(xret, q1, q2); } else
if ((q1->msf) && (!q2->msf)) { q1->msf=false; i64addS(xret, q1, q2); xret->msf=true; } else
if ((q1->msf) && (q2->msf)) { q1->msf=false;q2->msf=false; i64subS(xret, q2, q1); } else 
if ((!q1->msf) && (!q2->msf)) { int xcmp=i64cmpS(q1,q2);
  if (xcmp==0) return; else if (xcmp==-1) { i64subS(xret, q2, q1); xret->msf=true; }
  else { signed long xx,xh,xl;xx=(signed long)q1->ll-(signed long)q2->ll;
    xh=(xx>=0)?0:1;xret->ll=(word)xx;xx=(signed long)q1->lh-(signed long)q2->lh-xh;
    xh=(xx>=0)?0:1;xret->lh=(word)xx;xx=(signed long)q1->hl-(signed long)q2->hl-xh;
    xh=(xx>=0)?0:1;xret->hl=(word)xx;xx=(signed long)q1->hh-(signed long)q2->hh-xh;
    xret->hh=(word)xx; } }
}
 
boolean i64divW(struct int64 * xret, word * xmod, struct int64 * q1, word q2) {
i64nul(xret);*xmod=0; if (q2==0) return false;
else { unsigned long ql;ql=(unsigned long)q1->hh;xret->ll=ql/q2;*xmod=ql%q2;i64shl16(xret);
  ql=(((unsigned long)(*xmod))<<16)+(unsigned long)q1->hl;xret->ll=ql/q2;*xmod=ql%q2;i64shl16(xret);
  ql=(((unsigned long)(*xmod))<<16)+(unsigned long)q1->lh;xret->ll=ql/q2;*xmod=ql%q2;i64shl16(xret);
  ql=(((unsigned long)(*xmod))<<16)+(unsigned long)q1->ll;xret->ll=ql/q2;*xmod=ql%q2;
  return true; } 
}
 
unsigned long i64lo(struct int64 * xint) { return (((unsigned long)xint->lh)<<16)+((unsigned long)xint->ll);}
unsigned long i64hi(struct int64 * xint) { return (((unsigned long)xint->hh)<<16)+((unsigned long)xint->hl);}
 
void i64mul64(struct int64 * xretH, struct int64 * xretL, struct int64 * q1, struct int64 * q2) 
{ i64nul(xretH);i64nul(xretL);unsigned long q1l,q1h,q2l,q2h;
q1l=i64lo(q1);q1h=i64hi(q1);q2l=i64lo(q2);q2h=i64hi(q2);int64 xr1,xr2,xr3,xr4;
i64mul(&xr4, q1h, q2h);i64mul(&xr3, q1h, q2l);i64mul(&xr2, q1l, q2h); i64mul(&xr1, q1l, q2l); 
xretL->ll=xr1.ll;xretL->lh=xr1.lh;unsigned long xr2h=i64hi(&xr2);unsigned long xr3h=i64hi(&xr3);
xr2.hh=0;xr2.hl=0;xr3.hh=0;xr3.hl=0;int64 xr1x;i64nul(&xr1x);
xr1x.lh=xr1.hh;xr1x.ll=xr1.hl;int64 xr23sumx;i64addS(&xr23sumx,&xr2,&xr3);int64 xr23sumL;
i64addS(&xr23sumL,&xr23sumx,&xr1x);xretL->hl=xr23sumL.ll;xretL->hh=xr23sumL.lh;
int64 xr23o;i64nul(&xr23o);xr2.lh=(word)(xr2h>>16);xr2.ll=(word)(xr2h&0xFFFF);
xr3.lh=(word)(xr3h>>16);xr3.ll=(word)(xr3h&0xFFFF);xr23o.ll=xr23sumL.hl;xr23o.lh=xr23sumL.hh;
i64addS(&xr1,&xr4,&xr2);i64addS(&xr4,&xr1,&xr3);i64addS(xretH,&xr4,&xr23o);
}
 
void i64mul(struct int64 * xret, unsigned long q1, unsigned long q2) { 
unsigned long x1,x2,qp,qp1;i64nul(xret);
word all=(word)q1;word alh=(word)(q1>>16);word bll=(word)q2;word blh=(word)(q2>>16);
x1=(unsigned long)all*(unsigned long)bll;xret->ll=(word)(x1);qp=(x1>>16);
x1=(unsigned long)alh*(unsigned long)bll;qp1=(x1>>16);x1&=0xFFFF;
x2=(unsigned long)all*(unsigned long)blh;qp1+=(x2>>16);x2&=0xFFFF;x1+=x2+qp;qp=(x1>>16)+qp1;
xret->lh=(word)(x1);x1=((unsigned long)alh*(unsigned long)blh);
x1+=qp;xret->hl=(word)(x1);xret->hh=(word)(x1>>16);
}
 
void i64int10k2x10k(signed long * xval, int * x10k, struct int64 * xint64) {
boolean msf=xint64->msf;xint64->msf=false;int64 qret;i64nul(&qret);
word xmod=0;i64divW(&qret, &xmod, xint64, 10000);*x10k=xmod;
signed long qval=(((unsigned long)qret.lh)<<16)+(unsigned long)qret.ll;
*xval=msf?(-qval):qval;xint64->msf=msf;
}
 
void i64x10k2int10k(struct int64 * xret, signed long xval, int x10k) {
int64 q1;int64 q2;i64nul(xret);i64nul(&q1);i64nul(&q2);
boolean msf=((xval)<0);if (msf) xval=-(xval);if (x10k<0) x10k=-(x10k);
q2.ll=(x10k)&0xFFFF;i64mul(&q1, (unsigned long)(xval), 10000UL);
i64addS(xret, &q1, &q2);xret->msf=msf;
}
 
void i64x10k2int10kH(struct int64 * xret, signed long xval, int x10k) {
int64 q1;int64 q2;i64nul(xret);i64nul(&q1);i64nul(&q2);
boolean msf=((xval)<0);if (msf) xval=-(xval);if (x10k<0) x10k=-(x10k);
q2.ll=(x10k/100)&0xFFFF;i64mul(&q1, (unsigned long)(xval), 100UL);
i64addS(xret, &q1, &q2);xret->msf=msf;
}
source.1377324090.txt.gz · Poslední úprava: 2013/08/24 14:01 (upraveno mimo DokuWiki)

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki