Post Reply 
A small contribution and a big question (timer/keyboard)
11-29-2019, 03:42 AM
Post: #1
A small contribution and a big question (timer/keyboard)
Recently I ran into a problem of having to perform many time interval measurements and post process them. Since automating the measurement process was not possible, I decided that rather than using a stopwatch, writing down results, and later typing them in for post processing, I would write an HP Prime application combining a stopwatch and post processing in one.

Initial results were less than satisfying. It turned out that TICKS() based time measuring process yields a substantial error (about 2.5% in case of my G2).

In the web I found a note (pertaining to G1) stating that for the TICKS() command HP Prime uses processor internal clock which is not very stable, and that the real time is derived from external RTC which is very accurate, but has only 1 sec resolution.
Apparently this is also a case with G2. I accepted this fact not having time to have a closer look at the calculator board and studying i.MX 6ULL documentation.

I came up with a way if synchronizing the TICKS() derived signal with the Time() derived signal. This way the overall error of time measurement is minimized. The accuracy of the application was tested during many runs, the longest lasting over 10 hours. The error was negligible. (Keep in mind that manual starting and stopping the devices already introduced a few tenths of a second error.)

The following code implements a simple stopwatch. It's a core of the application I used for my measurements stripped of all irrelevant features, and instead equipped with very crude stopwatch user interface. Maybe somebody will find it useful.
Code:

#pragma mode(separator(.,;) integer(h64))

//prototypes
StopwatchCore();
ConvertMsToTime();
PrintTime();
RightJustifyString();
PrintMainScreen();
PrintMenuStop();
PrintMenuRun();
PrintOverfillWarning();

EXPORT STOPWATCH_HPM()
BEGIN

  LOCAL nBackground:=RGB(198,198,198);  
  LOCAL nKey;
  LOCAL lStatus:={0,0};  // list {first free line for lap time, last tick count}
  LOCAL sString;

  LOCAL sVersion:="ver. 1.11-HPM";

  // HP Prime has two sources of internal clock.
  // One is external RTC. It has good accuracy, but only 1 sec resolution (function Time() ).
  // Another is internal processor clock, and it's used for TICKS(). It has good resolution (1ms),
  //  but poor accuracy. (Measured about 2.5%.)
  // We use TICKS() for measuring tenths of a second, and every second we synchronize it to Time().

  // Resources: uses G1 and G2

  // initialization
  STARTVIEW(-1);
  PrintMainScreen(sVersion,nBackground);
  PrintMenuStop(nBackground);
  sString:=ConvertMsToTime(0);

  PrintTime(sString,nBackground);

  // main loop
  REPEAT
    nKey:=GETKEY();
    CASE
      // Enter
      IF nKey==30 THEN
        PrintMenuRun(nBackground);
        lStatus:=StopwatchCore(lStatus(1),lStatus(2),nBackground);
        PrintMenuStop(nBackground);
        IF lStatus(2)>=864000000 THEN
          PrintOverfillWarning(nBackground);
        END;
      END;
      // Del
      IF nKey==19 THEN
        PrintMainScreen(sVersion,nBackground);
        PrintMenuStop(nBackground);
        lStatus(1):=0;  // set lap counter to zero
        lStatus(2):=0;  // set starting time to zero
        sString:=ConvertMsToTime(0);
        PrintTime(sString,nBackground);
        PrintMenuStop(nBackground);  // in case overfill menu was printed
      END;
    END;
  UNTIL nKey==31; // EEX was pressed
  RETURN 0;
END;

// ***
StopwatchCore(nPreviousLaps,nPreviousTicks,nBackground)
BEGIN
  // controls stopwatch
  // nLaps: number of lap times displayed on the screen already
  // nStartTicks: time to resume counting from
  // nBackground: screen background

  LOCAL sString;
  LOCAL i,nStartTicks,nTime,nCount,nOffset;
  LOCAL nLaps:=0;
  LOCAL nKey;

  // if more than 10 days, refuse to run
  IF nPreviousTicks>=864000000 THEN
    RETURN {nPreviousLaps,nPreviousTicks};
  END;

  nTime:=Time();

  // print zero value
  sString:=ConvertMsToTime(nPreviousTicks);
  PrintTime(sString,nBackground);

  nStartTicks:=TICKS;
  nCount:=-1;
  // do first second and calculate offset
  REPEAT
    nCount:=nCount+1;
    REPEAT
      IF nTime<>Time() THEN
        nOffset:=TICKS-nStartTicks;
        nTime:=Time();
      END;
      nKey:=GETKEY();
      CASE
        IF nKey==30 AND nLaps+nPreviousLaps<13 THEN  // Enter and within capture limit
          sString:=ConvertMsToTime(TICKS-nStartTicks+nPreviousTicks);
          TEXTOUT_P(nLaps+nPreviousLaps+1+". ",4,4+(nLaps+nPreviousLaps)*14,3,RGB(0,0,0));
          TEXTOUT_P(sString,26,4+(nLaps+nPreviousLaps)*14,3,RGB(255,0,0));
          nLaps:=nLaps+1;
        END;
        IF nKey==4 OR TICKS-nStartTicks+nPreviousTicks>=864000000 THEN // Esc
          RETURN {nLaps+nPreviousLaps,TICKS-nStartTicks+nPreviousTicks};
        END;
      END;
      IF (TICKS-nStartTicks)MOD10==0 THEN
        sString:=ConvertMsToTime(TICKS-nStartTicks+nPreviousTicks);
        PrintTime(sString,nBackground);
      END;
    UNTIL TICKS-nStartTicks>=100*(nCount+1);
  UNTIL nCount<100;

  REPEAT    
    nCount:=nCount+1;
    REPEAT
      IF nTime<>Time() THEN
        nStartTicks:=TICKS-100*nCount-nOffset;  // synchronize to real time
        nTime:=Time();
      END;
      nKey:=GETKEY();
      CASE
        IF nKey==30 AND nLaps+nPreviousLaps<13 THEN  // Enter and within capture limit
          sString:=ConvertMsToTime(TICKS-nStartTicks+nPreviousTicks);
          TEXTOUT_P(nLaps+nPreviousLaps+1+". ",4,4+(nLaps+nPreviousLaps)*14,3,RGB(0,0,0));
          TEXTOUT_P(sString,26,4+(nLaps+nPreviousLaps)*14,3,RGB(255,0,0));
          nLaps:=nLaps+1;
        END;
        IF nKey==4 OR TICKS-nStartTicks+nPreviousTicks>=864000000 THEN // Esc
          RETURN {nLaps+nPreviousLaps,TICKS-nStartTicks+nPreviousTicks};
        END;
      END;
      IF (TICKS-nStartTicks)MOD10==0 THEN
        sString:=ConvertMsToTime(TICKS-nStartTicks+nPreviousTicks);
        PrintTime(sString,nBackground);
      END;
    UNTIL TICKS-nStartTicks>=100*(nCount+1);
  UNTIL 0;
END;

// ***
ConvertMsToTime(nMilliseconds)
BEGIN
  // converts number of milliseconds to string days:hrs:min:sec.trnth
  LOCAL nDays,nHours,nMinutes,nSeconds;
  LOCAL sDays,sHours,sMinutes,sSeconds;
  LOCAL sMilliseconds;

  // days
  nDays:=IP(nMilliseconds/86400000);
  nMilliseconds:=nMilliseconds-nDays*86400000;
  // hours
  nHours:=IP(nMilliseconds/3600000);
  nMilliseconds:=nMilliseconds-nHours*3600000;
  // minutes
  nMinutes:=IP(nMilliseconds/60000);
  nMilliseconds:=nMilliseconds-nMinutes*60000;
  // seconds
  nSeconds:=IP(nMilliseconds/1000);
  nMilliseconds:=nMilliseconds-nSeconds*1000;
  // tenths of seconds
  nMilliseconds:=IP(nMilliseconds/10);  // use nMilliseconds as a buffer

  IF nDays==0 THEN
    sDays:="";
  ELSE
    sDays:=STRING(nDays)+"d : ";
  END;
  IF nHours==0 AND nDays==0 THEN
    sHours:="";
  ELSE
    IF nDays<>0 AND nHours<10 THEN
      sHours:= "0"+STRING(nHours)+"h : ";
    ELSE 
      sHours:=STRING(nHours)+"h : ";
    END;
  END;
  IF nMinutes==0 AND nHours==0 AND nDays==0 THEN
    sMinutes:="";
  ELSE
    IF (nDays<>0 OR nHours<>0) AND nMinutes<10 THEN
      sMinutes:= "0"+STRING(nMinutes)+"m : ";
    ELSE
      sMinutes:=STRING(nMinutes)+"m : ";
    END;
  END;
  IF nMinutes==0 AND nHours==0 AND nDays==0 THEN
    sSeconds:=STRING(nSeconds)+".";
  ELSE
    IF nSeconds<10 THEN
      sSeconds:= "0"+STRING(nSeconds)+".";
    ELSE 
      sSeconds:=STRING(nSeconds)+".";
    END;
  END;
  IF nMilliseconds<10 THEN
    sMilliseconds:="0"+STRING(nMilliseconds)+"s";
  ELSE
    sMilliseconds:=STRING(nMilliseconds)+"s";
  END;

  RETURN sDays+sHours+sMinutes+sSeconds+sMilliseconds;
END;

// ***
PrintTime(sString,nBackground)
BEGIN
  LOCAL nX;

  DIMGROB_P(G1,1,1);
  nX:=TEXTOUT_P(sString,G1,0,0,7);
  DIMGROB_P(G2,320,23,nBackground);
  TEXTOUT_P(sString,G2,(320-nX)/2,0,7,RGB(0,0,0),320,nBackground);
  BLIT_P (G0,0,200,G2);
END;

// ***
RightJustifyString(sString,nX,nFont)
BEGIN
  // returns X coordinate of right justified string
  // uses G1
  // allocates area of 1 px since TEXTOUT_P prints faster to not allocated area

  DIMGROB_P(G1,1,1);  // reserve area of 1 pixel 
  RETURN nX-TEXTOUT_P(sString,G1,0,0,nFont);
END;

// ***
PrintMainScreen(sVersion,nBackground)
BEGIN
  RECT(nBackground);
  TEXTOUT_P("© dap, 2019",4,228,1,RGB(0,0,0));
  TEXTOUT_P(sVersion,RightJustifyString(sVersion,315,1),228,1,RGB(0,0,0));
END;

// ***
PrintMenuStop(nBackground)
BEGIN
  RECT_P(206,4,319,52,nBackground);
  TEXTOUT_P("[Enter] - start",228,4,3,RGB(255,0,168),91, nBackground);
  TEXTOUT_P("[Del] - reset",228,20,3,RGB(255,0,168),91, nBackground);
  TEXTOUT_P("[EEX] - quit",228,36,3,RGB(255,0,168),91, nBackground);
END;

// ***
PrintMenuRun(nBackground)
BEGIN
  RECT_P(226,4,319,52,nBackground);
  TEXTOUT_P("[Enter] - capture",210,4,3,RGB(255,0,168),111, nBackground);
  TEXTOUT_P("[Esc] - stop",210,20,3,RGB(255,0,168),111, nBackground);
END;

// ***
PrintOverfillWarning(nBackground)
BEGIN
  RECT_P(206,4,319,52,nBackground);
  TEXTOUT_P("Count limit",224,4,3,RGB(255,0,168),111, nBackground);
  TEXTOUT_P("exceeded,",224,20,3,RGB(255,0,168),111, nBackground);
  TEXTOUT_P("[Del] to reset",224,36,3,RGB(255,0,168),91, nBackground);
END;
(Those who would like to use it should keep in mind, though, that the battery of continuously running G2 gets drained quite fast. After 10 hours of running the battery level dropped from full to 25%. The HP Prime battery measurement system is extremely inaccurate, but, I believe, it's safe to say that if you plan to cross a boundary of a day of continuous run, use the charger to power the calculator.)

While testing the applications (both original one and the one modified for this forum) I ran into a key pressing problem. Once every hundred key presses or so (rough average) the calculator fails to recognize a key press, and misses it. I was not able to find any reason why it's happening.

If somebody knows the mechanism behind this failure and can share an explanation with me, I would appreciate it.

Darius
Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
A small contribution and a big question (timer/keyboard) - DrDarius - 11-29-2019 03:42 AM



User(s) browsing this thread: 1 Guest(s)