Glad you worked it out. I was going to suggest a corrupt SD card.
I've encountered embedded FAT code (elm-chan maybe) that could read files fine, but will fail to write when there was some corruption.
Obviously there is no embedded chkdsk/fsck type functionality, so you have to run that on a PC to fix things.
Glad you worked it out. I was going to suggest a corrupt SD card.
I've encountered embedded FAT code (elm-chan maybe) that could read files fine, but will fail to write when there was some corruption.
Obviously there is no embedded chkdsk/fsck type functionality, so you have to run that on a PC to fix things.
I knew the card was fine, since with the original code it was able to create new pictures, and I also tested creating a file on the card with my PC. That slowed testing things down also, loading the software to the scope, run it, take the card out, insert in the PC, check if file was written, etc. Needed to copy the files to my main disk to be able to open with wxHexeditor, since that refuses to open a file on a disk mounted in the media folder. This is some Linux problem.
But it is fixed and a lot of the functionality is implemented now. Unfortunately I had to quit early yesterday due to a thunderstorm passing by. Today I hope to get the remainder of the view part implemented and see if I can get the save picture and waveform in there too.
Perseverance!
And a lot of time
It takes a lot of skills, perseverance and time to do something like this.
What started as a relative simple fix of my new touch panel having reversed coordinates, became quite the undertaking of reversing the code.
Discovered a lot of crap in the original code, so decided to make my own interpretation of it, but still based on parts of the original code and functionality.
One has to have a good understanding of programming on a low level, and programming what so ever, to be able to do stuff like this. A lot of the time it is very frustrating, looking at output of Ghidra and trying to get an understanding of what some variable is for. Also seeing through what a compiler did to get to the assembly code is not easy.
I read somewhere in this forum that most of the time it is easier and faster to just write your own code then to reverse engineer it, and that is certainly true. Did that for the display part of the code, and also did that for other parts once I saw the logic behind things.
For others who are thinking of doing something like this be prepared to invest a lot of time.
f___
things where going so good, but I ran into a new strange problem
This time I think it really is a FatFs thing. Instead of writing the picture file in a single blob I chopped it into chunks to avoid a lot of memory copies. Also using the same function to write the waveform file, which works without problems.
Here is the part of the code doing it all.
//Open the new file. On failure signal this and quit
result = f_open(&viewfp, viewfilename, FA_CREATE_NEW | FA_WRITE);
//Check if file opened without problems
if(result == FR_OK)
{
//For pictures the bitmap header needs to be written
if(type == VIEW_TYPE_PICTURE)
{
//Write the bitmap header
result = f_write(&viewfp, bmpheader, sizeof(bmpheader), 0);
}
//Check if still ok to proceed
if(result == FR_OK)
{
//Save the settings for the trace portion of the data and write them to the file
scope_prepare_setup_for_file();
//Write the setup data to the file
if((result = f_write(&viewfp, viewfilesetupdata, sizeof(viewfilesetupdata), 0)) == FR_OK)
{
//Write the trace data to the file
//Save the channel 1 sample data
if((result = f_write(&viewfp, (uint8 *)channel1tracebuffer4, 3000, 0)) == FR_OK)
{
//Save the channel 2 sample data
if((result = f_write(&viewfp, (uint8 *)channel2tracebuffer4, 3000, 0)) == FR_OK)
{
//Save the channel 1 display data
if((result = f_write(&viewfp, (uint8 *)channel1ypoints, 1500, 0)) == FR_OK)
{
//Save the channel 2 display data
if((result = f_write(&viewfp, (uint8 *)channel2ypoints, 1500, 0)) == FR_OK)
{
//Finish with an empty blob of data to reach the needed file size
//Clear part of the thumbnail data for this. Is reloaded anyway so does not matter
memset((uint8 *)viewthumbnaildata, 0, 5000);
//Save it to the file
if((result = f_write(&viewfp, (uint8 *)viewthumbnaildata, 5000, 0)) == FR_OK)
{
//For pictures extra code is needed to write the pixel data to the file
if(type == VIEW_TYPE_PICTURE)
{
//Write the pixel data
result = f_write(&viewfp, (uint8 *)maindisplaybuffer, PICTURE_DATA_SIZE, 0);
}
}
}
}
}
}
}
}
//Close the file
f_close(&viewfp);
//Check if all went well
if(result == FR_OK)
{
//Show the saved successful message
scope_display_file_status_message(MESSAGE_SAVE_SUCCESSFUL);
}
else
{
//Signal unable to write to the file
scope_display_file_status_message(MESSAGE_FILE_WRITE_FAILED);
}
}
else
{
//Signal unable to create the file
scope_display_file_status_message(MESSAGE_FILE_OPEN_FAILED);
}
For a waveform file the bitmap header and pixel array is not written, and the file looks good. It is 15000 bytes long and I can see the channel 1 trace data. The settings part looks good to. The other bits are zero, because the code to fill that is not implemented yet. (Only channel 1 is partially done)
For the picture it writes the bitmap header, and it seems to write part of the settings. The file is only 512 bytes long, but I can see that the bitmap header is correct and the first bit of the settings data is also there and correct.
When I skip the writing of the 70 byte header (commented out the first f_write) it works without problems, and the resulting file then contains the pixel data. (last f_write)
So it looks like writing less then a sector and then write more data fails somehow.
I will try a work around for now, where I combine the first two writes and hope that solves it.
A light bulb appeared this early morning
(no emoticon for this
)
The SD card interface needs the data to be 32 bits aligned, since the FIFO works with 32 bits data. So the problem was caused by the bitmap header being 70 bytes, which is not a multiple of 32 bits. This lead to the second write becoming misaligned and thus failed.
The original code did have code for this but I dismissed it as being a bit of bullshit. They allocated a buffer 512 times the original buffer filled that with the data from the buffer, but for this they used memcpy with the size not being the original size but the size times 512. So reading outside the original buffer. The disk_read function is the same so writes outside the original buffer.
int disk_write(int pdrv,byte *buff,int sector,uint count)
{
uint *buffer;
int iVar1;
uint unaff_r4;
switch(pdrv)
{
case 0:
if (((uint)buff & 3) == 0) {
iVar1 = sd_card_write(0,sector,count,buff);
if (iVar1 == 0) {
return 0;
}
}
else {
buffer = malloc(count << 9);
if (buffer != NULL) {
memcpy(buffer,buff,count << 9);
iVar1 = sd_card_write(0,sector,count,(byte *)buffer);
free(buffer);
return (uint)(iVar1 != 0);
}
}
unaff_r4 = 1;
break;
case 1:
case 2:
case 3:
case 4:
break;
default:
unaff_r4 = 4;
}
return unaff_r4;
}
int disk_read(int pdrv,byte *buff,int sector,uint count)
{
uint *buffer;
int iVar1;
if (pdrv == 0)
{
if (((uint)buff & 3) == 0)
{
iVar1 = sd_card_read(0,sector,count,buff);
if (iVar1 == 0)
{
return 0;
}
}
else
{
buffer = malloc(count << 9);
if (buffer != NULL)
{
iVar1 = sd_card_read(0,sector,count,(byte *)buffer);
memcpy(buff,buffer,count << 9);
free(buffer);
return (uint)(iVar1 != 0);
}
}
count = 1;
}
return count;
}
I thought to have it covered with making sure the input buffers to FatFs were 32 bits aligned.
Rewrote the SD card code to be able to handle whatever aligned data. Most optimum is 32 bits aligned of course. For 16 bit it has to do 2 reads or writes and for 8 bits 4 reads or writes per 32 bits FIFO access.
So the problem is solved and the saving of the files works.
Also seeing through what a compiler did to get to the assembly code is not easy.
Here is an example of what I meant with the above about compiler tricks
uVar4 = DAT_800253b8; //0x38E38E39
puVar7 = DAT_800253c8; //0x801C3748 channel 1 trace on screen buffer channel1ypoints[-1]
lVar1 = (longlong)(int)uVar4 * (longlong)(int)((puVar7[1] - 0x2e) * 10);
*(char *)(iVar2 + dataindex + 0x14 + (iVar6 >> 2)) = ((char)(int)(lVar1 >> 0x23) - (char)(lVar1 >> 0x3f)) + '\x05';
In this piece of code the y coordinate is reduced by a factor of 3.61666 and then gets 5 added to it.
Translated to decimal numbers: ((954437177 * ((y - 46) * 10)) / 34359738368) + 5
This results in 434 being reduced to 125 (Max y = 480 - 46 = 434)
The first line does the multiplications and the second line does the divide. (lVar1 >> 0x23) The subtract with the msb is probably for adjusting when result became negative.
So what line of C code results to this pseudo code?
I made a list of what is done and what still needs to be implemented, which is still quite a bit
Implemented so far
- System setup
- Timer interrupt
- Touch panel interface
- Flash reading and writing
- SD card functionality based on FatFs
- FPGA interface functions
- Display library
- User interface
- The main screen with all the menus
- The picture view screen with picture view almost done. (Still needs displaying of the trace data)
- The waveform view screen with waveform view almost done. (Still needs displaying of the trace data)
- Saving of pictures and waveforms
- Trace data handling and displaying
- Long time base settings 50S-100mS. (This is in roll mode and fully done)
- Short time base settings 50mS-10nS. (This is partially implemented. Channel 1 data is fetched and displayed raw. Only part of the processing is implemented.)
- Battery charge measurement
- Power off interrupt for settings save. (Only the interrupt part and not yet tested. Needs the saving of the settings implemented first.)
Still to do
- USB interface
- Saving and loading of the settings to and from flash
Power off interrupt for settings saveBattery charge measurement- Finish the picture and waveform single item view. Needs the trace data processing functionality
- Trace processing and displaying for the short time bases (50mS-10nS)
- Calibration
- Auto set
- Cursor measurements display
- Measurements calculations and displaying
- FFT calculation and displaying
- Firmware update (This means both code within my version as creating an actual firmware update that can be loaded on a scope)
So still a lot of work ahead of me.
First edit to flag battery charge monitoring done on 28th of September 2021 at 18:56:41
Second edit to flag power off interrupt done on 28th of September 2021 at 21:00:00
Edit: These two where reasonable small parts to implement. Battery code was already investigated, so not a lot of work and the power off interrupt part was only investigating four fairly small and simple functions.
Unfortunately not able to work on the project all the time
But today again time for it. Analyzed the settings in the flash memory and found out I'm still not done with finding the variables
They restore data to a point in memory I have not found the code for that makes use of the data. I think it is some calibration data. The rest of the settings are known
This is the function that copies the data loaded from flash address 0x001FD000 to the actual settings
void restore_config_data(uint *address) //0x8035344E
{
undefined2 uVar1;
undefined *puVar2;
int iVar3;
int iVar4;
undefined2 *puVar5;
uint *puVar6;
int iVar7;
undefined *puVar8;
puVar5 = DAT_80027a1c; //0x802F18B0
iVar4 = DAT_80027a18; //0x801FA24C base of measurement settings
iVar3 = DAT_80027a14; //0x80361378 base of settings like screen brightness
puVar2 = DAT_80027a10; //0x8019D5A0 base of scope settings
puVar6 = address + 0x53;
puVar8 = (undefined *)(iVar4 + -1);
iVar7 = 0xc;
// bytes
puVar2[0] = *(undefined *)address; //channel 1 enable 0x8035344E 0
puVar2[3] = *(undefined *)((int)address + 2); // volts/div 0x80353450 1
puVar2[4] = *(undefined *)(address + 1); // fft enable 0x80353452 2
puVar2[1] = *(undefined *)((int)address + 6); // coupling 0x80353454 3
puVar2[2] = *(undefined *)(address + 2); // magnification 0x80353456 4
// bytes
puVar2[0xc] = *(undefined *)((int)address + 10); //channel 2 enable 0x80353458 5
puVar2[0xf] = *(undefined *)(address + 3); // volts/div 0x8035345A 6
puVar2[0x10] = *(undefined *)((int)address + 0xe); // fft enable 0x8035345C 7
puVar2[0xd] = *(undefined *)(address + 4); // coupling 0x8035345E 8
puVar2[0xe] = *(undefined *)((int)address + 0x12); // magnification 0x80353460 9
// byte
puVar2[10] = *(undefined *)(address + 5); //time base 0x80353462 10
// byte
puVar2[0x16] = *(undefined *)((int)address + 0x16); //move speed 0x80353464 11
// bytes
puVar2[0x21] = *(undefined *)(address + 6); //trigger mode 0x80353466 12
puVar2[0x22] = *(undefined *)((int)address + 0x1a); //trigger edge 0x80353468 13
puVar2[0x23] = *(undefined *)(address + 7); //trigger channel 0x8035346A 14
// byte
puVar2[0x42] = *(undefined *)((int)address + 0x1e); //right menu state 0x8035346C 15
// shorts
*(undefined2 *)(puVar2 + 0x24) = *(undefined2 *)(address + 0x14); //0x8035349E trigger position on screen 40
*(undefined2 *)(puVar2 + 0x26) = *(undefined2 *)((int)address + 0x52); //0x803534A0 trigger level screen offset 41
// shorts
*(undefined2 *)(puVar2 + 6) = *(undefined2 *)(address + 0x15); //0x803534A2 channel 1 screen offset 42
*(undefined2 *)(puVar2 + 0x12) = *(undefined2 *)((int)address + 0x56); //0x803534A4 channel 2 screen offset 43
// bytes
*(undefined *)(iVar3 + 2) = *(undefined *)(address + 0x1e); //0x803534C6 screen brightness 60
*(undefined *)(iVar3 + 3) = *(undefined *)((int)address + 0x7a); //0x803534C8 grid brightness 61
*(undefined *)(iVar3 + 4) = *(undefined *)(address + 0x1f); //0x803534CA always 50% trigger 62
*(undefined *)(iVar3 + 7) = *(undefined *)((int)address + 0x7e); //0x803534CC xy display mode 63
//Measurement settings
//Channel 1 enable 12 items bytes
*(undefined *)(iVar4 + 0x100) = *(undefined *)(address + 0x28); //0x803534EE Vmax 80
*(undefined *)(iVar4 + 0x112) = *(undefined *)((int)address + 0xa2); //0x803534F0 Vmin 81
*(undefined *)(iVar4 + 0x122) = *(undefined *)(address + 0x29); //0x803534F2 Vavg 82
*(undefined *)(iVar4 + 0x132) = *(undefined *)((int)address + 0xa6); //0x803534F4 Vrms 83
*(undefined *)(iVar4 + 0x142) = *(undefined *)(address + 0x2a); //0x803534F6 Vpp 84
*(undefined *)(iVar4 + 0x152) = *(undefined *)((int)address + 0xaa); //0x803534F8 Vp 85
*(undefined *)(iVar4 + 0x162) = *(undefined *)(address + 0x2b); //0x803534FA Freq 86
*(undefined *)(iVar4 + 0x172) = *(undefined *)((int)address + 0xae); //0x803534FC Cycle 87
*(undefined *)(iVar4 + 0x182) = *(undefined *)(address + 0x2c); //0x803534FE Tim+ 88
*(undefined *)(iVar4 + 0x192) = *(undefined *)((int)address + 0xb2); //0x80353500 Tim- 89
*(undefined *)(iVar4 + 0x1a2) = *(undefined *)(address + 0x2d); //0x80353502 Duty+ 90
*(undefined *)(iVar4 + 0x1b2) = *(undefined *)((int)address + 0xb6); //0x80353504 Duty- 91
//Channel 2 enable 12 items bytes
*(undefined *)(iVar4 + 0x1c2) = *(undefined *)(address + 0x2e); //0x80353506 Vmax 92
*(undefined *)(iVar4 + 0x1d2) = *(undefined *)((int)address + 0xba); //0x80353508 Vmin 93
*(undefined *)(iVar4 + 0x1e2) = *(undefined *)(address + 0x2f); //0x8035350A Vavg 94
*(undefined *)(iVar4 + 0x1f2) = *(undefined *)((int)address + 0xbe); //0x8035350C Vrms 95
*(undefined *)(iVar4 + 0x202) = *(undefined *)(address + 0x30); //0x8035350E Vpp 96
*(undefined *)(iVar4 + 0x212) = *(undefined *)((int)address + 0xc2); //0x80353510 Vp 97
*(undefined *)(iVar4 + 0x232) = *(undefined *)(address + 0x31); //0x80353512 Freq 98
*(undefined *)(iVar4 + 0x242) = *(undefined *)((int)address + 0xc6); //0x80353514 Cycle 99
*(undefined *)(iVar4 + 0x252) = *(undefined *)(address + 0x32); //0x80353516 Tim+ 100
*(undefined *)(iVar4 + 0x262) = *(undefined *)((int)address + 0xca); //0x80353518 Tim- 101
*(undefined *)(iVar4 + 0x272) = *(undefined *)(address + 0x33); //0x8035351A Duty+ 102
*(undefined *)(iVar4 + 0x282) = *(undefined *)((int)address + 0xce); //0x8035351C Duty- 103
//Channel 1 calibration data shorts
puVar5[0] = *(undefined2 *)(address + 0x3c); //0x802F18B0 = 0x8035353E channel1_calibration_factor 120
puVar5[1] = *(undefined2 *)((int)address + 0xf2); //0x802F18B2 = 0x80353540 channel1_calibration_data[0]
puVar5[2] = *(undefined2 *)(address + 0x3d); //0x802F18B4 = 0x80353542
puVar5[3] = *(undefined2 *)((int)address + 0xf6); //0x802F18B6 = 0x80353544
puVar5[4] = *(undefined2 *)(address + 0x3e); //0x802F18B8 = 0x80353546
puVar5[5] = *(undefined2 *)((int)address + 0xfa); //0x802F18BA = 0x80353548
puVar5[6] = *(undefined2 *)(address + 0x3f); //0x802F18BC = 0x8035354A channel1_calibration_data[5] (needs to be copied into [6]!!)
//Channel 2 calibration data shorts
puVar5[7] = *(undefined2 *)((int)address + 0xfe); //0x802F18BE = 0x8035354C channel2_calibration_factor 127
puVar5[8] = *(undefined2 *)(address + 0x40); //0x802F18C0 = 0x8035354E channel2_calibration_data[0]
puVar5[9] = *(undefined2 *)((int)address + 0x102); //0x802F18C2 = 0x80353550
puVar5[10] = *(undefined2 *)(address + 0x41); //0x802F18C4 = 0x80353552
puVar5[0xb] = *(undefined2 *)((int)address + 0x106); //0x802F18C6 = 0x80353554
puVar5[0xc] = *(undefined2 *)(address + 0x42); //0x802F18C8 = 0x80353556
puVar5[0xd] = *(undefined2 *)((int)address + 0x10a); //0x802F18CA = 0x80353558 channel2_calibration_data[5] 133
//Some other calibration data that still needs to be investigated
// shorts
puVar5[0xe] = *(undefined2 *)(address + 0x43); //0x802F18CC = 0x8035355A 134
puVar5[0xf] = *(undefined2 *)((int)address + 0x10e); //0x802F18CE = 0x8035355C
puVar5[0x10] = *(undefined2 *)(address + 0x44); //0x802F18D0 = 0x8035355E
puVar5[0x11] = *(undefined2 *)((int)address + 0x112); //0x802F18D2 = 0x80353560
// bytes
*(undefined *)(puVar5 + 0x12) = *(undefined *)(address + 0x45); //0x802F18D4 = 0x80353562
*(undefined *)((int)puVar5 + 0x25) = *(undefined *)((int)address + 0x116); //0x802F18D5 = 0x80353564
*(undefined *)(puVar5 + 0x13) = *(undefined *)(address + 0x46); //0x802F18D6 = 0x80353566
*(undefined *)((int)puVar5 + 0x27) = *(undefined *)((int)address + 0x11a); //0x802F18D7 = 0x80353568
*(undefined *)(puVar5 + 0x14) = *(undefined *)(address + 0x47); //0x802F18D8 = 0x8035356A
*(undefined *)((int)puVar5 + 0x29) = *(undefined *)((int)address + 0x11e); //0x802F18D9 = 0x8035356C
// shorts
puVar5[0x15] = *(undefined2 *)(address + 0x48); //0x802F18DA = 0x8035356E
puVar5[0x16] = *(undefined2 *)((int)address + 0x122); //0x802F18DC = 0x80353570
puVar5[0x17] = *(undefined2 *)(address + 0x49); //0x802F18DE = 0x80353572
puVar5[0x18] = *(undefined2 *)((int)address + 0x126); //0x802F18E0 = 0x80353574
puVar5[0x19] = *(undefined2 *)(address + 0x4a); //0x802F18E2 = 0x80353576
puVar5[0x1a] = *(undefined2 *)((int)address + 0x12a); //0x802F18E4 = 0x80353578
// bytes
*(undefined *)(puVar5 + 0x1b) = *(undefined *)(address + 0x4b); //0x802F18E6 = 0x8035357A
*(undefined *)((int)puVar5 + 0x37) = *(undefined *)((int)address + 0x12e); //0x802F18E7 = 0x8035357C
*(undefined *)(puVar5 + 0x1c) = *(undefined *)(address + 0x4c); //0x802F18E8 = 0x8035357E
*(undefined *)((int)puVar5 + 0x39) = *(undefined *)((int)address + 0x132); //0x802F18E9 = 0x80353580
*(undefined *)(puVar5 + 0x1d) = *(undefined *)(address + 0x4d); //0x802F18EA = 0x80353582
*(undefined *)((int)puVar5 + 0x3b) = *(undefined *)((int)address + 0x136); //0x802F18EB = 0x80353584
// shorts
puVar5[0x1e] = *(undefined2 *)(address + 0x4e); //0x802F18EC = 0x80353586
puVar5[0x1f] = *(undefined2 *)((int)address + 0x13a); //0x802F18EE = 0x80353588
puVar5[0x20] = *(undefined2 *)(address + 0x4f); //0x802F18F0 = 0x8035358A
puVar5[0x21] = *(undefined2 *)((int)address + 0x13e); //0x802F18F2 = 0x8035358C
puVar5[0x22] = *(undefined2 *)(address + 0x50); //0x802F18F4 = 0x8035358E
uVar1 = *(undefined2 *)((int)address + 0x142); // 0x80353590
// short
puVar5[0x23] = uVar1; //0x802F18F6 = 0x80353590 time cursor enable??? for what
// byte
*(char *)(iVar4 + 0x292) = (char)uVar1; //0x801FA4DE = 0x80353590 time cursor enable 161
// shorts
*(undefined2 *)(iVar4 + 0x294) = *(undefined2 *)(address + 0x51); //0x801FA4E0 = 0x80353592 time cursor 1 position 162
*(undefined2 *)(iVar4 + 0x296) = *(undefined2 *)((int)address + 0x146); //0x801FA4E2 = 0x80353594 time cursor 2 position 163
// byte
*(undefined *)(iVar4 + 0x29a) = *(undefined *)(address + 0x52); //0x801FA4E6 = 0x80353596 volt cursor enable 164
// shorts
*(undefined2 *)(iVar4 + 0x29c) = *(undefined2 *)((int)address + 0x14a); //0x801FA4E8 = 0x80353598 volt cursor 1 position 165
*(undefined2 *)(iVar4 + 0x29e) = *(undefined2 *)(address + 0x53); //0x801FA4EA = 0x8035359A volt cursor 2 position 166
//12 items times 2
//Load and store bytes
//Source start 0x8035359C
//Destination start 0x801FA24C
//This is the list of enabled measurement items in the order of displaying
do {
iVar7 = iVar7 + -1;
puVar8[1] = *(undefined *)((int)puVar6 + 2);
puVar6 = puVar6 + 1;
puVar8 = puVar8 + 2;
*puVar8 = *(undefined *)puVar6;
} while (iVar7 != 0);
//System OK flag (0x1432) short
*(undefined2 *)(puVar2 + 0x44) = *(undefined2 *)(address + 100); //0x8019D5E4 = 803535DE
return;
}
This is my version of it
void scope_restore_config_data(void)
{
uint32 channel;
uint32 index;
uint16 *ptr;
//Restore the channel 1 settings
scopesettings.channel1.enable = settingsworkbuffer[0];
scopesettings.channel1.coupling = settingsworkbuffer[3];
scopesettings.channel1.magnification = settingsworkbuffer[4];
scopesettings.channel1.voltperdiv = settingsworkbuffer[1];
scopesettings.channel1.fftenable = settingsworkbuffer[2];
scopesettings.channel1.traceoffset = settingsworkbuffer[42];
//Restore the channel 2 settings
scopesettings.channel2.enable = settingsworkbuffer[5];
scopesettings.channel2.coupling = settingsworkbuffer[8];
scopesettings.channel2.magnification = settingsworkbuffer[9];
scopesettings.channel2.voltperdiv = settingsworkbuffer[6];
scopesettings.channel2.fftenable = settingsworkbuffer[7];
scopesettings.channel2.traceoffset = settingsworkbuffer[43];
//Restore trigger settings
scopesettings.triggermode = settingsworkbuffer[12];
scopesettings.triggeredge = settingsworkbuffer[13];
scopesettings.triggerchannel = settingsworkbuffer[14];
scopesettings.triggerposition = settingsworkbuffer[40];
scopesettings.triggeroffset = settingsworkbuffer[41];
//Restore the time base
scopesettings.timeperdiv = settingsworkbuffer[10];
//Restore the move speed
scopesettings.movespeed = settingsworkbuffer[11];
//Restore the right menu state
scopesettings.rightmenustate = settingsworkbuffer[15];
//Restore screen brightness, grid brightness, always 50% trigger and xy display mode
scopesettings.screenbrightness = settingsworkbuffer[60];
scopesettings.gridbrightness = settingsworkbuffer[61];
scopesettings.alwaystrigger50 = settingsworkbuffer[62];
scopesettings.xymodedisplay = settingsworkbuffer[63];
//Restore the time cursor settings
scopesettings.timecursorsenable = settingsworkbuffer[161];
scopesettings.timecursor1position = settingsworkbuffer[162];
scopesettings.timecursor2position = settingsworkbuffer[163];
//Restore the volt cursor settings
scopesettings.voltcursorsenable = settingsworkbuffer[164];
scopesettings.voltcursor1position = settingsworkbuffer[165];
scopesettings.voltcursor2position = settingsworkbuffer[166];
//Point to the first measurement enable setting
ptr = &settingsworkbuffer[80];
//Restore the measurements enable states
for(channel=0;channel<2;channel++)
{
//12 measurements per channel
for(index=0;index<12;index++)
{
//Copy the current measurement state and point to the next one
scopesettings.measuresstate[channel][index] = *ptr++;
}
}
//Restore the calibration data
channel1_calibration_factor = settingsworkbuffer[120];
channel2_calibration_factor = settingsworkbuffer[127];
//Point to the first channel calibration value
ptr = &settingsworkbuffer[121];
//Copy the saved values to the working set
for(index=0;index<6;index++,ptr++)
{
//Copy the data for both channels
channel1_calibration_data[index] = ptr[0];
channel2_calibration_data[index] = ptr[7];
}
//The last entry is a copy of the fore last value
//Different from the original code where they use a switch statement instead of an array index for getting the data
channel1_calibration_data[6] = settingsworkbuffer[126];
channel2_calibration_data[6] = settingsworkbuffer[133];
//Need the system ok flag (settingsworkbuffer[200])
}
Need to implement the counter part of it for writing to the flash and need to hook it in to the main code for testing.
When that is done it is back to analyzing and reversing code again, since all the remaining items on the to do list are still like mars. Only touched on the surface
Edit: Stupid me keeps making the copy, paste not modify errors. Forgot to change the scopesettings.channel1. to scopesettings.channel2.
Cursor measurements done.
Way simpler code then the original code. Just a case of use your brain and some functions
typedef struct tagTimeCalcData TIMECALCDATA, *PTIMECALCDATA;
typedef struct tagVoltCalcData VOLTCALCDATA, *PVOLTCALCDATA;
struct tagTimeCalcData
{
uint32 mul_factor;
uint8 time_scale;
uint8 freq_scale;
};
struct tagVoltCalcData
{
uint32 mul_factor;
uint8 volt_scale;
};
const TIMECALCDATA time_calc_data[21] =
{
{ 100, 3, 3 }, // 50mS/div
{ 40000, 2, 4 }, // 20mS/div
{ 20000, 2, 4 }, // 10mS/div
{ 10000, 2, 4 }, // 5mS/div
{ 4000, 2, 4 }, // 2mS/div
{ 2000, 2, 4 }, // 1mS/div
{ 1000, 2, 4 }, //500uS/div
{ 400, 2, 4 }, //200uS/div
{ 200, 2, 4 }, //100uS/div
{ 100, 2, 4 }, // 50uS/div
{ 40000, 1, 5 }, // 20uS/div
{ 20000, 1, 5 }, // 10uS/div
{ 10000, 1, 5 }, // 5uS/div
{ 4000, 1, 5 }, // 2uS/div
{ 2000, 1, 5 }, // 1uS/div
{ 1000, 1, 5 }, //500nS/div
{ 500, 1, 5 }, //250nS/div
{ 200, 1, 5 }, //100nS/div
{ 100, 1, 5 }, // 50nS/div
{ 50000, 0, 6 }, // 25nS/div
{ 20000, 0, 6 } // 10nS/div
};
const VOLTCALCDATA volt_calc_data[3][7] =
{
{ { 10000, 3 }, { 5000, 3 }, { 2000, 3 }, { 1000, 3 }, { 400, 3 }, { 200, 3 }, { 100, 3 } },
{ { 100000, 3 }, { 50000, 3 }, { 20000, 3 }, { 10000, 3 }, { 4000, 3 }, { 2000, 3 }, { 1000, 3 } },
{ { 1000, 4 }, { 500, 4 }, { 200, 4 }, { 100, 4 }, { 40, 4 }, { 20, 4 }, { 10, 4 } }
};
const char *magnitude_scaler[8] = { "p", "n", "u", "m", "", "K", "M", "G"};
void scope_display_cursor_measurements(void)
{
uint32 height = 5;
uint32 ch1ypos = 52;
uint32 ch2ypos = 52;
uint32 delta;
char displaytext[10];
//Check if need to do anything here
if(scopesettings.timecursorsenable || (scopesettings.voltcursorsenable && (scopesettings.channel1.enable || scopesettings.channel2.enable)))
{
//Check if time cursor is enabled
if(scopesettings.timecursorsenable)
{
//Add height for two text lines
height += 32;
//Shift the voltage text positions down
ch1ypos += 32;
ch2ypos += 32;
}
//Check if volt cursor is enabled
if(scopesettings.voltcursorsenable)
{
//Check if channel 1 is enabled
if(scopesettings.channel1.enable)
{
//Add height for one text line
height += 16;
//Shift the channel 2 voltage text down
ch2ypos += 16;
}
//Check if channel 2 is enabled
if(scopesettings.channel2.enable)
{
//Add height for one text line
height += 16;
}
}
//Set gray background for the cursor measurements
display_set_fg_color(0x00404040);
//Draw rounded rectangle depending on what is enabled.
display_fill_rounded_rect(5, 49, 102, height, 2);
//Use white text and font_0
display_set_fg_color(0x00FFFFFF);
display_set_font(&font_0);
//Check if time cursor is enabled
if(scopesettings.timecursorsenable)
{
//Time texts are always on the top two lines
//Get the time delta based on the cursor positions
delta = scopesettings.timecursor2position - scopesettings.timecursor1position;
//Get the time calculation data for this time base setting. Only for the short time bases so take of the first 9
PTIMECALCDATA tcd = (PTIMECALCDATA)&time_calc_data[scopesettings.timeperdiv - 9];
//For the time multiply with the scaling factor and display based on the time scale
delta *= tcd->mul_factor;
//Format the time for displaying
scope_print_value(displaytext, delta, tcd->time_scale, "T ", "S");
display_text(10, 52, displaytext);
//Calculate the frequency for this time. Need to adjust for stay within 32 bits
delta /= 10;
delta = 1000000000/ delta;
//Format the frequency for displaying
scope_print_value(displaytext, delta, tcd->freq_scale, "F ", "Hz");
display_text(10, 68, displaytext);
}
//Check if volt cursor is enabled
if(scopesettings.voltcursorsenable)
{
PVOLTCALCDATA vcd;
uint32 volts;
//Get the volts delta based on the cursor positions
delta = scopesettings.voltcursor2position - scopesettings.voltcursor1position;
//Check if channel 1 is enabled
if(scopesettings.channel1.enable)
{
//Calculate the voltage based on the channel 1 settings
vcd = (PVOLTCALCDATA)&volt_calc_data[scopesettings.channel1.magnification][scopesettings.channel1.voltperdiv];
//Multiply with the scaling factor for the channel 1 settings
volts = delta * vcd->mul_factor;
//Channel 1 text has a variable position
//Format the voltage for displaying
scope_print_value(displaytext, volts, vcd->volt_scale, "V1 ", "V");
display_text(10, ch1ypos, displaytext);
}
//Check if channel 2 is enabled
if(scopesettings.channel2.enable)
{
//Calculate the voltage based on the channel 2 settings
vcd = (PVOLTCALCDATA)&volt_calc_data[scopesettings.channel2.magnification][scopesettings.channel2.voltperdiv];
//Multiply with the scaling factor for the channel 2 settings
volts = delta * vcd->mul_factor;
//Channel 2 text has a variable position
//Format the voltage for displaying
scope_print_value(displaytext, volts, vcd->volt_scale, "V2 ", "V");
display_text(10, ch2ypos, displaytext);
}
}
}
}
//----------------------------------------------------------------------------------------------------------------------------------
//Simple non optimized function for string copy that returns the position of the terminator
//----------------------------------------------------------------------------------------------------------------------------------
char *strcpy(char *dst, const char *src)
{
while(*src)
{
*dst++ = *src++;
}
//Terminate the copy
*dst = 0;
return(dst);
}
//----------------------------------------------------------------------------------------------------------------------------------
void scope_print_value(char *buffer, uint32 value, uint32 scale, char *header, char *sign)
{
//Copy the header into the string buffer
buffer = strcpy(buffer, header);
//Need to find the magnitude scale for the input
//The calculations are based on fixed point
while(value >= 100000)
{
//Skip to the next magnitude
scale++;
//Bring the value in range
value /= 1000;
}
//Format the remainder for displaying. Only 3 digits are allowed to be displayed
if(value < 1000)
{
//Less then 1000 means x.yy
buffer = scope_print_decimal(buffer, value, 2);
}
else if(value < 10000)
{
//More then 1000 but less then 10000 means xx.y
value /= 10;
buffer = scope_print_decimal(buffer, value, 1);
}
else
{
//More then 10000 and less then 100000 means xxx
value /= 100;
buffer = scope_print_decimal(buffer, value, 0);
}
//Make sure scale is not out of range
if(scale > 7)
{
scale = 7;
}
//Add the magnitude scaler
buffer = strcpy(buffer, magnitude_scaler[scale]);
//Add the type of measurement sign
strcpy(buffer, sign);
}
//----------------------------------------------------------------------------------------------------------------------------------
char *scope_print_decimal(char *buffer, uint32 value, uint32 decimals)
{
char b[12];
uint32 i = 12; //Start beyond the array since the index is pre decremented
uint32 s;
//For value 0 no need to do the work
if(value == 0)
{
//Value is zero so just set 0 character
b[--i] = '0';
}
else
{
//Process the digits
while(value)
{
//Set current digit to decreased index
b[--i] = (value % 10) + '0';
//Check if decimal point needs to be placed
if(i == 12 - decimals)
{
//If so put it in
b[--i] = '.';
}
//Take of the current digit
value /= 10;
}
}
//Determine the size of the string
s = 12 - i;
//Copy to the buffer
memcpy(buffer, &b[i], s);
//terminate the string
buffer[s] = 0;
//Return the position of the terminator to allow appending
return(&buffer[s]);
}
Tried using assembly versions of strcpy and strlen, but for some reason it did not work on the target. No problem under linux with the standard library functions, so I wrote my own strcpy, that returns a pointer to the end of the destination string instead of the beginning.
Checked it with different settings and cursor positions and it looks good.
So on to the next bit.
Implemented so far
- System setup
- Timer interrupt
- Touch panel interface
- Flash reading and writing
- SD card functionality based on FatFs
- FPGA interface functions
- Display library
- Battery charge measurement
- Power off interrupt for settings save
- Saving and loading of the settings to and from flash
- Cursor measurements display
- User interface
- The main screen with all the menus
- The picture view screen with picture view almost done. (Still needs displaying of the trace data)
- The waveform view screen with waveform view almost done. (Still needs displaying of the trace data)
- Saving of pictures and waveforms
- Trace data handling and displaying
- Long time base settings 50S-100mS. (This is in roll mode and fully done)
- Short time base settings 50mS-10nS. (This is partially implemented. Channel 1 data is fetched and displayed raw. Only part of the processing is implemented.)
Still to do
- USB interface
- Finish the picture and waveform single item view. Needs the trace data processing functionality
- Trace processing and displaying for the short time bases (50mS-10nS)
- Calibration
- Auto set
- Measurements calculations and displaying
- FFT calculation and displaying
- Firmware update (This means both code within my version as creating an actual firmware update that can be loaded on a scope)
Returned to the trace data processing, even though I wrote earlier I would skip it and write my own FPGA implementation.
To get a first working version of this open scope firmware, and have people test it, it is easier to stick with the original FPGA for now.
So I dove into the 25 and 10nS/div code. There are two functions per channel doing the work. Had to revert to my emulator to get to the bottom of the first function because the Ghidra output did not make it clear on what is being done.
This is the untouched C output
void scope_pre_process_ch1_25ns_data(void)
{
undefined2 uVar1;
int iVar2;
int iVar3;
uint *puVar4;
uint *puVar5;
uint *puVar6;
uint *puVar7;
uint **ppuVar8;
uint **ppuVar9;
byte *pbVar10;
undefined2 *puVar11;
uint uVar12;
uint uVar13;
byte bVar14;
uint uVar15;
int iVar16;
short *psVar17;
byte bVar18;
undefined2 uVar19;
uint *puVar20;
uint *puVar21;
uint uVar22;
uint uVar23;
uint uVar24;
bool bVar25;
bool bVar26;
puVar7 = DAT_8000470c;
puVar21 = DAT_80004708;
iVar16 = 0x2e8;
*(undefined2 *)((int)DAT_8000470c + 2) = *(undefined2 *)DAT_80004708;
uVar19 = *(undefined2 *)((int)puVar21 + 2);
puVar11 = (undefined2 *)((int)puVar7 + 2);
do {
uVar1 = *(undefined2 *)(puVar21 + 1);
puVar11[2] = uVar19;
uVar19 = *(undefined2 *)((int)puVar21 + 6);
iVar16 = iVar16 + -1;
puVar11 = puVar11 + 4;
*puVar11 = uVar1;
iVar3 = DAT_8000471c;
iVar2 = DAT_80004718;
puVar21 = puVar21 + 1;
} while (iVar16 != 0);
*(undefined2 *)(DAT_80004714 + 2) = *DAT_80004710;
uVar15 = DAT_80004720;
uVar12 = 0;
if (*(short *)(iVar2 + 0x1c) == 0) {
do {
uVar13 = (uint)*(ushort *)(iVar3 + uVar12 * 2);
if (*(ushort *)(iVar2 + 0x1e) < uVar13) {
puVar21 = (uint *)(uVar13 - *(ushort *)(iVar2 + 0x1e));
*(short *)(puVar7 + uVar12) = (short)puVar21;
}
else {
puVar21 = puVar7 + uVar12;
*(undefined2 *)puVar21 = 0;
}
uVar12 = uVar12 + 1 & 0xfffeffff;
} while (uVar12 < uVar15);
}
else {
do {
psVar17 = (short *)(iVar3 + uVar12 * 2);
puVar21 = puVar7 + uVar12;
uVar12 = uVar12 + 2 & 0xfffeffff;
*(short *)puVar21 = *psVar17 + *(short *)(iVar2 + 0x1e);
*(short *)(puVar21 + 1) = psVar17[1] + *(short *)(iVar2 + 0x1e);
} while (uVar12 < uVar15);
}
uVar12 = DAT_80004724;
puVar5 = DAT_80004708;
puVar7 = DAT_8000470c;
if (3 < DAT_80004724) {
puVar20 = (uint *)((uint)DAT_80004708 & 3);
uVar13 = DAT_80004724;
puVar21 = puVar20;
if (puVar20 != NULL) {
bVar14 = *(byte *)DAT_8000470c;
puVar6 = (uint *)((int)DAT_8000470c + 1);
if (puVar20 < (uint *)0x3) {
puVar6 = (uint *)((int)DAT_8000470c + 2);
puVar21 = (uint *)(uint)*(byte *)(uint *)((int)DAT_8000470c + 1);
}
puVar4 = (uint *)((int)DAT_80004708 + 1);
*(byte *)DAT_80004708 = bVar14;
puVar7 = puVar6;
if (puVar20 < (uint *)0x2) {
puVar7 = (uint *)((int)puVar6 + 1);
bVar14 = *(byte *)puVar6;
}
puVar6 = puVar4;
if (puVar20 < (uint *)0x3) {
puVar6 = (uint *)((int)puVar5 + 2);
*(byte *)puVar4 = (byte)puVar21;
}
uVar13 = (int)puVar20 + (uVar12 - 4);
puVar5 = puVar6;
if (puVar20 < (uint *)0x2) {
puVar5 = (uint *)((int)puVar6 + 1);
*(byte *)puVar6 = bVar14;
}
}
uVar15 = (uint)puVar7 & 3;
if (uVar15 == 0) {
while (uVar12 = uVar13 - 0x20, 0x1f < uVar13) {
uVar15 = puVar7[1];
uVar13 = puVar7[2];
uVar22 = puVar7[3];
*puVar5 = *puVar7;
puVar5[1] = uVar15;
puVar5[2] = uVar13;
puVar5[3] = uVar22;
uVar15 = puVar7[4];
uVar13 = puVar7[5];
uVar22 = puVar7[6];
uVar23 = puVar7[7];
puVar7 = puVar7 + 8;
puVar5[4] = uVar15;
puVar5[5] = uVar13;
puVar5[6] = uVar22;
puVar5[7] = uVar23;
puVar5 = puVar5 + 8;
uVar13 = uVar12;
}
if ((bool)((byte)(uVar12 >> 4) & 1)) {
uVar15 = *puVar7;
uVar22 = puVar7[1];
uVar23 = puVar7[2];
uVar24 = puVar7[3];
puVar7 = puVar7 + 4;
*puVar5 = uVar15;
puVar5[1] = uVar22;
puVar5[2] = uVar23;
puVar5[3] = uVar24;
puVar5 = puVar5 + 4;
}
if ((int)(uVar13 << 0x1c) < 0) {
uVar15 = *puVar7;
uVar22 = puVar7[1];
puVar7 = puVar7 + 2;
*puVar5 = uVar15;
puVar5[1] = uVar22;
puVar5 = puVar5 + 2;
}
puVar20 = puVar5;
puVar21 = puVar7;
if ((bool)((byte)(uVar12 >> 2) & 1)) {
puVar21 = puVar7 + 1;
uVar15 = *puVar7;
puVar20 = puVar5 + 1;
*puVar5 = uVar15;
}
uVar19 = (undefined2)uVar15;
if ((uVar12 & 3) != 0) {
bVar26 = (bool)((byte)(uVar12 >> 1) & 1);
uVar13 = uVar13 << 0x1f;
bVar25 = (int)uVar13 < 0;
puVar7 = puVar21;
if (bVar26) {
puVar7 = (uint *)((int)puVar21 + 2);
uVar19 = *(undefined2 *)puVar21;
}
if (bVar25) {
uVar13 = (uint)*(byte *)puVar7;
}
puVar21 = puVar20;
if (bVar26) {
puVar21 = (uint *)((int)puVar20 + 2);
*(undefined2 *)puVar20 = uVar19;
}
if (bVar25) {
*(byte *)puVar21 = (byte)uVar13;
}
return;
}
return;
}
uVar12 = uVar13 - 4;
if (3 < uVar13) {
ppuVar8 = (uint **)((int)puVar7 - uVar15);
puVar21 = *ppuVar8;
puVar7 = puVar5;
if (uVar15 == 2) {
do {
ppuVar9 = ppuVar8;
uVar15 = (uint)puVar21 >> 0x10;
ppuVar8 = ppuVar9 + 1;
puVar21 = *ppuVar8;
bVar25 = 3 < uVar12;
uVar12 = uVar12 - 4;
uVar15 = uVar15 | (int)puVar21 << 0x10;
puVar5 = puVar7 + 1;
*puVar7 = uVar15;
puVar7 = puVar5;
} while (bVar25);
puVar7 = (uint *)((int)ppuVar9 + 6);
}
else {
if (uVar15 < 3) {
do {
ppuVar9 = ppuVar8;
uVar15 = (uint)puVar21 >> 8;
ppuVar8 = ppuVar9 + 1;
puVar21 = *ppuVar8;
bVar25 = 3 < uVar12;
uVar12 = uVar12 - 4;
uVar15 = uVar15 | (int)puVar21 << 0x18;
puVar5 = puVar7 + 1;
*puVar7 = uVar15;
puVar7 = puVar5;
} while (bVar25);
puVar7 = (uint *)((int)ppuVar9 + 5);
}
else {
do {
ppuVar9 = ppuVar8;
uVar15 = (uint)puVar21 >> 0x18;
ppuVar8 = ppuVar9 + 1;
puVar21 = *ppuVar8;
bVar25 = 3 < uVar12;
uVar12 = uVar12 - 4;
uVar15 = uVar15 | (int)puVar21 << 8;
puVar5 = puVar7 + 1;
*puVar7 = uVar15;
puVar7 = puVar5;
} while (bVar25);
puVar7 = (uint *)((int)ppuVar9 + 7);
}
}
}
}
bVar18 = (byte)puVar21;
bVar14 = (byte)uVar15;
bVar26 = (bool)((byte)(uVar12 >> 1) & 1);
uVar12 = uVar12 << 0x1f;
bVar25 = (int)uVar12 < 0;
if (bVar26) {
pbVar10 = (byte *)((int)puVar7 + 1);
bVar14 = *(byte *)puVar7;
puVar7 = (uint *)((int)puVar7 + 2);
bVar18 = *pbVar10;
}
if (bVar25) {
uVar12 = (uint)*(byte *)puVar7;
}
if (bVar26) {
pbVar10 = (byte *)((int)puVar5 + 1);
*(byte *)puVar5 = bVar14;
puVar5 = (uint *)((int)puVar5 + 2);
*pbVar10 = bVar18;
}
if (bVar25) {
*(byte *)puVar5 = (byte)uVar12;
}
return;
}
And this is the assembly, which tells a bit more, but still tough to figure out.
**************************************************************
* FUNCTION *
**************************************************************
void __stdcall scope_pre_process_ch1_25ns_data(void)
void <VOID> <RETURN>
undefined4 Stack[-0x18]:4 local_18 XREF[2]: 80004614(W),
800046b0(*)
scope_pre_process_ch1_25ns_data XREF[1]: scope_get_short_timebase_data:80
8000460c e0 03 2d e9 stmdb sp!,{r5 r6 r7 r8 r9}
80004610 f0 20 9f e5 ldr r2,[DAT_80004708] = 8019D5EAh
80004614 04 40 2d e5 str r4,[sp,#local_18]!
80004618 b0 c0 d2 e1 ldrh r12,[r2,#0x0]=>DAT_8019d5ea
8000461c e8 00 9f e5 ldr r0,[DAT_8000470c] = 801AEF2Ah
80004620 ba 3f a0 e3 mov r3,#0x2e8
80004624 b2 c0 c0 e1 strh r12,[r0,#0x2]=>DAT_801aef2c
80004628 b2 c0 d2 e1 ldrh r12,[r2,#0x2]=>DAT_8019d5ec
8000462c 02 10 80 e2 add r1,r0,#0x2
LAB_80004630 XREF[1]: 80004644(j)
80004630 b4 40 f2 e1 ldrh r4,[r2,#0x4]!=>DAT_8019d5ee
80004634 b4 c0 c1 e1 strh r12,[r1,#0x4]=>DAT_801aef30
80004638 b2 c0 d2 e1 ldrh r12,[r2,#0x2]=>DAT_8019d5f0
8000463c 01 30 53 e2 subs r3,r3,#0x1
80004640 b8 40 e1 e1 strh r4,[r1,#0x8]!=>DAT_801aef34
80004644 f9 ff ff 1a bne LAB_80004630
80004648 c0 10 9f e5 ldr r1,[DAT_80004710] = 8019E18Ch
8000464c c0 c0 9f e5 ldr r12,[DAT_80004714] = 801B066Eh
80004650 b0 10 d1 e1 ldrh r1,[r1,#0x0]=>DAT_8019e18c
80004654 bc 20 9f e5 ldr r2,[DAT_80004718] = 802F18B0h
80004658 bc 50 9f e5 ldr r5,[DAT_8000471c] = 8019ED5Ah
8000465c b2 10 cc e1 strh r1,[r12,#0x2]=>DAT_801b0670
80004660 bc 11 d2 e1 ldrh r1,[r2,#0x1c]=>DAT_802f18cc
80004664 b4 30 9f e5 ldr r3,[DAT_80004720] = 000005D2h
80004668 00 00 51 e3 cmp r1,#0x0
8000466c 00 10 a0 e3 mov r1,#0x0
80004670 00 40 a0 03 moveq r4,#0x0
80004674 13 00 00 0a beq LAB_800046c8
LAB_80004678 XREF[1]: 800046ac(j)
80004678 be 71 d2 e1 ldrh r7,[r2,#0x1e]=>DAT_802f18ce
8000467c 02 60 81 e2 add r6,r1,#0x2
80004680 81 40 85 e0 add r4,r5,r1, lsl #0x1
80004684 b0 80 d4 e1 ldrh r8,[r4,#0x0]=>DAT_8019ed5a
80004688 01 c1 80 e0 add r12,r0,r1, lsl #0x2
8000468c 01 18 c6 e3 bic r1,r6,#0x10000
80004690 07 60 88 e0 add r6,r8,r7
80004694 b0 60 cc e1 strh r6,[r12,#0x0]=>DAT_801aef2a
80004698 b2 40 d4 e1 ldrh r4,[r4,#0x2]=>DAT_8019ed5c
8000469c be 61 d2 e1 ldrh r6,[r2,#0x1e]=>DAT_802f18ce
800046a0 03 00 51 e1 cmp r1,r3
800046a4 06 40 84 e0 add r4,r4,r6
800046a8 b4 40 cc e1 strh r4,[r12,#0x4]=>DAT_801aef2e
800046ac f1 ff ff 3a bcc LAB_80004678
LAB_800046b0 XREF[1]: 80004704(j)
800046b0 f0 01 bd e8 ldmia sp!,{r4 r5 r6 r7 r8}=>local_18
800046b4 68 20 9f e5 ldr r2,[DAT_80004724] = 000016A8h
800046b8 4c 10 9f e5 ldr r1,[DAT_8000470c] = 801AEF2Ah
800046bc 44 00 9f e5 ldr r0,[DAT_80004708] = 8019D5EAh
800046c0 04 90 9d e4 ldr r9,[sp],#0x4
800046c4 e4 ef ff ea b memcpy
LAB_800046c8 XREF[2]: 80004674(j), 80004700(j)
800046c8 81 c0 85 e0 add r12,r5,r1, lsl #0x1
800046cc b0 c0 dc e1 ldrh r12,[r12,#0x0]=>DAT_8019ed5a
800046d0 be 61 d2 e1 ldrh r6,[r2,#0x1e]=>DAT_802f18ce
800046d4 0c 00 56 e1 cmp r6,r12
800046d8 01 c1 80 20 addcs r12,r0,r1, lsl #0x2
800046dc b0 40 cc 21 strhcs r4,[r12,#0x0]
800046e0 03 00 00 2a bcs LAB_800046f4
800046e4 be 61 d2 e1 ldrh r6,[r2,#0x1e]=>DAT_802f18ce
800046e8 01 71 80 e0 add r7,r0,r1, lsl #0x2
800046ec 06 c0 4c e0 sub r12,r12,r6
800046f0 b0 c0 c7 e1 strh r12,[r7,#0x0]=>DAT_801aef2a
LAB_800046f4 XREF[1]: 800046e0(j)
800046f4 01 10 81 e2 add r1,r1,#0x1
800046f8 01 18 c1 e3 bic r1,r1,#0x10000
800046fc 03 00 51 e1 cmp r1,r3
80004700 f0 ff ff 3a bcc LAB_800046c8
80004704 e9 ff ff ea b LAB_800046b0
This is my commented take on it.
void scope_pre_process_ch1_25ns_data(void)
{
undefined2 uVar1;
int iVar2;
int iVar3;
uint *puVar4;
uint *puVar5;
uint *puVar6;
uint *puVar7;
uint **ppuVar8;
uint **ppuVar9;
byte *pbVar10;
undefined2 *puVar11;
uint uVar12;
uint uVar13;
byte bVar14;
uint uVar15;
int iVar16;
short *psVar17;
byte bVar18;
undefined2 uVar19;
uint *puVar20;
uint *puVar21;
uint uVar22;
uint uVar23;
uint uVar24;
bool bVar25;
bool bVar26;
puVar7 = DAT_8000470c; //0x801AEF2A = temptracebuffer1 + 4
puVar21 = DAT_80004708; //0x8019D5EA = channel1tracebuffer1 (1500 samples from most likely adc1)
iVar16 = 0x2e8; //744
//Copy a short from buffer1 to buffer2
*(undefined2 *)((int)DAT_8000470c + 2) = *(undefined2 *)DAT_80004708; //0x801aef2c = 0x8019d5ea
uVar19 = *(undefined2 *)((int)puVar21 + 2); //Get data from 0x8019d5ec
puVar11 = (undefined2 *)((int)puVar7 + 2); //point to next item in the temp buffer
//Copy data from sample buffer to temp buffer while skipping a sample in the temp buffer. (Make room for another sample???)
do
{
uVar1 = *(undefined2 *)(puVar21 + 1); //0x8019d5ee
puVar11[2] = uVar19; //0x801aef30 = 0x8019d5ec skip one item
uVar19 = *(undefined2 *)((int)puVar21 + 6); //0x8019d5f0
iVar16 = iVar16 + -1;
puVar11 = puVar11 + 4;
*puVar11 = uVar1; //0x801aef34 = 0x8019d5ee
puVar21 = puVar21 + 1;
} while (iVar16 != 0);
//Last copies done
//0x0x801B0668 = 0x8019E18A
//0x0x801B066C = 0x8019E18C
iVar3 = DAT_8000471c; //0x8019ED5A channel1tracebuffer2 (1500 samples from most likely adc2)
iVar2 = DAT_80004718; //0x802F18B0 Calibration data
*(undefined2 *)(DAT_80004714 + 2) = *DAT_80004710; //0x801B0670 = 0x8019E18C
uVar15 = DAT_80004720; //0x000005D2 = 1490
uVar12 = 0;
if (*(short *)(iVar2 + 0x1c) == 0) //0x802f18cc Either 1 or 0 based on some calibration action
{
//Trace data showed this to be zero on my scope, so this loop is done
do
{
uVar13 = (uint)*(ushort *)(iVar3 + uVar12 * 2); //First sample from 0x8019ed5a
if (*(ushort *)(iVar2 + 0x1e) < uVar13) //0x802f18ce also some calibration data (3 on my scope)
{
puVar21 = (uint *)(uVar13 - *(ushort *)(iVar2 + 0x1e));
*(short *)(puVar7 + uVar12) = (short)puVar21; //puVar7 = temp trace buffer
}
else
{
puVar21 = puVar7 + uVar12;
*(undefined2 *)puVar21 = 0;
}
uVar12 = uVar12 + 1 & 0xfffeffff;
} while (uVar12 < uVar15);
//Trace shows this
//First samples
//0x801AEF2A = 0x8019ED5A
//0x801AEF2E = 0x8019ED5C
//0x801AEF32 = 0x8019ED5E
//Last samples
//0x801B066A = 0x8019F8FA
//0x801B066E = 0x8019F8FC
}
else
{
do
{ //two samples at a time, but I miss the interleaving???? Maybe buffers or pointers defined as 32 bit items
psVar17 = (short *)(iVar3 + uVar12 * 2);
puVar21 = puVar7 + uVar12;
uVar12 = uVar12 + 2 & 0xfffeffff;
*(short *)puVar21 = *psVar17 + *(short *)(iVar2 + 0x1e);
*(short *)(puVar21 + 1) = psVar17[1] + *(short *)(iVar2 + 0x1e);
} while (uVar12 < uVar15);
//Trace shows this
//First samples
//0x801AEF2A = 0x8019ED5A
//0x801AEF2E = 0x8019ED5C
//0x801AEF32 = 0x8019ED5E
//0x801AEF36 = 0x8019ED60
//Last samples
//0x801B0662 = 0x8019F8F6
//0x801B0666 = 0x8019F8F8
//0x801B066A = 0x8019F8FA
//0x801B066E = 0x8019F8FC
}
//DAT_80004724; //0x000016A8 5800 bytes
//DAT_80004708; //0x8019D5EA first buffer destination
//DAT_8000470c; //0x801AEF2A temp buffer source
//Copy the temp buffer back to the first trace buffer
memcpy(DAT_80004708, DAT_8000470c, DAT_80004724);
}
It does confirm my thoughts on why they read a second buffer of 1500 bytes from the FPGA when in 25 or 10nS/Div setting. For the other time base settings they only sample using a single ADC. For the lowest two settings they also use the second ADC, but instead of having the FPGA do the interleaving of the two samples, they do it in the CPU.
That is all this first function does. Interleave the samples of the two reads. Only on the second set of data they do some calibration based action. In the code there is a check on a flag, if zero they use a subtract of a calibration value, if one they add the value. They probably measure the difference between the two ADC's and the flag is set based on which one is lower then the other.
This flag and value are determined in the calibration procedure and stored in the settings. This concerns the first four of the unknown calibration values found earlier. (2 per channel. Flag and value)
For this to make sense the two ADC's in one package have to have a possible mismatch. Need to look at the specifications.
I'm back on the part of the code I wrote about on page 39 post 950.
It is becoming a little bit clearer and managed to write a bit cleaner code that handles the data from the top reducing the number of data copies being made, but still fail to see the logic behind it.
The below code only does the first part of what the original code does. It interpolates the samples without copying the data to another buffer. (Tested this on my Linux machine)
void scope_up_sample_x_10(uint16 * buffer, uint32 count)
{
register uint32 cnt, idx;
register uint16 *sptr;
register uint16 *dptr;
register int32 sample1, sample2;
register int32 delta;
//Only do one tenth of the samples
cnt = count / 10;
//For the source point to the last sample to use
sptr = &buffer[cnt];
//For the destination point to the last result sample
dptr = &buffer[count];
//Get the first sample to use
sample1 = *sptr--;
//Process all the needed samples
while(cnt)
{
//Store the first sample
*dptr-- = sample1;
//Get the second sample
sample2 = *sptr--;
//Fill in the in between samples
//The original code uses a different approach
//Get the samples shifted up for fractional calculations 10.22 bits
sample1 <<= 22;
//Calculate a delta step between the samples
delta = (sample1 - (sample2 << 22)) / 10;
for(idx=0;idx<9;idx++)
{
//Calculate the next sample with fixed point calculation
//Since the direction is from last sample to first sample the step needs to be taken off
sample1 -= delta;
//Store the decimal part of it
*dptr-- = sample1 >> 22;
}
//Save the second sample as the first sample
sample1 = sample2;
//One set of samples done
cnt--;
}
}
The same code with different offsets and another destination buffer can do the second interpolation, and it might even be possible to do the averaging in the same loop and again keep it all in one buffer, but to get an understanding I think I will have to keep it separate for now and have the output displayed as a trace on a screen.
So yet write some test software first to get to the bottom of it all.
Need to figure it out since this function is also used in the 25 and 10nS/div data processing.
So break out the popcorn and sit back, again