Author Topic: FNIRSI-1013D "100MHz" tablet oscilloscope  (Read 388865 times)

Anty_94, wsg, tokar, Magua and 8 Guests are viewing this topic.

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #875 on: June 25, 2021, 07:20:47 pm »
There is some progress.

Don't think I can fully reverse the display library, because I suspect they used some C++ code and are only using part of the full functionality. That makes it hard to fill in the blanks in the data structures. There are a lot of function pointers and tables with function pointers. Some of them point to empty functions so look like callback functions to do extra or dedicated actions.

Did find the "render function" at least used for font_2. This is a variable width font and uses single pixel bitmaps per character. The "render function" has some painting modes. Before the display_text function is called this mode is set. Named this function "set_font_paint_mode" and is found at address 0x800197C8. It is used with either 0x00 or 0x02 as input.

When 0x00 is used the render function paints the background with the background color (assumed) and the character with the foreground color. (also assumed)

When 0x02 is used the render function paints the character with the background color (assumed) and leaves the background for what it is.

There are two other modes that don't seem to be used. 0x01 and 0x03 (the mode is anded with 0x03). These use the same code. Through a function pointer a function is called that returns a short. Each font dot is then read from a screen buffer and exored with this value. So some sort of color inversion.

Uploaded a new Ghidra archive with the latest findings to the repository. (https://github.com/pecostm32/FNIRSI-1013D-Hack)

With the found information I can extract some of the fonts from the binary and convert them to C.

For font_0 and font_1 I have to do more research. These are fixed width fonts, so for every character the same number of data bytes are used.

That's it for today. 8)

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #876 on: June 26, 2021, 07:08:42 pm »
Wrote a simple program to extract a variable width font from the binary.

Extracted font_2 as a c source. Made a header file with the font structures. Not all the names in there will be correct, but the ones that matter and are used look correct.

Need to test the font in some way, maybe in the emulator, but that requires some programming.

Also found more about the color handling. Will update the repository with the new Ghidra archive and the font extractor code.

The extracted font and header file plus the extractor code are also attached here.

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #877 on: July 01, 2021, 04:19:02 pm »
Extracted the other variable width fonts and wrote a html/javascript test to print them. It turns out that the base of the font is the same for all of them and only the scale is different. A couple of them have extra characters for languages like French.

Researched the fixed width fonts and they have some special overlay system where two characters can be printed on top of each other. Did not extract them yet. Also found an extra font which is set as some default in initialization but did not found where it is used yet.

Attached the html/javascript code with the 6 fonts extracted from the scope code. Rewrote the extractor to output javascript.

Plan on writing a simple display library myself to provide what is needed for the scope. Nothing fancy. After that the actual scope code can be reversed on top of that.

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #878 on: July 03, 2021, 01:41:56 pm »
Extracted the fixed width fonts and these also have the same base font with different sizes. Font_0 and font_1 are the same except for the interline spacing. Font_0 uses a height and baseline of 16, while font_1 uses 16 for the height, but 18 for the baseline, so has 2 pixels more between the text lines.

The default font which does not seem to be used is smaller. It's height is only 8 pixels and the width 6 pixels.

All the fonts are in the repository as C sources. Font_0 and font_1 are in the same file (font_0.c)

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #879 on: July 04, 2021, 09:59:15 am »
Stumbled onto something interesting.

I was writing some initial code for testing on the scope and based it on the bootloader reversal I did. Here the code header for the F1C100s is included in the startup file and the checksum in there is set with mksunxi. Before running the code in the scope I decided to see what it looks like in Ghidra. Used the same methodology as for the original scope code and stripped of the header. This showed me that the jump to the main function was of by 20 bytes (the header size).

Decided to do the same with the bootloader code and noticed the same. But I tested it in the scope and it worked. :-//

Turns out that the first 4 bytes of the header are a branch instruction to the first instruction right after the header. So within this setup the header is also loaded in as code and execution starts at the beginning of the header.

Code: [Select]
                             **************************************************************
                             *                       THUNK FUNCTION                       *
                             **************************************************************
                             thunk undefined Reset()
                               Thunked-Function: FUN_00000020
             undefined         r0:1           <RETURN>
                             Reset                                           XREF[1]:     Entry Point(*) 
        00000000 06 00 00 ea     b          FUN_00000020
                             **************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             undefined UndefinedInstruction()
             undefined         r0:1           <RETURN>
                             UndefinedInstruction                            XREF[1]:     Entry Point(*) 
        00000004 65 47 4f 4e     cdpmi      p7,0x4,cr4,cr15,cr5,0x3
                             **************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             undefined SupervisorCall()
             undefined         r0:1           <RETURN>
                             SupervisorCall                                  XREF[1]:     Entry Point(*) 
        00000008 2e 42 54 30     subccs     r4,r4,lr, lsr #0x4
                             **************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             undefined PrefetchAbort()
             undefined         r0:1           <RETURN>
                             PrefetchAbort                                   XREF[1]:     Entry Point(*) 
        0000000c c5 45 42 68     stmdavs    r2,{r0 r2 r6 r7 r8 r10 lr}^
                             **************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             undefined DataAbort()
             undefined         r0:1           <RETURN>
                             DataAbort                                       XREF[1]:     Entry Point(*) 
        00000010 00 26 00 00     andeq      r2,r0,r0, lsl #0xc
                             **************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             undefined NotUsed()
             undefined         r0:1           <RETURN>
                             NotUsed                                         XREF[1]:     Entry Point(*) 
        00000014 53 50 4c 02     subeq      r5,r12,#0x53
                             **************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             undefined IRQ()
             undefined         r0:1           <RETURN>
                             IRQ                                             XREF[1]:     Entry Point(*) 
        00000018 00 00 00 00     andeq      r0,r0,r0
                             **************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             undefined FIQ()
             undefined         r0:1           <RETURN>
                             FIQ                                             XREF[1]:     Entry Point(*) 
        0000001c 00 00 00 00     andeq      r0,r0,r0
                             **************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             undefined FUN_00000020()
             undefined         r0:1           <RETURN>
                             FUN_00000020                                    XREF[1]:     Reset:00000000(T),
                                                                                          Reset:00000000(j) 
        00000020 00 00 0f e1     mrs        r0,cpsr
        00000024 1f 00 c0 e3     bic        r0,r0,#0x1f
        00000028 db 00 80 e3     orr        r0,r0,#0xdb
        0000002c 00 f0 29 e1     msr        cpsr_cf,r0
        00000030 78 d0 9f e5     ldr        sp,[DAT_000000b0]                                = 00006C00h
        00000034 00 00 0f e1     mrs        r0,cpsr


So for the main code I have to incorporate the header in an other way or change the bootloader to treat the header also as part of the code and not skip it.

Simple solution might be to set the linker to see memory starting from 0x7FFFFFE0 instead of 0x8000000. This way the header sits before actual memory and the rest will be on the right addresses.

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #880 on: July 05, 2021, 03:10:32 pm »
Had to solve some linker issues concerning a data segment to get the right size of the program in the flash, but after that a test of bare metal programming resulted in text on the screen of the emulator. You have to look closely since the font is very small, but is what is used for the channel menu select buttons and the volts/div text next to it. :-DD

Also needed the header to use the eGON.EXE instead of eGON.BT0 marker, which is used for the bootloader. The original bootloader of the scope checks on this header part >:( causing the very first test to fail. The second one failed on the incorrect size in the header, causing the font data to not be loaded from the flash. :palm:

So I can now start with writing a simple display library and then finally try to replicate the original scope code.

Edit: The library is taking shape. Added the fixed width font handling and drawing of a rectangle.
« Last Edit: July 05, 2021, 06:00:31 pm by pcprogrammer »
 

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #881 on: July 08, 2021, 02:30:42 pm »
Still working on recreating the code and found yet another piece of the puzzle with a big why? :-//

The text for some of the buttons is not written with the display text function but by copying bitmaps from the code memory. For the CTRL button (Upper right on the screen) the function to display it can be found at address 0x8000C4B8. The bitmap can be found at address 0x800449E4. It is 16 bits per pixel and 60 pixels by 55 lines. The used pixels are set with 0xFFFF.

Extracted and converted the image to verify the find.

There are more of these bitmaps in there.

Why they did it like this, who knows? It will be faster than rendering the text with their code, but when optimized, the text printing is fast enough.

Also identified more drawing functions. One for filling a rounded rectangle and another for drawing the outline of a rounded rectangle. So have to add versions of it to my own code.

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #882 on: July 08, 2021, 05:16:53 pm »
They used several handling styles in their code.  |O

The top bar uses a bitmap for the menu "button", a print text (CH1, CH2, T) and fill rectangle for the channel and trigger "buttons" and bigger bitmaps for the actual menus, instead of building them with code. Certainly faster, but why the mix. Using bitmaps for everything would have been the fastest. A full bitmap for the CTRL "button" instead of filling a rounded rectangle, drawing a rounded rectangle outline and copy in the text bitmap would have been faster.

But this puzzle is also nearing the end. Able to name more and more of the functions and get an understanding of how it works.

Offline robca

  • Frequent Contributor
  • **
  • Posts: 257
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #883 on: July 08, 2021, 11:44:17 pm »
They used several handling styles in their code.  |O

The top bar uses a bitmap for the menu "button", a print text (CH1, CH2, T) and fill rectangle for the channel and trigger "buttons" and bigger bitmaps for the actual menus, instead of building them with code. Certainly faster, but why the mix. Using bitmaps for everything would have been the fastest. A full bitmap for the CTRL "button" instead of filling a rounded rectangle, drawing a rounded rectangle outline and copy in the text bitmap would have been faster.

But this puzzle is also nearing the end. Able to name more and more of the functions and get an understanding of how it works.
When that happens is because of legacy code, usually. Probably they have some legacy code for less powerful devices that used bitmaps, then added more flexible fonts for all languages, but kept using the old code for those elements since it works and it's tested... Everything new uses the new fonts code

BTW: I'm a long time lurker, who loves reading about the amazing work you do and the progress you are making. Kudos!
 
The following users thanked this post: pcprogrammer

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #884 on: July 09, 2021, 12:06:40 pm »
Found hopefully all of the bitmaps. Labeled them and the functions using them in Ghidra and uploaded the archive to the repository.

With this new information tracking how the scope works should be easier. Have to make a decision on how to implement things in the recreation of the code. Copy and improve the bitmap setup or use display drawing and text functions to mimic the behavior.

Think I will give the latter a shot first since the printing of text already works :)

I'm also curious as to what people are doing with the data from the repository. I can see that every time I post here and update the repository, clones of the repository are being made. It is there for it, but as said curious about it :-//

Offline tv84

  • Super Contributor
  • ***
  • Posts: 3212
  • Country: pt
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #885 on: July 09, 2021, 12:22:21 pm »
I'm also curious as to what people are doing with the data from the repository.

Sounds like you've got to expand your reversing capabilities!  :-DD
 

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #886 on: July 09, 2021, 12:55:57 pm »
I'm also curious as to what people are doing with the data from the repository.

Sounds like you've got to expand your reversing capabilities!  :-DD

Nah human targets way more difficult than computers and far beyond my skills :) :palm:

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #887 on: July 11, 2021, 03:23:04 pm »
Nearly done with the first draft of the display library :)

Last to do are fill rounded rectangle and fill arc. For now everything is based on 1 pixel line width, which might do for the scope. Adding a dot size is probably not that difficult, but if it is not needed I might leave it.

The test result suits in a modern art gallery, if I say so myself :-DD

Offline rhb

  • Super Contributor
  • ***
  • Posts: 3476
  • Country: us
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #888 on: July 14, 2021, 02:23:02 am »
Very fine work.  Can I get a signed print?

Have Fun!
Reg
 

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #889 on: July 14, 2021, 09:33:39 am »
Very fine work.  Can I get a signed print?

Sorry, I only do open license open source work :-DD

see https://github.com/pecostm32/FNIRSI-1013D-Hack/tree/main/Test%20code/Display_Lib_Test

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #890 on: July 17, 2021, 07:24:30 pm »
After an unfortunate break, today some good progress.

Due to my wife developing a cat allergy, we had the difficult task to find a new home for our 8 year old cat. It was not easy and of course emotional. Here in France there are many cats and people like the young ones and not the older ones. The SPA's are filled up and we could not get it over our hearts to put her there even if there was space. We eventually found a good home where some Dutch people run an animal paradise, but it required a trip of over 400Km. We did it because we wanted a good home for her, where she can spend the rest of her live. She was born on our veranda. The cat of our neighbors decided to deliver her kittens there because her previous litter was drowned by the same neighbor >:(

We decided to keep the kittens and had a lovely time with them. Unfortunately the blackish male got cancer in the kidneys and we had to have him put to sleep almost two years ago :'(

For the scope I managed to write a lot of the menu button functions. Need to finish the trigger settings and the battery symbol. Next after that is writing the touch panel interface and a state machine for the menu actions, to be able to control everything.


Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #891 on: July 19, 2021, 05:12:32 pm »
Things are getting along.

Implemented the touch panel interface code. Made an improved copy of the original code. Tested it on the scope and it worked straight away. Modified the touch panel configuration to be on 800x480 instead of 1024x600 so no post processing of the coordinates is needed, as in the original code. Have to check the delay's with a scope to see if they need tweaking. Some of the delay's in the initialization can probably be reduced anyway, since they are quite long.

Next up is a state machine for control handling. Will be a bit more work to reproduce all the control functionality of the scope.

Once that is done, the real task begins. Reproducing the trace display. Still a lot of work needs to be done.

The picture shows the finished main screen with battery level and charge indicator. All controlled with variables. For now manually set in the main function to test everything.
There is still room for improvement since I'm in a somewhat fast coding mode :-DD

The new files are in the repository. https://github.com/pecostm32/FNIRSI-1013D-Hack/tree/main/Test%20code/fnirsi_1013d_scope

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #892 on: July 20, 2021, 10:13:30 am »
Measurement showed the i2c was slower than the original. Did some tests with some port toggle code and noticed it being faster when running it in SRAM (using FEL) instead of in DRAM. I realized I did not implemented the memory management code of the original scope code. Since that uses a linear translation I decided to only try to enable the caches, and that did the trick. Makes a difference of almost a factor 2.

Tweaked the touch panel timing and now it works on ~140KHz instead of the ~40KHz of the original code. Since the delay is based on a simple for loop I have to be aware when turning up optimization level of the compiler. It might remove it and result in not working touch panel :(

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #893 on: July 20, 2021, 04:44:18 pm »
Spend a while trying to work out the first function called in the main while loop. It is for monitoring the battery level and charging state, but I'm a bit at a loss of why they are doing it the way they are doing it.

Code: [Select]
void monitor_battery(void)
{
  int iVar1;
  undefined *puVar2;
  byte bVar3;
  uint uVar4;
  byte *pbVar5;
  int iVar6;
  int iVar7;
  byte bVar8;
  bool bVar9;
 
  iVar1 = DAT_8000a6a8;                               //Base of settings data
  bVar8 = 0xff;

  if (0xd < *(byte *)(DAT_8000a6a8 + 10))             //Time base setting   If 13 is smaller then, so 14 and up (1mS/div and down)
  {
    iVar7 = 0x1e;                                     //1mS/div --- 10nS/div, factor is 30
    goto LAB_8000a5bc;
  }

  if (*(byte *)(DAT_8000a6a8 + 10) < 0xc)             //Less then 0x0C
  {
    if (*(byte *)(DAT_8000a6a8 + 10) < 9)             //Less then 9
    {
      if (6 < *(byte *)(DAT_8000a6a8 + 10))           //If 6 is smaller then, so 7 and 8.
      {
        iVar7 = 100;                                  //200mS/div, 100mS/div, factor is 100
        goto LAB_8000a5bc;
      }

      if (3 < *(byte *)(DAT_8000a6a8 + 10))           //If 3 is smaller then, so 4, 5 and 6
      {
        iVar7 = 0x32;                                 //2S/div, 1S/div, 500mS/div, factor is 64
        goto LAB_8000a5bc;
      }

      if (1 < *(byte *)(DAT_8000a6a8 + 10))           //If 1 is smaller then, so 2 and 3
        goto LAB_8000a5b0;                            //10S/div, 5S/div, factor is 10
    }

    iVar7 = 3;                                        //0, 1, 9, 10, 11
                                                      //50S/div, 20S/div, 50mS/div, 20mS/div, 10mS/div, factor is 3
  }
  else
  {
LAB_8000a5b0:                                         //12, 13
    iVar7 = 10;                                       //5mS/div, 2mS/div factor is 10
  }

LAB_8000a5bc:

  uVar4 = check_port_pin(DAT_8000a6ac,0xc);           //Battery charge detect

  puVar2 = PTR_DAT_8000a6b0;                          //0x80192ed4  some global variable, some accumulator??

  if (uVar4 == 0)                                     //If pin is low the battery is being charged
  {
    if (*(char *)(iVar1 + 0x39) == '\0')              //BatteryCharging variable
    {
      *PTR_DAT_8000a6b0 = 0;                          //If previous state was not charging this variable is set 0
    }

    *(undefined *)(iVar1 + 0x39) = 1;                 //Indicate charging
  }
  else
  {
    *(undefined *)(iVar1 + 0x39) = 0;                 //Indicate not charging
  }

  bVar3 = read_keyadc_data();                         //Battery level reading. result 0 - 0x3F


  //0x80361378 Some base pointer

  //Some fractional addition to the adc value
  //            result from scan                                         byte from 0x8036137A (screen brightness)                                   0x068DB8BB
  uVar4 = (uint)bVar3 + (uint)((ulonglong)(uint)((int)(short)(ushort)*(byte *)(DAT_8000a6b4 + 2) * (int)(short)((ushort)bVar3 * 10)) * (ulonglong)DAT_8000a6b8 >> 0x28);  //High result byte logical shifted right an extra 8

  //Check if on charge
  if (*(char *)(iVar1 + 0x39) != '\0')
  {
    uVar4 = uVar4 - 7;   //Take of 7 as compensation
  }

  //Check if result is less then 25
  if (uVar4 < 0x19)
  {
    //If so set it to the minimum
    uVar4 = 0x19;
  }

  //Divide ((the result minus the minimum) multiplied by 20) by 21
  pbVar5 = (byte *)divide((uVar4 - 0x19) * 0x14, 0x15);

  //Get data from global variable which is reset when charging starts
  //Is an array index
  bVar3 = *puVar2;


  //0x802F1906 some array where the result is stored
  DAT_8000a6bc[bVar3] = (byte)pbVar5;

  //As long as the index is lower than the factor obtained from timebase setting
  if ((int)(uint)bVar3 < iVar7 + -1)
  {
    //Increment the index and store it back
    *puVar2 = bVar3 + 1;
    return; //and quit
  }

  //When several samples are stored it comes here
  //true since none of the timebase compare paths lead to iVar being set zero
  bVar9 = iVar7 != 0;

  if (bVar9)
  {
    pbVar5 = DAT_8000a6bc; //Point to the data
  }

  *puVar2 = 0; //Reset the index

  //As long as there is data to process
  while (bVar9)
  {
    bVar3 = *pbVar5;          //Get the first byte
    pbVar5 = pbVar5 + 1;      //Point to the next one

    if (bVar3 < bVar8)        //Determine the lowest value
    {
      bVar8 = bVar3;          //Keep the lowest value of the samples
    }

    iVar7 = iVar7 + -1;       //One count done
    bVar9 = iVar7 != 0;       //Check on done
  }

  //Store result in BatteryChargeLevel
  *(byte *)(iVar1 + 0x38) = bVar8;

  display_battery_status();
}


Based on the time base setting they determine a number of samples that needs to be monitored before the screen is updated. They store each sample in an array and once the number of needed samples is reached they look for the lowest value and use that to display. This can be easier done with one variable and keep the lowest one after taking a sample, and reset the variable at the start of a new run, but that aside.

What I don't get is the math they are doing after taking a sample. I have no experience with battery charge reading what so ever, so any input is welcomed.

The sample comes from the keyadc and is in range of 0 to 63. To this result they add some value. Looks like some fixed point fractional calculation.
They multiply the sample by 10. This is multiplied with the value coming from some variable (at 0x8036137A)
The result of this multiplication is multiplied with 0x068DB8BB. The top 24 bits are used to add to the sample.
After that they take of 7 when on charge.
Then it is checked against 25 and if less they make it 25.
From the resulting value is then 25 subtracted. The resulting value of that is then multiplied by 20 and that is divided by 21.

Anyone?????

Edit: The variable  (at 0x8036137A) used in the multiplication seems to be the screen brightness. This makes sense since it will drain the battery when it is higher.
« Last Edit: July 20, 2021, 04:51:43 pm by pcprogrammer »
 

Offline Martin72

  • Super Contributor
  • ***
  • Posts: 5670
  • Country: de
  • Testfield Technician
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #894 on: July 21, 2021, 10:20:51 pm »
Hi folks,

Just found a review of the Fnirsi-1013D with a clear verdict:

Hands off the Fnirsi 1013D

Martin
 
The following users thanked this post: e_Johny

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #895 on: July 22, 2021, 05:33:04 pm »
After again a bit of scanning the original code in Ghidra I found the code for displaying the channel 1 menu. This pointed me to the FFT enable variable, so that is one more down :) and I found out how they "animate" the menus, because when you select a menu it slides in from the top, or in case of the measures menu from the side. The bitmap is drawn repeatedly from the top of the screen with the bitmap from the end up, So in the first loop the 16 bottom lines are drawn, the second loop the 31 bottom lines, the third loop the 45  bottom lines until the whole bitmap is displayed.

Have not implemented this yet in my own code, but did implement the non bitmap version of the menu, as one can see in the screen capture of the emulator.

Also gained some insight in how they made their state machine. I will copy it for now just to get something up and running. But my programming gut tells me it can be improved on :-DD

Also found proof of the FPGA analysis I did. The second function in the main while loop is for displaying the traces and I can see that based on the time base setting the different values are written to the FPGA. These values match what I saw with tracing the data to the FPGA 8)

The third function might be for handling the cursors, but that needs further investigation.

So breakout the popcorn and sit back, the story continues :popcorn:

Offline e_Johny

  • Contributor
  • Posts: 12
  • Country: hu
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #896 on: July 22, 2021, 07:37:55 pm »
Hi folks,

Just found a review of the Fnirsi-1013D with a clear verdict:

Hands off the Fnirsi 1013D

Martin

Hello Martin.
Yes, it was in the #866 post (in other language).
 
The following users thanked this post: Martin72

Offline Martin72

  • Super Contributor
  • ***
  • Posts: 5670
  • Country: de
  • Testfield Technician
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #897 on: July 22, 2021, 09:37:29 pm »
Oops... :o


Offline rhb

  • Super Contributor
  • ***
  • Posts: 3476
  • Country: us
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #898 on: July 22, 2021, 10:01:47 pm »
FWIW I am supposed to get first hand experience with a Hantek 2D42 DSO-DMM-AWG tomorrow.  It will be very interesting to see how it does.  I can live with a decent 40 MHz scope.

Have Fun!
Reg
 

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3623
  • Country: nl
Re: FNIRSI-1013D "100MHz" tablet oscilloscope
« Reply #899 on: July 23, 2021, 05:55:24 pm »
Coded the channel 1 menu handling. Still need to scan through the original code some more to see what is being done, but the changing of the settings works. The menu slides in from the top, just as in the original code.

Reduced quite a bit on the number of calls to reading the touch panel status.

This is the code that came out of Ghidra.
Code: [Select]
LAB_8001dc04:
        do
        {
          tp_i2c_read_status();
          uVar11 = (uint)*(ushort *)(puVar4 + 2);

          if (uVar11 - 0xa2 < 0xb6)   //Check the xrange
          {
            uVar15 = (uint)*(ushort *)(puVar4 + 4);  //Get the y pos
            bVar27 = 0x2d < uVar15;
            bVar26 = uVar15 == 0x2e;

            if (0x2e < uVar15)
            {
              bVar27 = uVar15 <= uVar12;
              bVar26 = uVar12 == uVar15;
            }

            if (bVar27 && !bVar26)
            {
              uVar16 = uVar11 - 0xdc;

              if (((uVar16 < 0x3b) && (0x30 < uVar15)) && (uVar15 < 0x6a))
              {
                if (*puVar4 != '\0')           //Do we have touch
                {
                  *pcVar5 = '\x01';            //This is for channel 1 enable
                  display_channel1_menu();

                  FUN_80002790();

                  tp_i2c_read_status();
                  cVar1 = *puVar4;

                  while (cVar1 != '\0')
                  {
                    tp_i2c_read_status();
                    cVar1 = *puVar4;
                  }
                }
              }
              else
              {
                uVar18 = uVar11 - 0x11a;
                if (((uVar18 < 0x3a) && (0x31 < uVar15)) && (uVar15 < 0x6b))
                {
                  if (*puVar4 != '\0')
                  {
                    *pcVar5 = '\0';             //This is for channel 1 disable
                    display_channel1_menu();
                    FUN_80002790();
                    pcVar5[3] = '\0';
                    FUN_8000689c();
                    tp_i2c_read_status();
                    cVar1 = *puVar4;
                    while (cVar1 != '\0') {
                      tp_i2c_read_status();
                      cVar1 = *puVar4;
                    }
                  }
                }
                else {
                  if (((uVar16 < 0x3b) && (0x6f < uVar15)) && (uVar15 < 0xa9)) {
                    if (*puVar4 != '\0') {
                      pcVar5[4] = '\x01';
                      display_channel1_menu();
                      tp_i2c_read_status();
                      cVar1 = *puVar4;
                      while (cVar1 != '\0') {
                        tp_i2c_read_status();
                        cVar1 = *puVar4;
                      }
                    }
                  }
                  else {
                    if (((uVar18 < 0x3a) && (0x6f < uVar15)) && (uVar15 < 0xa9)) {
                      if (*puVar4 != '\0') {
                        pcVar5[4] = '\0';
                        display_channel1_menu();
                        tp_i2c_read_status();
                        cVar1 = *puVar4;
                        while (cVar1 != '\0') {
                          tp_i2c_read_status();
                          cVar1 = *puVar4;
                        }
                      }
                    }
                    else {
                      if (((uVar16 < 0x3b) && (0xad < uVar15)) && (uVar15 < 0xe7)) {
                        if (*puVar4 != '\0') {
                          pcVar5[1] = '\0';
                          FUN_800068d4();
                          display_channel1_menu();
                          tp_i2c_read_status();
                          cVar1 = *puVar4;
                          while (cVar1 != '\0') {
                            tp_i2c_read_status();
                            cVar1 = *puVar4;
                          }
                        }
                      }
                      else {
                        if (((uVar18 < 0x3a) && (0xad < uVar15)) && (uVar15 < 0xe7)) {
                          if (*puVar4 != '\0') {
                            pcVar5[1] = '\x01';
                            FUN_800068d4();
                            display_channel1_menu();
                            tp_i2c_read_status();
                            cVar1 = *puVar4;
                            while (cVar1 != '\0') {
                              tp_i2c_read_status();
                              cVar1 = *puVar4;
                            }
                          }
                        }
                        else {
                          if (((uVar11 - 0xe6 < 0x22) && (0xeb < uVar15)) && (uVar15 < 0x125)) {
                            if (*puVar4 != '\0') {
                              pcVar5[2] = '\0';
                              display_channel1_menu();
                              tp_i2c_read_status();
                              cVar1 = *puVar4;
                              while (cVar1 != '\0') {
                                tp_i2c_read_status();
                                cVar1 = *puVar4;
                              }
                            }
                          }
                          else {
                            if (((uVar11 - 0x108 < 0x20) && (0xeb < uVar15)) && (uVar15 < 0x125)) {
                              if (*puVar4 != '\0') {
                                pcVar5[2] = '\x01';
                                display_channel1_menu();
                                tp_i2c_read_status();
                                cVar1 = *puVar4;
                                while (cVar1 != '\0') {
                                  tp_i2c_read_status();
                                  cVar1 = *puVar4;
                                }
                              }
                            }
                            else {
                              if (((uVar11 - 0x129 < 0x20) && (0xeb < uVar15)) &&
                                 ((uVar15 < 0x125 && (*puVar4 != '\0')))) {
                                pcVar5[2] = '\x02';
                                display_channel1_menu();
                                tp_i2c_read_status();
                                cVar1 = *puVar4;
                                while (cVar1 != '\0') {
                                  tp_i2c_read_status();
                                  cVar1 = *puVar4;
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
              goto LAB_8001dc04;
            }
          }
        } while (*puVar4 == '\0');

        FUN_8000a6c0();  //Copy saved screen rect back to the screen


        tp_i2c_read_status();
        cVar1 = *puVar4;
        while (cVar1 != '\0') {
          tp_i2c_read_status();
          cVar1 = *puVar4;
        }


This is what I made.
Code: [Select]
  //Stay in the menu as long as there is no touch outside the menu 
  while(1)
  {
    //Scan the touch panel for touch
    tp_i2c_read_status();
   
    //Check if there is touch
    if(havetouch)
    {
      //Check if touch within the menu field
      if((xtouch >= 161) && (xtouch <= 344) && (ytouch >= 46) && (ytouch <= 298))
      {
        //Check on channel enable or disable
        if((ytouch >= 62) && (ytouch <= 84))
        {
          //Check on enable
          if((xtouch >= 239) && (xtouch <= 271))
          {
            //Enable the channel
            scopesettings.channel1.enable = 1;
           
            //Display this
            display_channel1_enable_select();
            display_channel1_settings(0);
          }
          //Check on disable
          else if((xtouch >= 291) && (xtouch <= 323))
          {
            //Disable the channel
            scopesettings.channel1.enable = 0;
           
            //Display this
            display_channel1_enable_select();
            display_channel1_settings(0);
          }
        }
        //Check on fft enable or disable
        else if((ytouch >= 124) && (ytouch <= 146))
        {
          //Check on enable
          if((xtouch >= 239) && (xtouch <= 271))
          {
            //Enable the channel
            scopesettings.channel1.fftenable = 1;
           
            //Display this
            display_channel1_fft_show();
          }
          //Check on disable
          else if((xtouch >= 291) && (xtouch <= 323))
          {
            //Disable the channel
            scopesettings.channel1.fftenable = 0;
           
            //Display this
            display_channel1_fft_show();
          }
        }
        //Check on coupling DC or AD
        else if((ytouch >= 188) && (ytouch <= 210))
        {
          //Check on enable
          if((xtouch >= 239) && (xtouch <= 271))
          {
            //Enable the channel
            scopesettings.channel1.coupling = 0;
           
            //Display this
            display_channel1_coupling_select();
            display_channel1_settings(0);
          }
          //Check on disable
          else if((xtouch >= 291) && (xtouch <= 323))
          {
            //Disable the channel
            scopesettings.channel1.coupling = 1;
           
            //Display this
            display_channel1_coupling_select();
            display_channel1_settings(0);
          }
        }
        //Check on probe magnification setting
        else if((ytouch >= 245) && (ytouch <= 283))
        {
          //Check on 1x
          if((xtouch >= 239) && (xtouch <= 259))
          {
            //Enable the channel
            scopesettings.channel1.magnification = 0;
           
            //Display this
            display_channel1_probe_magnification_select();
            display_channel1_settings(0);
          }
          //Check on 10x
          else if((xtouch >= 270) && (xtouch <= 293))
          {
            //Disable the channel
            scopesettings.channel1.magnification = 1;
           
            //Display this
            display_channel1_probe_magnification_select();
            display_channel1_settings(0);
          }
          //Check on 100x
          else if((xtouch >= 299) && (xtouch <= 329))
          {
            //Disable the channel
            scopesettings.channel1.magnification = 2;
           
            //Display this
            display_channel1_probe_magnification_select();
            display_channel1_settings(0);
          }
        }
       
        //Wait until touch is released before checking on a new position
        while(havetouch)
        {
          //Scan the touch panel for touch
          tp_i2c_read_status();
        }
      }
      else
      {
        //Touch outside the menu so quit
        return;
      }
    }
  }


Eventually I will think up a better setup with tables and function pointers. But first see if I can make a working scope ;D

It will be a lot of coding work, but with this first step taken, I'm confident it will happen 8)


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf