У цифровых осциллографов GW Instek GDS-8xx (GDS-810/GDS-820/GDS-840) есть USB порт к которому можно подключить PC с программой FreeView. Однако, оказалось, что у FreeView закрыт код и софт не работает под Vista, Windows 7, Linux.
FreeView занимается тем, что копирует содержимое экрана осциллографа на компьютер. Копирование экрана сделано примитивнейшим образом: содержимое экрана после запроса попиксельно посылается по UART-у на PC. Для того, чтобы этот процесс выглядел по-современнее, внутрь осциллографа поставлен чип конвертера USB2COM от www.ftdichip.com.
На компьютере устанавливается драйвер, который имитирует наличие COM-порта, к которому автоматически цепляется FreeView.
Но FreeView был написан для доисторического драйвера под XP, исходники никто не потрудился открыть, и, естественно, что на новых ОС и новых драйверах FreeView не работает, а под Linux подобный код вообще никто не потрудился написать.
Изучение работы FreeView показало, что ничего сложного в реализации нет. Копия экрана отсылается в бинарном виде после посылки запроса через виртуальный COM-порт.
Ниже приводится демонстрационный пример, который считывает копию экрана осциллографа и записывает в файл.
#include <windows.h>
#include <setupapi.h>
#include <stdio.h>
#define X_RESOLUTION 320
#define Y_RESOLUTION 240
void CloseCom(HANDLE* hCm)
{
if (*hCm!=INVALID_HANDLE_VALUE)
{
CloseHandle(*hCm);
*hCm=INVALID_HANDLE_VALUE;
}
}
BOOL OpenCom(DWORD com, HANDLE* OUT hCm)
{
BOOL fSuccess;
DCB dcb;
COMMTIMEOUTS ct;
DWORD err;
TCHAR szComName[32];
if (*hCm!=INVALID_HANDLE_VALUE) CloseCom(hCm);
err=0;
if (com==0) { err=1; goto err_exit; }
wsprintf(szComName,L"\\\\.\\COM%u",com);
*hCm=CreateFile(szComName,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
if (*hCm==INVALID_HANDLE_VALUE) { err=1; goto err_exit; }
fSuccess=GetCommState(*hCm,&dcb);
if (!fSuccess) { err=2; goto err_exit; }
// изменение скорости на процесс чтения почему-то не влияет
dcb.BaudRate=921600;//CBR_115200; // set the baud rate
dcb.fBinary=TRUE;
dcb.fParity=FALSE;
dcb.fOutxCtsFlow=FALSE; // CTS output flow control
dcb.fOutxDsrFlow=FALSE; // DSR output flow control
dcb.fDtrControl=DTR_CONTROL_DISABLE; // DTR flow control type
dcb.fDsrSensitivity=FALSE; // DSR sensitivity
dcb.fTXContinueOnXoff=TRUE; // XOFF continues Tx
dcb.fOutX=FALSE; // XON/XOFF out flow control
dcb.fInX=FALSE; // XON/XOFF in flow control
dcb.fErrorChar=FALSE; // enable error replacement
dcb.fNull=FALSE; // enable null stripping
dcb.fRtsControl=RTS_CONTROL_DISABLE; // RTS flow control
dcb.fAbortOnError=FALSE; // abort reads/writes on error
dcb.wReserved=0; // not currently used
dcb.XonLim=1; // transmit XON threshold
dcb.XoffLim=8; // transmit XOFF threshold
dcb.ByteSize=8; // number of bits/byte, 4-8
dcb.Parity=NOPARITY; // no parity bit
dcb.StopBits=ONESTOPBIT; // one stop bit
dcb.StopBits=ONESTOPBIT; // 0,1,2 = 1, 1.5, 2
dcb.XonChar=0x1B; // Tx and Rx XON character
dcb.XoffChar=0x1C; // Tx and Rx XOFF character
dcb.ErrorChar=0x00; // error replacement character
dcb.EofChar=0x00; // end of input character
dcb.EvtChar=(BYTE)0x80; // received event character
fSuccess=SetCommState(*hCm,&dcb);
if (!fSuccess) { err=3; goto err_exit; }
ct.ReadIntervalTimeout=0;
ct.ReadTotalTimeoutMultiplier=0;
ct.ReadTotalTimeoutConstant=50;
ct.WriteTotalTimeoutMultiplier=0;
ct.WriteTotalTimeoutConstant=50;
fSuccess=SetCommTimeouts(*hCm,&ct);
if (!fSuccess) { err=4; goto err_exit; }
fSuccess=SetupComm(*hCm,48,48);
if (!fSuccess) { err=5; goto err_exit; }
fSuccess=PurgeComm(*hCm,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
if (!fSuccess) { err=6; goto err_exit; }
fSuccess=EscapeCommFunction(*hCm,SETDTR);
if (!fSuccess) { err=7; goto err_exit; }
fSuccess=EscapeCommFunction(*hCm,SETRTS);
if (!fSuccess) { err=8; goto err_exit; }
err_exit:
if (err)
{
if (*hCm!=INVALID_HANDLE_VALUE) CloseHandle(*hCm);
return FALSE;
}
return TRUE;
}
int main(void)
{
// заголовок BITMAP (4 бита на цвет + палитра)
BYTE hdr[]={
0x42,0x4D,0x76,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x76,0x00,0x00,0x00,0x28,0x00,
0x00,0x00,0x40,0x01,0x00,0x00,0xF0,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x00,0x00,
0x00,0x00,0x00,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,
0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
0xFF,0xFF,0x00,0x77,0x77,0x77,0xFF,0xFF,0x00,0x00,0x66,0x44,0x22,0x00,0x66,0xFF,
0x66,0x66,0xFF,0xFF,0xFE,0xFF,0x88,0x88,0x87,0x88,0x22,0x22,0x88,0xFF,0x55,0x00,
0x00,0x00,0xBB,0xBB,0xBB,0xBB,0x33,0x66,0x99,0x99,0x88,0x88,0x88,0xFF,0x22,0x22,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
HANDLE hCom=INVALID_HANDLE_VALUE;
DWORD cnt,written,readen;
BYTE buf[]={ 0x57, 0x00, 0x00, 0x0A };
DWORD raw,col,ptr;
BYTE bt1,bt2;
BYTE ibuf[0xA000];
BYTE imgbuf[0xA000];
printf("Open com... "); // открываем COM-порт который создал драйвер FTDI
if (!OpenCom(4,&hCom)) // попытка открытия порта
{
printf("failed!\n");
exit(1);
}
printf("ok.\n"); // открытие прошло успешно
printf("Write..."); // посылка запроса чтения экрана
if (!WriteFile(hCom,buf,4,&written,NULL))
{
printf("failed!\n");
exit(1);
}
printf("ok.\nReading...\n");
for(cnt=0;cnt<0xA000;) // чтение ответа осциллографа
{
if (!ReadFile(hCom,&ibuf[cnt],0xA000-cnt,&readen,NULL))
{
printf("read failed...\n");
}
else
{
cnt+=readen; // добавление считанных байтов к счётчику
}
}
printf("Read complete.\n"); // чтение завершено
printf("Close com...\n"); // закрытие COM-порта
CloseCom(&hCom);
// восстанавливаем из сырых данных картинку
for(raw=0;raw<(X_RESOLUTION/2);raw++)
{
for(col=0,ptr=raw<<8;col<0xA000;col+=X_RESOLUTION,ptr++)
{
imgbuf[raw+col]=(ibuf[ptr]&0xF0)|(ibuf[ptr+128]>>4);
imgbuf[raw+col+(X_RESOLUTION/2)]=(ibuf[ptr+128]&0x0F)|((ibuf[ptr]<<4)&0xF0);
}
}
// поворачиваем картинку на 180
for(raw=0;raw<Y_RESOLUTION;raw++)
{
for(col=0;col<(X_RESOLUTION/4);col++)
{
bt1=imgbuf[raw*(X_RESOLUTION/2)+col]; bt1=(bt1>>4)|(bt1<<4);
bt2=imgbuf[((Y_RESOLUTION-1)-raw)*(X_RESOLUTION/2)+((X_RESOLUTION/2-1)-col)]; bt2=(bt2>>4)|(bt2<<4);
imgbuf[raw*(X_RESOLUTION/2)+col]=bt2;
imgbuf[((Y_RESOLUTION-1)-raw)*(X_RESOLUTION/2)+((X_RESOLUTION/2-1)-col)]=bt1;
}
}
// запись bmp-файла
hCom=CreateFile(L"temp.bmp",GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL);
WriteFile(hCom,hdr,0x76,&written,NULL);
WriteFile(hCom,imgbuf,0x9600,&written,NULL);
CloseHandle(hCom);
return 1;
}
Картинка, которая получается в результате работы программы.