OWON VDS3104 をpythonで制御 (その2)

[前回](https://qiita.com/nachtele/items/291604601179cf376895)に引き続き、OWON の USBオシロスコープ VDS3104(LAN無しモデル) をpythonで制御してみます。

#環境
OS : Windows 10
対象機器 : VDS3104
アプリ : OWON VDS 2.0.19.4
言語 : python 3.7

#SCPIコマンド
[OWONのexample](http://files.owon.com.cn//software/Application/VDS_Series_SCPI_example_folder.zip)に 'VDS Series SCPI Protocol V1.6.pdf'が同梱されています。これに記載されている各SCPIコマンドの動作を確認してみました。
当初、少し古いバージョンのアプリ(OWON VDS 2.0.17)を使っていたところ、いくつかのコマンドがレスポンス b'CAN NOT ANALYSE THE ORDER' を返して動かないということが分かりました。
そこで、[最新版のアプリ(OWON VDS 2.0.19.4)](http://files.owon.com.cn/software/pc/OWON_VDS_S4_Setup.zip)と[USBドライバー](http://files.owon.com.cn/software/pc/VDS_USBDRV.zip)をにしたところ正しく動作するようになりました。


```python:vds02.py
from socket import AF_INET, socket, SOCK_STREAM, setdefaulttimeout
from time import sleep

class LanSource:
    def __init__(self, address):
        #param address: (ip, port) -> (str, int)
        super(LanSource, self).__init__()
        setdefaulttimeout(5)
        client = socket(AF_INET, SOCK_STREAM)
        client.connect(address)
        client.settimeout(5)
        self.address = address
        self.client = client

    def close(self):
        self.client.close()

def PlayCmds(ls, cmdlist):
    for cmd, slp, dst in cmdlist:
        print(cmd)
        ls.client.send(cmd)
        sleep(slp)
        dat = b''
        while True:
            rsv = ls.client.recv(2048)
            dat += rsv
            if len(rsv) < 2048: break
        if dst:
            with open(dst,"wb") as f:
                f.write(dat)
        else:
            print(dat)

Commands_Init = [
     [b'*ADC? CH1', 1, 'adc_ch1.bin']
    ,[b'*AUToset', 10, '']
    ,[b'*LDM? C:\\tmp\\DAT', 5, '']
    ,[b'*RDM?', 5, 'RDMDAT.bin']
    ,[b'*RUNStop', 1, '']
    ,[b'*RUNStop', 1, '']
    ,[b'*IDN?', 0, '']
    ,[b'*RST', 1, '']
    ,[b':MEASure:SOURce CH1', 0, '']
    ,[b':MEASure:ADD PERiod', 0, '']
    ,[b':MEASure:DELete MAX', 0, '']
    ,[b':MEASure:PERiod?', 0, '']
    ,[b':MEASure:FREQuency?', 0, '']
    ,[b':MEASure:AVERage?', 0, '']
    ,[b':MEASure:MAX?', 0, '']
    ,[b':MEASure:MIN?', 0, '']
    ,[b':MEASure:VTOP?', 0, '']
    ,[b':MEASure:VBASe?', 0, '']
    ,[b':MEASure:VAMP?', 0, '']
    ,[b':MEASure:PKPK?', 0, '']
    ,[b':MEASure:CYCRms?', 0, '']
    ,[b':MEASure:RTIMe?', 0, '']
    ,[b':MEASure:FTIMe?', 0, '']
    ,[b':MEASure:PDUTy?', 0, '']
    ,[b':MEASure:NDUTy?', 0, '']
    ,[b':MEASure:PWIDth??', 0, '']
    ,[b':MEASure:NWIDth??', 0, '']
    ,[b':MEASure:OVERshoot?', 0, '']
    ,[b':MEASure:PREShoot?', 0, '']
    ,[b':MEASure:RDELay?', 0, '']
    ,[b':MEASure:FDELay?', 0, '']
    ,[b':ACQuire:TYPE AVERage', 0, '']
    ,[b':ACQuire:AVERage 64', 0, '']
    ,[b':ACQuire:MDEPth 10K', 0, '']
    ,[b':TIMebase:SCALe 200us', 0, '']
    ,[b':TIMebase:HOFFset 50', 0, '']
    ,[b':FFT:DISPlay ON', 0, '']
    ,[b':FFT: FREQbase 10MHz', 0, '']
    ,[b':FFT:FORMat VRMS 0.5', 0, '']
    ,[b':FFT:FORMat DB 2DB', 0, '']
    ,[b':FFT:WINDow RECTangle', 0, '']
    ,[b':FFT:ZONE X5', 0, '']
    ,[b':CHANnel1:DISPlay ON', 0, '']
    ,[b':CHANnel1:COUPling DC', 0, '']
    ,[b':CHANnel1:PROBe X10', 0, '']
    ,[b':CHANnel1:SCALe 0.5', 0, '']
    ,[b':CHANnel1:OFFSet 25', 0, '']
    ,[b':CHANnel1: HARDfreq?', 0, '']
    ,[b':CHANnel1: INVerse ON', 0, '']
    ,[b':CHANnel1:CURRent ON', 0, '']
    ,[b':TRIGger:TYPE SINGle', 0, '']
    ,[b':TRIGger:MODE NORMal', 0, '']
    ,[b':TRIGger:SINGle VIDeo', 0, '']
    ,[b':TRIGger:ALT VIDeo', 0, '']
    ,[b':TRIGger:SINGle:EDGE:SOURce CH2', 0, '']
    ,[b':TRIGger:SINGle:EDGE:SLOPe FALL', 0, '']
    ,[b':TRIGger:SINGle:EDGE:LEVel 25', 0, '']
    ,[b':TRIGger:SINGle:VIDeo:SOURce CH2', 0, '']
    ,[b':TRIGger:SINGle:VIDeo:MODU NTSC', 0, '']
    ,[b':TRIGger:SINGle:VIDeo:SYNC ODD', 0, '']
    ,[b':TRIGger:SINGle:VIDeo:LNUM 100', 0, '']
    ,[b':TRIGger:ALT:EDGE:SOURce CH2', 0, '']
    ,[b':TRIGger:ALT:EDGE:SLOPe FALL', 0, '']
    ,[b':TRIGger:ALT:EDGE:LEVel 50', 0, '']
    ,[b':TRIGger:ALT:VIDeo:SOURce CH2', 0, '']
    ,[b':TRIGger:ALT:VIDeo:MODU NTSC', 0, '']
    ,[b':TRIGger:ALT:VIDeo:SYNC ODD', 0, '']
    ,[b':TRIGger:ALT:VIDeo:LNUM100', 0, '']
    ,[b':SAVE:CSV C:\\TMP\\test.csv', 2, '']
    ,[b':SAVE:IMAGe C:\\TMP\\test.png', 2, '']
    ,[b':SAVE:IMAGe:INVert ON', 0, '']
    ,[b':CURSor:HORizontal:DISPlay ON', 0, '']
    ,[b':CURSor:HORizontal:BAR1 500', 0, '']
    ,[b':CURSor:VERTical:DISPlay ON', 0, '']
    ,[b':CURSor:HORizontal:BAR1 250', 0, '']
    ,[b':CURSor:SOURce CH1', 0, '']
    ,[b':CURSor:X1?', 0, '']
    ,[b':CURSor:XDELta?', 0, '']
    ,[b':CURSor:IXDELta?', 0, '']
    ,[b':CURSor:Y1?', 0, '']
    ,[b':CURSor:YDELta?', 0, '']
]

if __name__ == '__main__':
    ls = LanSource(('localhost', 5188))
    PlayCmds(ls, Commands_Init)
    ls.close()
```


#コマンド-レスポンス確認結果

'*ADC?'コマンドのレスポンスの先頭4バイトはビッグエンディアンでデータサイズを示しているようで、レコード長が1kの時は0x000003E8(1000)、それ以外の時は0x00000F9C(3996)となります。それに続くデータは符号付8ビットデータ(波形の縦軸の中央が0)と思われます。

|コマンド |レスポンス例 |
|---|---|
|b'*ADC? CH1' |(データサイズ) + (データ) |
|b'*AUToset' |b'SUCCESS\n\r' |
|b'*LDM? C:\\\\tmp\\\\DAT' |b'GETTING  DEEPMEMORY DATA , PLEASE WAIT...\r\nTRANSMITSSION  DONE  SAVED @ C:\\\\TMP\\\\DAT\\\\2021_0828_18.39.39.bin\r\n' |
|b'*RDM?' |b'GETTING  DEEPMEMORY DATA , PLEASE WAIT...\r\n' + (データ) + b'TRANSMITSSION  DONE\r\n' |
|b'*RUNStop' |b'SET RUN\n\r' |
|b'*RUNStop' |b'SET STOP\n\r' |
|b'*IDN?' |b'OWON,VDS3104,VDS31041506121,V4.0\n\r' |
|b'*RST' |b'SUCCESS\n\r' |
|b':MEASure:SOURce CH1' |b'SUCCESS\n\r' |
|b':MEASure:ADD PERiod' |b'SUCCESS\n\r' |
|b':MEASure:DELete MAX' |b'FIALED\n\r' |
|b':MEASure:PERiod?' |b'?\n\r' |
|b':MEASure:FREQuency?' |b'?\n\r' |
|b':MEASure:AVERage?' |b'0.0\n\r' |
|b':MEASure:MAX?' |b'0.0\n\r' |
|b':MEASure:MIN?' |b'0.0\n\r' |
|b':MEASure:VTOP?' |b'?\n\r' |
|b':MEASure:VBASe?' |b'?\n\r' |
|b':MEASure:VAMP?' |b'?\n\r' |
|b':MEASure:PKPK?' |b'0.0\n\r' |
|b':MEASure:CYCRms?' |b'0.0\n\r' |
|b':MEASure:RTIMe?' |b'?\n\r' |
|b':MEASure:FTIMe?' |b'?\n\r' |
|b':MEASure:PDUTy?' |b'?\n\r' |
|b':MEASure:NDUTy?' |b'?\n\r' |
|b':MEASure:PWIDth??' |b'?\n\r' |
|b':MEASure:NWIDth??' |b'?\n\r' |
|b':MEASure:OVERshoot?' |b'?\n\r' |
|b':MEASure:PREShoot?' |b'?\n\r' |
|b':MEASure:RDELay?' |b'0.0\n\r' |
|b':MEASure:FDELay?' |b'0.0\n\r' |
|b':ACQuire:TYPE AVERage' |b'SUCCESS\n\r' |
|b':ACQuire:AVERage 64' |b'SUCCESS\n\r' |
|b':ACQuire:MDEPth 10K' |b'SUCCESS , 10k\n\r' |
|b':TIMebase:SCALe 200us' |b'SUCCESS , 200us\n\r' |
|b':TIMebase:HOFFset 50' |b'SUCCESS\n\r' |
|b':FFT:DISPlay ON' |b'SUCCESS\n\r' |
|b':FFT: FREQbase 10MHz' |b'FIALED\n\r' |
|b':FFT:FORMat VRMS 0.5' |b'SUCCESS\n\r' |
|b':FFT:FORMat DB 2DB' |b'SUCCESS\n\r' |
|b':FFT:WINDow RECTangle' |b'SUCCESS\n\r' |
|b':FFT:ZONE X5' |b'SUCCESS\n\r' |
|b':CHANnel1:DISPlay ON' |b'SUCCESS\n\r' |
|b':CHANnel1:COUPling DC' |b'SUCCESS\n\r' |
|b':CHANnel1:PROBe X10' |b'SUCCESS\n\r' |
|b':CHANnel1:SCALe 0.5' |b'SUCCESS\n\r' |
|b':CHANnel1:OFFSet 25' |b'SUCCESS,Valid Set:25\n\r' |
|b':CHANnel1: HARDfreq?' |b'<2Hz\n\r' |
|b':CHANnel1: INVerse ON' |b'SUCCESS\n\r' |
|b':CHANnel1:CURRent ON' |b'SUCCESS\n\r' |
|b':TRIGger:TYPE SINGle' |b'SUCCESS\n\r' |
|b':TRIGger:MODE NORMal' |b'SUCCESS\n\r' |
|b':TRIGger:SINGle VIDeo' |b'SUCCESS\n\r' |
|b':TRIGger:ALT VIDeo' |b'SUCCESS\n\r' |
|b':TRIGger:SINGle:EDGE:SOURce CH2' |b'SUCCESS\n\r' |
|b':TRIGger:SINGle:EDGE:SLOPe FALL' |b'SUCCESS\n\r' |
|b':TRIGger:SINGle:EDGE:LEVel 25' |b'SUCCESS\n\r' |
|b':TRIGger:SINGle:VIDeo:SOURce CH2' |b'SUCCESS\n\r' |
|b':TRIGger:SINGle:VIDeo:MODU NTSC' |b'SUCCESS\n\r' |
|b':TRIGger:SINGle:VIDeo:SYNC ODD' |b'SUCCESS\n\r' |
|b':TRIGger:SINGle:VIDeo:LNUM 100' |b'NOT ENABLE TO ADJUST\n\r' |
|b':TRIGger:ALT:EDGE:SOURce CH2' |b'SUCCESS\n\r' |
|b':TRIGger:ALT:EDGE:SLOPe FALL' |b'SUCCESS\n\r' |
|b':TRIGger:ALT:EDGE:LEVel 50' |b'SUCCESS\n\r' |
|b':TRIGger:ALT:VIDeo:SOURce CH2' |b'SUCCESS\n\r' |
|b':TRIGger:ALT:VIDeo:MODU NTSC' |b'SUCCESS\n\r' |
|b':TRIGger:ALT:VIDeo:SYNC ODD' |b'SUCCESS\n\r' |
|b':TRIGger:ALT:VIDeo:LNUM100' |b'NOT ENABLE TO ADJUST\n\r' |
|b':SAVE:CSV C:\\\\TMP\\\\test.csv' |b'TRANSMITSSION  DONE  SAVED @ C:\\\\TMP\\\\test.csv\n\r' |
|b':SAVE:IMAGe C:\\\\TMP\\\\test.png' |b'TRANSMITSSION  DONE  SAVED @ C:\\\\TMP\\\\test.png\n\r' |
|b':SAVE:IMAGe:INVert ON' |b'Turn on the reverse color function\n\r' |
|b':CURSor:HORizontal:DISPlay ON' |b'timeline cursor turned on\n\r' |
|b':CURSor:HORizontal:BAR1 500' |b'Set up X1 500px successfully\n\r' |
|b':CURSor:VERTical:DISPlay ON' |b'Y axis cursor turned on\n\r' |
|b':CURSor:HORizontal:BAR1 250' |b'Set up X1 250px successfully\n\r' |
|b':CURSor:SOURce CH1' |b'Set CH1 successfully\n\r' |
|b':CURSor:X1?' |b'800.0 us\n\r' |
|b':CURSor:XDELta?' |b'1.600 ms\n\r' |
|b':CURSor:IXDELta?' |b'625.0 Hz\n\r' |
|b':CURSor:Y1?' |b'5.000A\n\r' |
|b':CURSor:YDELta?' |b'20.00A\n\r' |

[次回](https://qiita.com/nachtele/items/ad2cdbe3cfa6f6e9f774)に続く。