├── .gitignore ├── Color-Sreenshot.py ├── LICENSE ├── README.md ├── Test1.py ├── Test2.py ├── Test3.py ├── Test4.py ├── Test5-MJPEG.py ├── docs ├── DSO5000P Series Digital Storage Oscilloscope User Manual(V1.1).pdf └── DSO5000P_Manual.pdf ├── inf ├── keyprotocol.inf ├── protocol.inf └── sys.inf ├── rcr ├── __init__.py └── dso5102p │ ├── DSO5102P.py │ └── __init__.py └── screenshot ├── 2019-05-05 11:57:16.png ├── 2019-05-05 11:58:17.png ├── 2019-05-05 11:58:48.png └── DSO5102p 09-11-2023 07:37:26.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /Color-Sreenshot.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import time 5 | import numpy as np 6 | import cv2 7 | import os 8 | 9 | from rcr.dso5102p.DSO5102P import DSO5102P 10 | 11 | def main(): 12 | dso = DSO5102P( 0x049f, 0x505a, False ) 13 | 14 | print( 'Getting the screenshot' ) 15 | r = dso.Screenshot() 16 | 17 | print( 'Converting image...' ) 18 | im = np.zeros((480,800,3)) 19 | for h in range(0,r.shape[0]): 20 | for v in range(0,r.shape[1]): 21 | Pixel = r[h,v] 22 | match Pixel: 23 | # color comments based on GUI color = Black setting 24 | # only tested Black and Blue GUI color setting 25 | case 0 | 160 | 108: #black background 26 | im[h,v,0] = 0 27 | im[h,v,1] = 0 28 | im[h,v,2] = 0 29 | case 224 | 102 | 198 | 64: ##CH1, DC/AC indication bottom bar yellow 30 | im[h,v,0] = 0 31 | im[h,v,1] = 255 32 | im[h,v,2] = 255 33 | case 170 | 147: #bottom bar darker grey 34 | im[h,v,0] = 85 35 | im[h,v,1] = 85 36 | im[h,v,2] = 85 37 | case 174: #right menu lighter grey 38 | im[h,v,0] = 118 39 | im[h,v,1] = 118 40 | im[h,v,2] = 118 41 | case 255 | 115 | 217 | 223 | 230 | 249: #CH2 blue 42 | im[h,v,0] = 255 #blue 43 | im[h,v,1] = 255 #green 44 | im[h,v,2] = 0 #red 45 | case 251: #border menu right, border signal window even lighter grey 46 | im[h,v,0] = 220 47 | im[h,v,1] = 220 48 | im[h,v,2] = 220 49 | case 215: #frame shadow light grey 50 | im[h,v,0] = 190 51 | im[h,v,1] = 190 52 | im[h,v,2] = 190 53 | case 4: #frame shadow dark grey 54 | im[h,v,0] = 34 55 | im[h,v,1] = 34 56 | im[h,v,2] = 34 57 | case 44: #button shadow grey 58 | im[h,v,0] = 100 59 | im[h,v,1] = 100 60 | im[h,v,2] = 100 61 | case 31: #math color purple 62 | im[h,v,0] = 255 63 | im[h,v,1] = 0 64 | im[h,v,2] = 255 65 | case 140 | 6 | 12: #bottom bar bandwidth limit indicator 66 | im[h,v,0] = 0 67 | im[h,v,1] = 0 68 | im[h,v,2] = 255 69 | case 121 | 127 | 57: #printer icon, cursor indicator border light blue 70 | im[h,v,0] = 155 71 | im[h,v,1] = 207 72 | im[h,v,2] = 155 73 | case 125: #menu right X icon, white 74 | im[h,v,0] = 255 75 | im[h,v,1] = 255 76 | im[h,v,2] = 255 77 | case 128: #X icon, red 78 | im[h,v,0] = 0 79 | im[h,v,1] = 0 80 | im[h,v,2] = 255 81 | case 130: #channel/slope indicator left top menu dark grey 82 | im[h,v,0] = 18 83 | im[h,v,1] = 18 84 | im[h,v,2] = 18 85 | case 134: #border period top right, dark grey 86 | im[h,v,0] = 50 87 | im[h,v,1] = 50 88 | im[h,v,2] = 50 89 | case 19: #purple 90 | im[h,v,0] = 155 91 | im[h,v,1] = 0 92 | im[h,v,2] = 54 93 | case 192: #selected menu item red 94 | im[h,v,0] = 0 95 | im[h,v,1] = 154 96 | im[h,v,2] = 255 97 | case 204 | 96: #yellow-grey 98 | im[h,v,0] = 0 99 | im[h,v,1] = 173 100 | im[h,v,2] = 173 101 | case 211: #light grey 102 | im[h,v,0] = 155 103 | im[h,v,1] = 155 104 | im[h,v,2] = 155 105 | case 254: #almost white/blue cursor indicator text 106 | im[h,v,0] = 246 #blue 107 | im[h,v,1] = 255 #green 108 | im[h,v,2] = 255 #red 109 | case 32 | 38: #red top menu time/base indicator 110 | im[h,v,0] = 0 111 | im[h,v,1] = 101 112 | im[h,v,2] = 255 113 | case 40: #menu title bar background, disabled feature dark grey 114 | im[h,v,0] = 65 115 | im[h,v,1] = 65 116 | im[h,v,2] = 65 117 | case 63: #cursor indicator background blue 118 | im[h,v,0] = 255 119 | im[h,v,1] = 101 120 | im[h,v,2] = 54 121 | case 81: #button shadow top light gray 122 | im[h,v,0] = 138 123 | im[h,v,1] = 138 124 | im[h,v,2] = 138 125 | case 85 | 51: #menu title bar border 126 | im[h,v,0] = 172 127 | im[h,v,1] = 172 128 | im[h,v,2] = 172 129 | case _: 130 | print('unmapped pixel value:') # 243 159 131 | print(Pixel) 132 | im[h,v,0] = 0 133 | im[h,v,1] = 0 134 | im[h,v,2] = 0 135 | im = im.astype(np.uint8) 136 | 137 | print( 'Saving ...' ) 138 | #cv2.imwrite( 'greyscale.png', r ) #greyscale 139 | cv2.imwrite( 'screenshot.png', im ) #color 140 | 141 | main() 142 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Roberto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DSO5102P-Python 2 | Access to the Hantek DSO5102P oscilloscope from Python 3.x 3 | 4 | See this sites for details: 5 | * https://elinux.org/Das_Oszi_Protocol 6 | * https://randomprojects.org/wiki/Voltcraft_DSO-3062C 7 | 8 | Screenshot 9 | 10 | My Hantek DSO5102P reports VID:PID as 049f:505a so I added the file ``99-dso5102P.rules`` to ``/lib/udev/rules.d/`` (or to ``/etc/udev/rules.d/``) 11 | 12 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="049f", ATTR{idProduct}=="505a", MODE="0666" 13 | 14 | and reload udev rules with 15 | 16 | $ sudo udevadm control --reload-rules 17 | $ sudo udevadm trigger 18 | 19 | Implemented and tested functions: 20 | * Echo: send data bytes a returned unchanged 21 | * ReadFile: read any file from the DSO filesystem 22 | * LockControlPanel: lock/unlock DSO control panel 23 | * StartAcquisition: start/stop acquisition in the DSO 24 | * KeyTrigger: lets you simulate the press of nearly any button on the DSO's control panel. 25 | * Screenshot: get a screenshot from the DSO (no color palette information) 26 | * ReadSystemTime: read the DSO's system time 27 | * RemoteShell: run shell commands in the DSO 28 | 29 | Implemented and not tested functions: 30 | * ReadSettings: read current DSO settings 31 | * ReadSampleData: read sample data from the DSO CH1/CH2 32 | -------------------------------------------------------------------------------- /Test1.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import time 5 | from rcr.dso5102p.DSO5102P import DSO5102P 6 | 7 | def main(): 8 | dso = DSO5102P( 0x049f, 0x505a, True ) 9 | 10 | r = dso.Echo( [ 1, 2, 3, 4, 5, 6 ] ) 11 | print( 'Echo:', r ) 12 | 13 | r = dso.ReadSystemTime() 14 | print( r ) 15 | 16 | # see inf/keyprotocol.inf 17 | # [FN-0-KEY] is 0x00, [MENU-ACQUIRE-KEY] is 0x0D and so on 18 | dso.KeyTrigger( 0x0C, 0x01 ) # MENU-MEASURE-KEY 19 | time.sleep( 4 ) 20 | dso.KeyTrigger( 0x0D, 0x01 ) # MENU-ACQUIRE-KEY 21 | 22 | print( 'Lock Panel' ) 23 | dso.LockControlPanel() 24 | time.sleep( 2 ) 25 | print( 'Unlock Panel' ) 26 | dso.UnLockControlPanel() 27 | 28 | print( 'Start Acquisition' ) 29 | dso.StartAcquisition() 30 | time.sleep( 2 ) 31 | print( 'Stop Acquisition' ) 32 | dso.StopAcquisition() 33 | time.sleep( 2 ) 34 | print( 'Start Acquisition' ) 35 | dso.StartAcquisition() 36 | 37 | # show time 38 | main() 39 | -------------------------------------------------------------------------------- /Test2.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import time 5 | from rcr.dso5102p.DSO5102P import DSO5102P 6 | 7 | def main(): 8 | dso = DSO5102P( 0x049f, 0x505a, True ) 9 | 10 | print( 'Listing /*.inf' ) 11 | r = dso.RemoteShell( 'ls /*.inf' ) 12 | print( r ) 13 | 14 | 15 | print( 'Getting keyprotocol.inf' ) 16 | r = dso.ReadFile( '/keyprotocol.inf' ) 17 | f=open( './inf/keyprotocol.inf', 'w' ) 18 | f.write( r ) 19 | f.close() 20 | 21 | print( 'Getting protocol.inf' ) 22 | r = dso.ReadFile( '/protocol.inf' ) 23 | f=open( './inf/protocol.inf', 'w' ) 24 | f.write( r ) 25 | f.close() 26 | 27 | print( 'Getting sys.inf' ) 28 | r = dso.ReadFile( '/sys.inf' ) 29 | f=open( './inf/sys.inf', 'w' ) 30 | f.write( r ) 31 | f.close() 32 | 33 | 34 | # show time 35 | main() 36 | -------------------------------------------------------------------------------- /Test3.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import time 5 | import numpy as np 6 | import cv2 7 | from rcr.dso5102p.DSO5102P import DSO5102P 8 | 9 | def main(): 10 | dso = DSO5102P( 0x049f, 0x505a, False ) 11 | 12 | print( 'Getting the screenshot' ) 13 | r = dso.Screenshot() 14 | 15 | print( 'Saving ...' ) 16 | st = dso.ReadSystemTime() 17 | cv2.imwrite( './screenshot/' + st + '.png', r ) 18 | 19 | print( 'Press ESC to exit ...' ) 20 | cv2.imshow( st, r ) 21 | while( cv2.waitKey(5) != 27 ): 22 | pass 23 | cv2.destroyAllWindows() 24 | 25 | # show time 26 | main() 27 | -------------------------------------------------------------------------------- /Test4.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import time 5 | import numpy as np 6 | import cv2 7 | from rcr.dso5102p.DSO5102P import DSO5102P 8 | 9 | def main(): 10 | dso = DSO5102P( 0x049f, 0x505a, False ) 11 | running = True 12 | while( running ): 13 | img = dso.Screenshot() 14 | img = cv2.applyColorMap( img, cv2.COLORMAP_HOT ) 15 | cv2.imshow( "DSO5102P", img ) 16 | if( cv2.waitKey(100) == 27 ): 17 | running = False 18 | cv2.destroyAllWindows() 19 | 20 | # show time 21 | main() 22 | -------------------------------------------------------------------------------- /Test5-MJPEG.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import time 5 | import numpy as np 6 | import cv2 7 | 8 | import http.server 9 | import socketserver 10 | 11 | from rcr.dso5102p.DSO5102P import DSO5102P 12 | 13 | class Streamer( http.server.SimpleHTTPRequestHandler ): 14 | def do_GET(self): 15 | self.send_response( 200 ) 16 | self.send_header( "Content-type", "multipart/x-mixed-replace; boundary=--boundary" ) 17 | self.end_headers() 18 | while(True): 19 | try: 20 | img = self.dso.Screenshot() 21 | #img = cv2.applyColorMap( img, cv2.COLORMAP_HOT ) 22 | _, data = cv2.imencode( '.JPEG', img, ( cv2.IMWRITE_JPEG_QUALITY, 80 ) ) 23 | self.wfile.write( b"--boundary\r\n" ) 24 | self.wfile.write( b"Content-Type: image/jpeg\r\n" ) 25 | self.wfile.write( b"Content-length: " + bytes( str( len( data) ).encode() ) ) 26 | self.wfile.write( b"\r\n" ) 27 | self.end_headers() 28 | self.wfile.write( data ) 29 | self.wfile.write( b"\r\n\r\n\r\n" ) 30 | #time.sleep( 0.100 ) 31 | except Exception as e: 32 | print( e ) 33 | break 34 | 35 | 36 | # show time 37 | if __name__ == '__main__': 38 | try: 39 | print( "Inicializando DSO5102P" ) 40 | Streamer.dso = DSO5102P( 0x049f, 0x505a, False ) 41 | 42 | print( "Levantando HTTP Server" ) 43 | server = socketserver.TCPServer( ('', 8080), Streamer ) 44 | server.serve_forever() 45 | except Exception as e: 46 | print( e ) 47 | 48 | -------------------------------------------------------------------------------- /docs/DSO5000P Series Digital Storage Oscilloscope User Manual(V1.1).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/titos-carrasco/DSO5102P-Python/181f290601c8eea43a00d8aa0add0d85ec8d19da/docs/DSO5000P Series Digital Storage Oscilloscope User Manual(V1.1).pdf -------------------------------------------------------------------------------- /docs/DSO5000P_Manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/titos-carrasco/DSO5102P-Python/181f290601c8eea43a00d8aa0add0d85ec8d19da/docs/DSO5000P_Manual.pdf -------------------------------------------------------------------------------- /inf/keyprotocol.inf: -------------------------------------------------------------------------------- 1 | [TOTAL] 49 2 | [START] 3 | [FN-0-KEY] 1 4 | [FN-1-KEY] 1 5 | [FN-2-KEY] 1 6 | [FN-3-KEY] 1 7 | [FN-4-KEY] 1 8 | [FN-5-KEY] 1 9 | [FN-6-KEY] 1 10 | [FN-7-KEY] 1 11 | [FN-MLEFT-KEY] 1 12 | [FN-MRIGHT-KEY] 1 13 | [FN-MZERO-KEY] 1 14 | [MENU-SR-KEY] 1 15 | [MENU-MEASURE-KEY] 1 16 | [MENU-ACQUIRE-KEY] 1 17 | [MENU-UTILITY-KEY] 1 18 | [MENU-CURSOR-KEY] 1 19 | [MENU-DISPLAY-KEY] 1 20 | [CT-AUTOSET-KEY] 1 21 | [CT-SINGLESEQ-KEY] 1 22 | [CT-RS-KEY] 1 23 | [CT-HELP-KEY] 1 24 | [CT-DS-KEY] 1 25 | [CT-STU-KEY] 1 26 | [VT-MATH-MENU-KEY] 1 27 | [VT-CH1-MENU-KEY] 1 28 | [VT-CH1-PSUB-KEY] 1 29 | [VT-CH1-PADD-KEY] 1 30 | [VT-CH1-PZERO-KEY] 1 31 | [VT-CH1-VBSUB-KEY] 1 32 | [VT-CH1-VBADD-KEY] 1 33 | [VT-CH2-MENU-KEY] 1 34 | [VT-CH2-PSUB-KEY] 1 35 | [VT-CH2-PADD-KEY] 1 36 | [VT-CH2-PZERO-KEY] 1 37 | [VT-CH2-VBSUB-KEY] 1 38 | [VT-CH2-VBADD-KEY] 1 39 | [HZ-MENU-KEY] 1 40 | [HZ-PSUB-KEY] 1 41 | [HZ-PADD-KEY] 1 42 | [HZ-PZERO-KEY] 1 43 | [HZ-TBSUB-KEY] 1 44 | [HZ-TBADD-KEY] 1 45 | [TG-MENU-KEY] 1 46 | [TG-PSUB-KEY] 1 47 | [TG-PADD-KEY] 1 48 | [TG-PZERO-KEY] 1 49 | [TG-PHALF-KEY] 1 50 | [TG-FORCE-KEY] 1 51 | [TG-PROBECHECK-KEY] 1 52 | [END] -------------------------------------------------------------------------------- /inf/protocol.inf: -------------------------------------------------------------------------------- 1 | [TOTAL] 208 2 | [START] 3 | [VERT-CH1-DISP] 1 4 | [VERT-CH1-VB] 1 5 | [VERT-CH1-COUP] 1 6 | [VERT-CH1-20MHZ] 1 7 | [VERT-CH1-FINE] 1 8 | [VERT-CH1-PROBE] 1 9 | [VERT-CH1-RPHASE] 1 10 | [VERT-CH1-CNT-FINE] 1 11 | [VERT-CH1-POS] 2 12 | [VERT-CH2-DISP] 1 13 | [VERT-CH2-VB] 1 14 | [VERT-CH2-COUP] 1 15 | [VERT-CH2-20MHZ] 1 16 | [VERT-CH2-FINE] 1 17 | [VERT-CH2-PROBE] 1 18 | [VERT-CH2-RPHASE] 1 19 | [VERT-CH2-CNT-FINE] 1 20 | [VERT-CH2-POS] 2 21 | [TRIG-STATE] 1 22 | [TRIG-TYPE] 1 23 | [TRIG-SRC] 1 24 | [TRIG-MODE] 1 25 | [TRIG-COUP] 1 26 | [TRIG-VPOS] 2 27 | [TRIG-FREQUENCY] 8 28 | [TRIG-HOLDTIME-MIN] 8 29 | [TRIG-HOLDTIME-MAX] 8 30 | [TRIG-HOLDTIME] 8 31 | [TRIG-EDGE-SLOPE] 1 32 | [TRIG-VIDEO-NEG] 1 33 | [TRIG-VIDEO-PAL] 1 34 | [TRIG-VIDEO-SYN] 1 35 | [TRIG-VIDEO-LINE] 2 36 | [TRIG-PULSE-NEG] 1 37 | [TRIG-PULSE-WHEN] 1 38 | [TRIG-PULSE-TIME] 8 39 | [TRIG-SLOPE-SET] 1 40 | [TRIG-SLOPE-WIN] 1 41 | [TRIG-SLOPE-WHEN] 1 42 | [TRIG-SLOPE-V1] 2 43 | [TRIG-SLOPE-V2] 2 44 | [TRIG-SLOPE-TIME] 8 45 | [TRIG-SWAP-CH1-TYPE] 1 46 | [TRIG-SWAP-CH1-MODE] 1 47 | [TRIG-SWAP-CH1-COUP] 1 48 | [TRIG-SWAP-CH1-EDGE-SLOPE] 1 49 | [TRIG-SWAP-CH1-VIDEO-NEG] 1 50 | [TRIG-SWAP-CH1-VIDEO-PAL] 1 51 | [TRIG-SWAP-CH1-VIDEO-SYN] 1 52 | [TRIG-SWAP-CH1-VIDEO-LINE] 2 53 | [TRIG-SWAP-CH1-PULSE-NEG] 1 54 | [TRIG-SWAP-CH1-PULSE-WHEN] 1 55 | [TRIG-SWAP-CH1-PULSE-TIME] 1 56 | [TRIG-SWAP-CH1-SLOPE-SET] 1 57 | [TRIG-SWAP-CH1-SLOPE-WIN] 1 58 | [TRIG-SWAP-CH1-SLOPE-WHEN] 1 59 | [TRIG-SWAP-CH1-SLOPE-V1] 2 60 | [TRIG-SWAP-CH1-SLOPE-V2] 2 61 | [TRIG-SWAP-CH1-SLOPE-TIME] 8 62 | [TRIG-SWAP-CH2-TYPE] 1 63 | [TRIG-SWAP-CH2-MODE] 1 64 | [TRIG-SWAP-CH2-COUP] 1 65 | [TRIG-SWAP-CH2-EDGE-SLOPE] 1 66 | [TRIG-SWAP-CH2-VIDEO-NEG] 1 67 | [TRIG-SWAP-CH2-VIDEO-PAL] 1 68 | [TRIG-SWAP-CH2-VIDEO-SYN] 1 69 | [TRIG-SWAP-CH2-VIDEO-LINE] 2 70 | [TRIG-SWAP-CH2-PULSE-NEG] 1 71 | [TRIG-SWAP-CH2-PULSE-WHEN] 1 72 | [TRIG-SWAP-CH2-PULSE-TIME] 8 73 | [TRIG-SWAP-CH2-SLOPE-SET] 1 74 | [TRIG-SWAP-CH2-SLOPE-WIN] 1 75 | [TRIG-SWAP-CH2-SLOPE-WHEN] 1 76 | [TRIG-SWAP-CH2-SLOPE-V1] 2 77 | [TRIG-SWAP-CH2-SLOPE-V2] 2 78 | [TRIG-SWAP-CH2-SLOPE-TIME] 8 79 | [TRIG-OVERTIME-NEG] 1 80 | [TRIG-OVERTIME-TIME] 8 81 | [HORIZ-TB] 1 82 | [HORIZ-WIN-TB] 1 83 | [HORIZ-WIN-STATE] 1 84 | [HORIZ-TRIGTIME] 8 85 | [MATH-DISP] 1 86 | [MATH-MODE] 1 87 | [MATH-FFT-SRC] 1 88 | [MATH-FFT-WIN] 1 89 | [MATH-FFT-FACTOR] 1 90 | [MATH-FFT-DB] 1 91 | [DISPLAY-MODE] 1 92 | [DISPLAY-PERSIST] 1 93 | [DISPLAY-FORMAT] 1 94 | [DISPLAY-CONTRAST] 1 95 | [DISPLAY-MAXCONTRAST] 1 96 | [DISPLAY-GRID-KIND] 1 97 | [DISPLAY-GRID-BRIGHT] 1 98 | [DISPLAY-MAXGRID-BRIGHT] 1 99 | [ACQURIE-MODE] 1 100 | [ACQURIE-AVG-CNT] 1 101 | [ACQURIE-TYPE] 1 102 | [ACQURIE-STORE-DEPTH] 1 103 | [MEASURE-ITEM1-SRC] 1 104 | [MEASURE-ITEM1] 1 105 | [MEASURE-ITEM2-SRC] 1 106 | [MEASURE-ITEM2] 1 107 | [MEASURE-ITEM3-SRC] 1 108 | [MEASURE-ITEM3] 1 109 | [MEASURE-ITEM4-SRC] 1 110 | [MEASURE-ITEM4] 1 111 | [MEASURE-ITEM5-SRC] 1 112 | [MEASURE-ITEM5] 1 113 | [MEASURE-ITEM6-SRC] 1 114 | [MEASURE-ITEM6] 1 115 | [MEASURE-ITEM7-SRC] 1 116 | [MEASURE-ITEM7] 1 117 | [MEASURE-ITEM8-SRC] 1 118 | [MEASURE-ITEM8] 1 119 | [CONTROL-TYPE] 1 120 | [CONTROL-MENUID] 1 121 | [CONTROL-DISP-MENU] 1 122 | [END] -------------------------------------------------------------------------------- /inf/sys.inf: -------------------------------------------------------------------------------- 1 | [DST type]dst1102b 2 | [soft version]3.40.0(200217.0) 3 | [fpga version]0xffff8108 4 | [start time]25 5 | [update time]0 6 | -------------------------------------------------------------------------------- /rcr/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/titos-carrasco/DSO5102P-Python/181f290601c8eea43a00d8aa0add0d85ec8d19da/rcr/__init__.py -------------------------------------------------------------------------------- /rcr/dso5102p/DSO5102P.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Thanks to: 4 | # https://elinux.org/Das_Oszi_Protocol (protocolo) 5 | # https://randomprojects.org/wiki/Voltcraft_DSO-3062C (uso de usb) 6 | # 7 | # My DSO5102P has idVendor=0x049f and idProduct=0x505a, EndpointAddress=0x81 and wMaxPacketSize=0x200 8 | # 9 | #-- 10 | 11 | import usb 12 | import time 13 | import array 14 | import numpy as np 15 | import cv2 16 | 17 | class DSO5102P(): 18 | def __init__( self, idVendor, idProduct, debug=False ): 19 | self.debug = debug 20 | self.dev = usb.core.find( idVendor=idVendor, idProduct=idProduct ) 21 | if( self.dev is None ): 22 | print( 'DSO5102P No Encontrado' ) 23 | exit() 24 | 25 | # unload de 'cdc_subset' 26 | if( self.dev.is_kernel_driver_active( 0 ) ): 27 | self.dev.detach_kernel_driver( 0 ) 28 | 29 | # limpia buffers 30 | while( True ): 31 | try: 32 | r = self.dev.read( 0x81, 512, 1000 ) 33 | self._dump( 'FLUSH', r ) 34 | except usb.core.USBError as e: 35 | print( 'FLUSH:', e ) 36 | break 37 | 38 | 39 | def _dump( self, origin, data ): 40 | if( self.debug ): 41 | print( origin, ':', [ '0x%02X' % h for h in data ] ) 42 | 43 | def _SendCommand( self, origin, cmd, data, isDebug=False ): 44 | assert isinstance( data, array.array ), '\'data\' must be array.array(\'B\')' 45 | 46 | time.sleep( 0.1 ) 47 | action = 0x43 if isDebug else 0x53 48 | packetLen = 1 + len( data ) + 1 49 | packet = array.array( 'B', [ action, packetLen & 0xFF, ( packetLen >> 8 ) & 0xFF, cmd ] ) + data 50 | packet = packet + array.array( 'B', [ sum( packet ) & 0xFF ] ) 51 | self._dump( origin.upper(), packet[:5] ) 52 | self.dev.write( 0x02, packet ) 53 | return packet 54 | 55 | def _ReadAnswer( self, origin, rcode ): 56 | r = None 57 | while( True ): 58 | r = self.dev.read( 0x81, 1024*1024, 500 ) 59 | chksum = sum( r[:-1] ) & 0xFF 60 | if( chksum != r[-1] ): 61 | self._dump( 'BADCHKSUM', r[:5] ) 62 | if( r[3] == rcode ): 63 | break 64 | else: 65 | self._dump( 'BADANSWER', r[:5] ) 66 | self._dump( origin, r[:5] ) 67 | return r 68 | 69 | #---- 70 | 71 | # OK 72 | def Echo( self, data ): 73 | data = array.array( 'B', data ) 74 | self._SendCommand( 'Echo', 0x00, data ) 75 | r = self._ReadAnswer( 'Echo', 0x80 ) 76 | return list( r[4:-1] ) 77 | 78 | def ReadSettings( self ): 79 | self._SendCommand( 'ReadSettings', 0x01, array.array( 'B' ) ) 80 | r = self._ReadAnswer( 'ReadSettings', 0x81 ) 81 | return r[4:-1] 82 | 83 | def ReadSampleData( self, channel ): 84 | self._SendCommand( 'ReadSampleData', 0x02, array.array( 'B', [ 0x01, channel & 0x01 ] ) ) 85 | r = array.array( 'B' ) 86 | sdlen = 0 87 | while( True ): 88 | d = self._ReadAnswer( 'ReadSampleData', 0x82 ) 89 | if( d[4] == 0x00 ): 90 | sdlen = d[5] + (d[6]<<8) + (d[7]<<16) 91 | elif( d[4] == 0x01 ): 92 | r = r + d[6:-1] 93 | elif( d[4] == 0x02 ): 94 | # d[6] == channel 95 | break; 96 | else: 97 | # some error 98 | # d[6] == channel 99 | break; 100 | #print( sdlen, len( r ) ) 101 | return r 102 | 103 | # OK 104 | def ReadFile( self, fname ): 105 | p = self._SendCommand( 'ReadFile', 0x10, array.array( 'B', bytearray( '\x00' + fname, 'utf8' ) ) ) 106 | r = array.array( 'B' ) 107 | while( True ): 108 | d = self._ReadAnswer( 'ReadFile', 0x90 ) 109 | if( d[4] == 0x01 ): 110 | r = r + d[5:-1] 111 | else: 112 | # checksum??? 113 | break; 114 | r = ''.join( [ chr( c ) for c in r ] ) 115 | return r 116 | 117 | # OK 118 | def LockControlPanel( self ): 119 | self._SendCommand( 'LockControlPanel', 0x12, array.array( 'B', [ 0x01, 0x01 ] ) ) 120 | r = self._ReadAnswer( 'LockControlPanel', 0x92 ) 121 | 122 | # OK 123 | def UnLockControlPanel( self ): 124 | self._SendCommand( 'UnLockControlPanel', 0x12, array.array( 'B', [ 0x01, 0x00 ] ) ) 125 | r = self._ReadAnswer( 'UnLockControlPanel', 0x92 ) 126 | 127 | # OK 128 | def StartAcquisition( self ): 129 | self._SendCommand( 'StartAcquisition', 0x12, array.array( 'B', [ 0x00, 0x00 ] ) ) 130 | r = self._ReadAnswer( 'StartAcquisition', 0x92 ) 131 | 132 | # OK 133 | def StopAcquisition( self ): 134 | self._SendCommand( 'StopAcquisition', 0x12, array.array( 'B', [ 0x00, 0x01 ] ) ) 135 | r = self._ReadAnswer( 'StopAcquisition', 0x92 ) 136 | 137 | # OK 138 | def KeyTrigger( self, b1, b2 ): 139 | self._SendCommand( 'KeyTrigger', 0x13, array.array( 'B', [ b1, b2 ] ) ) 140 | r = self._ReadAnswer( 'KeyTrigger', 0x93 ) 141 | 142 | # OK 143 | def Screenshot( self ): 144 | self._SendCommand( 'Screenshot', 0x20, array.array( 'B' ) ) 145 | bmp = array.array( 'B' ) 146 | while( True ): 147 | d = self._ReadAnswer( 'Screenshot', 0xA0 ) 148 | if( d[4] == 0x01 ): 149 | bmp = bmp + d[5:-1] 150 | else: 151 | # checksum??? 152 | break; 153 | img = np.frombuffer( bytearray( bmp ), dtype=np.uint16 ).reshape( 480, 800 ) 154 | img = img.astype( np.uint8 ) 155 | return img 156 | 157 | # OK 158 | def ReadSystemTime( self ): 159 | self._SendCommand( 'ReadSystemTime', 0x21, array.array( 'B' ) ) 160 | r = self._ReadAnswer( 'ReadSystemTime', 0xA1 ) 161 | r = '%04d-%02d-%02d %02d:%02d:%02d' % ( r[5]*0xFF + r[4] + 7, r[6], r[7], r[8], r[9], r[10] ) 162 | return r 163 | 164 | # OK 165 | def RemoteShell( self, cmdline ): 166 | self._SendCommand( 'RemoteShell', 0x11, array.array( 'B', bytearray( cmdline, 'utf8' ) ), True ) 167 | r = self._ReadAnswer( 'RemoteShell', 0x91 ) 168 | r = ''.join( [ chr( c ) for c in r ] ) 169 | return r 170 | 171 | -------------------------------------------------------------------------------- /rcr/dso5102p/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /screenshot/2019-05-05 11:57:16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/titos-carrasco/DSO5102P-Python/181f290601c8eea43a00d8aa0add0d85ec8d19da/screenshot/2019-05-05 11:57:16.png -------------------------------------------------------------------------------- /screenshot/2019-05-05 11:58:17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/titos-carrasco/DSO5102P-Python/181f290601c8eea43a00d8aa0add0d85ec8d19da/screenshot/2019-05-05 11:58:17.png -------------------------------------------------------------------------------- /screenshot/2019-05-05 11:58:48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/titos-carrasco/DSO5102P-Python/181f290601c8eea43a00d8aa0add0d85ec8d19da/screenshot/2019-05-05 11:58:48.png -------------------------------------------------------------------------------- /screenshot/DSO5102p 09-11-2023 07:37:26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/titos-carrasco/DSO5102P-Python/181f290601c8eea43a00d8aa0add0d85ec8d19da/screenshot/DSO5102p 09-11-2023 07:37:26.png --------------------------------------------------------------------------------