pax_global_header00006660000000000000000000000064133463256730014526gustar00rootroot0000000000000052 comment=e94434d11a117f25ef5c1a6a2eb8058e39542420 pyvisa-py-0.3.1/000077500000000000000000000000001334632567300134705ustar00rootroot00000000000000pyvisa-py-0.3.1/.gitignore000066400000000000000000000003021334632567300154530ustar00rootroot00000000000000*~ __pycache__ *egg-info* *.pyc .DS_Store docs/_build/ .idea build/ dist/ MANIFEST .tox .coveragerc # WebDAV file system cache files .DAV/ _test/ .spyproject/ .mypy_cache/ .pytest_cache/ .cache/pyvisa-py-0.3.1/.travis.yml000066400000000000000000000013511334632567300156010ustar00rootroot00000000000000language: python # newer python versions are available only on xenial # (while some older only on trusty) Ubuntu distribution dist: xenial sudo: required branches: only: # This is where pull requests from "bors r+" are built. - staging # This is where pull requests from "bors try" are built. - trying # Build master too - master matrix: include: - python: 2.7 dist: trusty - python: 3.4 dist: trusty - python: 3.5 dist: trusty - python: 3.6 - python: 3.7 install: - pip install coverage - pip install coveralls script: - python -bb -m coverage run -p --source=pyvisa-py --omit="*test*" setup.py test - coverage combine - coverage report -m after_script: - coveralls --verbose pyvisa-py-0.3.1/AUTHORS000066400000000000000000000011411334632567300145350ustar00rootroot00000000000000pyvisa-py is written and maintained by Hernan E. Grecco . Other contributors, listed alphabetically, are: * Alex Forencich * Alexander Bessman * Colin Marquardt * Lance McCulley * Martin Ritter * Matthieu Dartiailh * Sebastian Held * Thomas Kopp <20.kopp@gmail.com> * Thorsten Liebig * Tobias Müller (If you think that your name belongs here, please let the maintainer know) pyvisa-py-0.3.1/CHANGES000066400000000000000000000046321334632567300144700ustar00rootroot00000000000000PyVISA-py Changelog =================== 0.3.1 (2018-09-12) ------------------ - Fix initialization of timeout (issue identified in TCPIP resources) PR #160 0.3 (2018-09-05) ---------------- - Fix handling of seesion registration under Python 3.7 PR #155 - Add read_stb, assert_trigger, lock, unlock to highlevel PR #139 - Fix timeout handling in usb PR #144 - Add gpib_command and assert_trigger to GPIB PR # 136 - Handle ValueError in usb list fix #131 PR #132 - Fix reading on GPIB and implement clear and gpib_send_ifc PR #132 - Do not error when listing USB devices PR #126 - Fix an error in the handling of the termchar for TCPIP INSTR PR #126 - Make list_resources return an empty tuple instead of erroring PR #121 - Proper support for timeout in TCPIP INSTR sessions PR #120 #127 #130 #144 - Proper encoding of data before transfer for all backends PR #119 - Unify use of StatusCode PR #118 - Improve handling of sessions attrs PR #116 - TCPIP SOCKET timeout handling improvement PR #115 - Fix compatibility with pyserial 3.0 PR #112 - TCPIP SOCKET handler read should not block PR #107 - TCPIP error handling fixes PR #100 - Use repr() instead of str() to log RPC record PR #97 - Speed up large transfer over GPIB 2beb52a5bcea2dae32d4a9908dc19f7874bfc0b7 - Catch GPIB errors while enumerating devices 9fea9d5c40cc6c33ce1244c209e5e576a33abfc2 - Add a serial poll function to GPIB backend PR #67 - Handle timeout in USB TMC backend PR #64 - Make USB TMC backend faster by transferring multiple bytes PR #63 - Fix issue with encoding before data transfer PR #59 # - Get Linux GPIB version PR #55 - Fix broken import in TCPIP sessions PR #51 0.2 (2015-08-25) ---------------- - Added support for TCPIP Socket. (Issue #38, thanks Thorsten Liebig) - Added support for GPIB INSTR using linux-gpib. (Issue #24, thanks bessman) - Added support for USB RAW. (Issue #18, kopp) - Better error reporting when pyusb or pyserial is missing. - Fixed logging of unicode strings. (Issue #54) - Fixed timeout in SerialSession. (Issue #44) - Moved resource name parsing to PyVISA. - VXI11 protocol performance enhancement. (thanks alexforencich) - Improved pyusb importing. - Fixed large binary reads in TCPIP. - Added backend information to logger. - Use pyvisa compat/struct.py for python < 2.7.8 (thanks Martin Ritter) 0.1 (2015-02-08) ---------------- - Initial release. Preliminary support for: - USB INSTR - TCPIP INSTR - ASRL INSTR pyvisa-py-0.3.1/LICENSE000066400000000000000000000021241334632567300144740ustar00rootroot00000000000000The MIT License Copyright (c) 2014 PyVISA-py Authors and contributors. See AUTHORS Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pyvisa-py-0.3.1/MANIFEST.in000066400000000000000000000002461334632567300152300ustar00rootroot00000000000000include README AUTHORS CHANGES LICENSE recursive-include pyvisa-py * recursive-include docs * prune docs/_build global-exclude *.pyc *~ .DS_Store *__pycache__* *.pyo pyvisa-py-0.3.1/README000066400000000000000000000035211334632567300143510ustar00rootroot00000000000000PyVISA-py ========= A PyVISA backend that implements a large part of the "Virtual Instrument Software Architecture" (VISA_) in pure Python (with the help of some nice cross platform libraries python packages!). Description ----------- PyVISA started as wrapper for the NI-VISA library and therefore you need to install National Instruments VISA library in your system. This works most of the time, for most people. But NI-VISA is a proprietary library that only works on certain systems. That is when PyVISA-py jumps in. Starting from version 1.6, PyVISA allows to use different backends. These backends can be dynamically loaded. PyVISA-py is one of such backends. It implements most of the methods for Message Based communication (Serial/USB/GPIB/Ethernet) using Python and some well developed, easy to deploy and cross platform libraries .. _VISA: http://www.ivifoundation.org/Downloads/Specifications.htm VISA and Python --------------- Python has a couple of features that make it very interesting for measurement controlling: - Python is an easy-to-learn scripting language with short development cycles. - It represents a high abstraction level, which perfectly blends with the abstraction level of measurement programs. - It has a very rich set of native libraries, including numerical and plotting modules for data analysis and visualisation. - A large set of books (in many languages) and on-line publications is available. Requirements ------------ - Python (tested with 2.7, 3.4+) - PyVISA 1.6+ Optionally - PySerial (to interface with Serial instruments) - PyUSB (to interface with USB instruments) - linux-gpib (to interface with gpib instruments, only on linux) Installation -------------- Using pip: $ pip install pyvisa-py Documentation -------------- The documentation can be read online at https://pyvisa-py.readthedocs.org pyvisa-py-0.3.1/docs/000077500000000000000000000000001334632567300144205ustar00rootroot00000000000000pyvisa-py-0.3.1/docs/Makefile000066400000000000000000000127101334632567300160610ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pyvisa-py.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pyvisa-py.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/pyvisa-py" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pyvisa-py" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." pyvisa-py-0.3.1/docs/_static/000077500000000000000000000000001334632567300160465ustar00rootroot00000000000000pyvisa-py-0.3.1/docs/_static/logo-full.jpg000066400000000000000000000252221334632567300204530ustar00rootroot00000000000000JFIFHH@ICC_PROFILE0appl mntrRGB XYZ   acspAPPLappl-appl dscmdescogXYZlwtptrXYZbXYZrTRCcprt8chad,gTRCbTRCmluc enUS&~esES&daDK.deDE,fiFI(frFU(*itIT(VnlNL(nbNO&ptBR&svSE&jaJPRkoKR@zhTWlzhCNruRU"plPL,Yleinen RGB-profiiliGenerisk RGB-profilProfil Gnrique RVBN, RGB 000000u( RGB r_icϏPerfil RGB GenricoAllgemeines RGB-Profilfn RGB cϏeNGenerel RGB-beskrivelseAlgemeen RGB-profiel| RGB \ |Profilo RGB GenericoGeneric RGB Profile1I89 ?@>D8;L RGBUniwersalny profil RGBdescGeneric RGB ProfileGeneric RGB ProfileXYZ Zus4XYZ RXYZ tM=XYZ (6curvtextCopyright 2007 Apple Inc., all rights reserved.sf32 B&lExifMM*bj(1r2iHHAdobe Photoshop CS4 Macintosh2013:08:26 20:57:27C     C  " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(((((((((((((((((?>0 vr_M.p5?/ShFE0<ٺ;7 #Ě'KM!I?P1_",G;In=:lw{e%$qƬd+?ioSKI ^iyyY_$XnkOyw eZns&}hE()8}gu|}x3,\lI>|H֗Jϊ[Wc,Y2Dk*|UVnRi䉃# ??\_`n\{>7sjo#Xy<c+g'@uI%ƻi4}떅ʬB_G)kM'B=~IT:(:(((((((((Ց_iz52X[b}4jH4{^^X[ZZ4~ /$0x~1|d_?/=F~q^#H ؠ*Af㠯nT䜏ˎ>ʊjֹ֓3eN+i{O~(|h}Yn-|w$D2Å8<%Ə/\xIrNɯ[U9:ౖ\GʼFRjT{4i|1SASѵ,1"δ1>ܼ8g܏TmtN}w~ֿqyY_8⠻g~A~x3[Wڋlv+6`ihcBt*:r:(` ( ( ( ( ( ( ( ( ֿa?zK?8?} _:~K?/KXV]aqNr}n _ SџfI֐<#wַ<mO? &^&_ Bff:U%&좯#Zw9%{v,6U#" ks4g"8vq?}t1Ox#?%cmk" KUS{8.vp: q]Sx[E p0ݲ1.#Sd }Z\ͫ~yg؊׳}vg??t߮8)S7Ka|\.+ >[މy:sq+'O*v;Gg&s5NY3qg3ʶ??vzX :Odz ' 'I5{t'Ҿ|SjWY_A!ʟcJu%y?6 j9EEPEPEPEPEPEPEPEP\{?x3Y5a-P}pt9EhJ->oE a)T0yiwD1>?K -{7W>ǶG h"[|%xb2{7|wc/ x Eu kwl4E'a}3Tk>25ә3.c7T%B>lgǐG9Qu[ͫk'Kt9+Yrݖ5EhZ*K[: 9ϯJcxPKǚö==է`9om*.V3@˃Аq>|-O <;gnw 1sƺ<kHUcBk\neB*O[H+q 7 S2oqඞ?.u~\5_Z01{Ud򬾖 ?.c*b3?QEEPEPEPEPEPEPEPEPEPUg]{֭Td ٬3(KiK?ķs F<5ϼ7=kWBҵ0j=j˿vpZQ&xS%&,Q4 s2 c澁6EyaxRIG2JC$( }~'0xzή-F]#l]xs6cTWލo.⋿?\k&%s"8ݜk1"!|gϦjljUo)^87Tf lY,k9\g5dwu;|~55jlhFsW!n]VҠ>M=tѱEӻ'VR\sY';L麄:^=FLyX $g߲o߈?q:]˧77S4JCIbcbNH5' qIŻ[&m cqJ?MZ+h=ew%-tb}$t 33^vU8&zJU%W=Ҋ}|o#m-3OU..aK3ʇQq99f_g,-t#nS"Oq! G @$9՞SJ:XjՔRVC6W7wQ_fo|ocj4JIDDۈs=_7>4|6GiGOE9 8\mĪ'9>kk<_6qE|/2~>:-\u_ _^heiW3 "HPgI8'%H-BI_1ң[Nu>Z=Z|w$wXgv fcyşv-/y<.|Ckʴ_-|E?h1RO \ޘ4=CNIl:>ˢ> un0KkLHh }~} .^:$*Wk? N&rX*ivO#|Iً6P]:;PoHxC. /Nf&`IP | x BQ~V嘼Mhk (ۃψ+x'FHԵ *KY2LQ!hI*ge1у}{fY0XyVGW.o[ Ũ\#U2 ;Q0XQ]{[7VL(;¼5& 5&0^?0`8:]_şw߈]Vk5)C(T?*i x+Km?I-migTE`5\SI4(u$GinUm="#Egeq֭3­gJ7e՟gxo-uAeitKyL$*2#,p{şG>6x3ִwhxգu J4M?H<6~>a!|^4T+cpΗ~͟xuׁ[MM^0a O?1_q ,NX^|}MBs_x4Jw^y>rp/ᦛvqV"Kg_ ߱gtɡh O+ \0;BG5 "EE,q"F0M_7*V[ɷAN;E$|;|ɟxk+$>/WIeG&}LĿ9\%}rsO>'5=LVmJװ*&WPDWmE|u9MK!i5C:̰[ϪXr@iiap2;p>~W_/*xD~wW uYntI,DDO8_=6|u ?|W&]n!qyLs$97͢N=UTuG?V[ž1|oxG\״giJwV⺚IQ>Ҕ] ^V 4UyntkG'OVl΄c{If̂+ 2CfI7WW4qpd\VP'+?_{ _/?EWb>&ة4U>&ة4_'2y@?6?'R{3zӥ0x#I++N8kolRr蝗|]?=_YxŖ$A[+'̒BW4Q_wl} C OlE[^e֭vF庈mg_ß$Sn+ç륧_ɽN]@~6~~~~V6۶e\gKq;dIA1 }/ Ԏ*\>s ^>vվhcgu*8e5{Za?~W^4f⛟2" H2T#xTkMō֖y2o& 9%>'6ZMm>;[XD5R,+zN旧E}fKXAr׫V*?og^- ^ŬoGuuhs/nU/c_d7QжnH@y9cNOfu=>"}cR+u8|i!d\t7 -$%\z Q>6WQF[KVn}9 +lt, j6L-\cH''6s<^U3ӂ;d#a8,w-=74|Sy7(SE&}LĿ9\%rK?`o3qUI>?jt)ş`:h0|<ަmW2u%5> ' G ? a%~/l]&Ǟiy20 A=i;KhNլ%o#捿V ] <-(1UnX{Cq޾l`1w<Dou)SX{Q6ݟ)as*(Jm??o? o(}xy`*I aXe*yh֚o_5[u-J6 2GT+3Q/i3oXX81 ,D潿uSQbj9{&8*0}ҷ~ؚW~-cĚVZho@~5:xPg\Wd㬾ro(>'*8tjzml̖KwD]@$ kqEH)?7d:9j6$p]`#ºDw]>I[i^6 )rXPI~_A9=-Qss{Y߽#ُw4w|YstFu_3DAmml23}3úekA.5GI 8Qyncө:9JإqIhZ-G )6o]Oƈ>$ֿ5Z\WnP1\0aw&ހ9qei:agaN.e%u'C_tW."TiYgSib?<<|fu<]CwGѮ$I5 WYusGo @#v(9+ំOVD" $GZh+4kcdcV=<&[r~h~Oث⏇ 77pI\%>21I+d|W}V9i[YTi[M|-m{__foz핮xᗆtۨu(.c- )Ul_8_UeylWRN=4NgSPڳ24{ Z5I#{2g/UN$d8$sZQ^cbQE ( e v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} html_sidebars = { 'index': ['sidebarintro.html', 'sourcelink.html', 'searchbox.html'], '**': ['sidebarlogo.html', 'localtoc.html', 'relations.html', 'sourcelink.html', 'searchbox.html'] } # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'pyvisa-pytdoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'pyvisa-py.tex', 'PyVISA Documentation', 'PyVISA Authors', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'pyvisa-py', 'PyVISA Documentation', ['PyVISA Authors'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'PyVISA', 'PyVISA Documentation', 'PyVISA Authors', 'PyVISA', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # -- Options for Epub output --------------------------------------------------- # Bibliographic Dublin Core info. epub_title = project epub_author = author epub_publisher = author epub_copyright = copyright # The language of the text. It defaults to the language option # or en if the language is not set. #epub_language = '' # The scheme of the identifier. Typical schemes are ISBN or URL. #epub_scheme = '' # The unique identifier of the text. This can be a ISBN number # or the project homepage. #epub_identifier = '' # A unique identification for the text. #epub_uid = '' # A tuple containing the cover image and cover page html template filenames. #epub_cover = () # HTML files that should be inserted before the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_pre_files = [] # HTML files shat should be inserted after the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_post_files = [] # A list of files that should not be packed into the epub file. #epub_exclude_files = [] # The depth of the table of contents in toc.ncx. #epub_tocdepth = 3 # Allow duplicate toc entries. #epub_tocdup = True # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'python': ('http://docs.python.org/2', None)} pyvisa-py-0.3.1/docs/index.rst000066400000000000000000000071001334632567300162570ustar00rootroot00000000000000:orphan: PyVISA-py: Pure Python backend for PyVISA ========================================= .. image:: _static/logo-full.jpg :alt: PyVISA PyVISA-py is a backend for PyVISA_. It implements most of the methods for Message Based communication (Serial/USB/GPIB/Ethernet) using Python and some well developed, easy to deploy and cross platform libraries. You can select the PyVISA-py backend using **@py** when instantiating the visa Resource Manager: >>> import visa >>> rm = visa.ResourceManager('@py') >>> rm.list_resources() ('USB0::0x1AB1::0x0588::DS1K00005888::INSTR') >>> inst = rm.open_resource('USB0::0x1AB1::0x0588::DS1K00005888::INSTR') >>> print(inst.query("*IDN?")) That's all! Except for **@py**, the code is exactly what you would write to using the NI-VISA backend for PyVISA. Installation ============ Just run the following command in your console: pip install pyvisa-py You can report a problem or ask for features in the `issue tracker`_. Or get the code in GitHub_. FAQ === Which libraries are used by PyVISA-py? -------------------------------------- It depends on the interface type. For **ASRL** and **USB** we use PySerial_ and PyUSB_ respectively. For **TCPIP** we use the :py:mod:`socket` module in the Python Standard Library. **GPIB** resources are not currently supported but they are in the plan using `linux-gpib`_. PySerial_ version 3.0 or newer is required. If I only need **TCPIP**, do I need to install PySerial and PyUSB? ------------------------------------------------------------------ No. Libraries are loaded on demand. How do I know if PyVISA-py is properly installed? ------------------------------------------------- Using the pyvisa information tool. Run in your console:: python -m visa info You will get info about PyVISA, the installed backends and their options. Which resource types are supported? ----------------------------------- Now: - ASRL INSTR - USB INSTR - TCPIP INSTR - USB RAW - TCPIP SOCKET - GPIB INSTR Are all VISA attributes and methods implemented? ------------------------------------------------ No. We have implemented those attributes and methods that are most commonly needed. We would like to reach feature parity. If there is something that you need, let us know. Why are you developing this? ---------------------------- The `National Instruments's VISA`_ is a proprietary library that only works on certain systems. We wanted to provide a compatible alternative. Why not using LibreVISA? ------------------------ LibreVISA_ is still young. However, you can already use it with the NI backend as it has the same API. We think that PyVISA-py is easier to hack and we can quickly reach feature parity with NI-VISA for message-based instruments. Why putting PyVISA in the middle? --------------------------------- Because it allows you to change the backend easily without changing your application. In other projects we implemented classes to call USBTMC devices without PyVISA. But this leads to code duplication or an adapter class in your code. By using PyVISA as a frontend to many backends, we abstract these things from higher level applications. .. _PySerial: http://pyserial.sourceforge.net/ .. _PyVISA: http://pyvisa.readthedocs.org/ .. _PyUSB: http://walac.github.io/pyusb/ .. _PyPI: https://pypi.python.org/pypi/PyVISA-py .. _GitHub: https://github.com/pyvisa/pyvisa-py .. _`National Instruments's VISA`: http://ni.com/visa/ .. _`LibreVISA`: http://www.librevisa.org/ .. _`issue tracker`: https://github.com/pyvisa/pyvisa-py/issues .. _`linux-gpib`: http://linux-gpib.sourceforge.net/ pyvisa-py-0.3.1/docs/make.bat000066400000000000000000000122541334632567300160310ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\pyvisa-py.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\pyvisa-py.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end pyvisa-py-0.3.1/pyvisa-py/000077500000000000000000000000001334632567300154315ustar00rootroot00000000000000pyvisa-py-0.3.1/pyvisa-py/__init__.py000066400000000000000000000013401334632567300175400ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ pyvisa-py ~~~~~~~~~ Pure Python backend for PyVISA. :copyright: 2014 by PyVISA-py Authors, see AUTHORS for more details. :license: MIT, see LICENSE for more details. """ from __future__ import division, unicode_literals, print_function, absolute_import import pkg_resources __version__ = "unknown" try: # pragma: no cover __version__ = pkg_resources.get_distribution('pyvisa-py').version except: # pragma: no cover pass # we seem to have a local copy without any repository control or installed without setuptools # so the reported version will be __unknown__ from .highlevel import PyVisaLibrary WRAPPER_CLASS = PyVisaLibrary pyvisa-py-0.3.1/pyvisa-py/common.py000066400000000000000000000035401334632567300172750ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ pyvisa-sim.common ~~~~~~~~~~~~~~~~~ Common code. :copyright: 2014 by PyVISA-sim Authors, see AUTHORS for more details. :license: MIT, see LICENSE for more details. """ from __future__ import (division, unicode_literals, print_function, absolute_import) import logging import sys from pyvisa import logger logger = logging.LoggerAdapter(logger, {'backend': 'py'}) class MockInterface(object): def __init__(self, resource_name): self.resource_name = resource_name class NamedObject(object): """A class to construct named sentinels. """ def __init__(self, name): self.name = name def __repr__(self): return '<%s>' % self.name __str__ = __repr__ if sys.version >= '3': def iter_bytes(data, mask=None, send_end=False): if send_end and mask is None: raise ValueError('send_end requires a valid mask.') if mask is None: for d in data[:]: yield bytes([d]) else: for d in data[:-1]: yield bytes([d & ~mask]) if send_end: yield bytes([data[-1] | ~mask]) else: yield bytes([data[-1] & ~mask]) int_to_byte = lambda val: bytes([val]) last_int = lambda val: val[-1] else: def iter_bytes(data, mask=None, send_end=False): if send_end and mask is None: raise ValueError('send_end requires a valid mask.') if mask is None: for d in data[:]: yield d else: for d in data[:-1]: yield chr(ord(d) & ~mask) if send_end: yield chr(ord(data[-1]) | ~mask) else: yield chr(ord(data[-1]) & ~mask) int_to_byte = chr last_int = lambda val: ord(val[-1]) pyvisa-py-0.3.1/pyvisa-py/gpib.py000066400000000000000000000310741334632567300167310ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ pyvisa-py.gpib ~~~~~~~~~~~~~~ GPIB Session implementation using linux-gpib. :copyright: 2015 by PyVISA-py Authors, see AUTHORS for more details. :license: MIT, see LICENSE for more details. """ from __future__ import division, unicode_literals, print_function, absolute_import from bisect import bisect from pyvisa import constants, logger, attributes from .sessions import Session, UnknownAttribute try: import gpib from Gpib import Gpib except ImportError as e: Session.register_unavailable(constants.InterfaceType.gpib, 'INSTR', 'Please install linux-gpib to use this resource type.\n%s' % e) raise def _find_listeners(): """Find GPIB listeners. """ for i in range(31): try: if gpib.listener(BOARD, i) and gpib.ask(BOARD, 1) != i: yield i except gpib.GpibError as e: logger.debug("GPIB error in _find_listeners(): %s", repr(e)) StatusCode = constants.StatusCode # linux-gpib timeout constants, in seconds. See GPIBSession._set_timeout. TIMETABLE = (0, 10e-6, 30e-6, 100e-6, 300e-6, 1e-3, 3e-3, 10e-3, 30e-3, 100e-3, 300e-3, 1.0, 3.0, 10.0, 30.0, 100.0, 300.0, 1000.0) # TODO: Check board indices other than 0. BOARD = 0 # TODO: Check secondary addresses. @Session.register(constants.InterfaceType.gpib, 'INSTR') class GPIBSession(Session): """A GPIB Session that uses linux-gpib to do the low level communication. """ @staticmethod def list_resources(): return ['GPIB0::%d::INSTR' % pad for pad in _find_listeners()] @classmethod def get_low_level_info(cls): try: ver = gpib.version() except AttributeError: ver = '< 4.0' return 'via Linux GPIB (%s)' % ver def after_parsing(self): minor = int(self.parsed.board) pad = int(self.parsed.primary_address) sad = 0 timeout = 13 send_eoi = 1 eos_mode = 0 self.interface = Gpib(name=minor, pad=pad, sad=sad, timeout=timeout, send_eoi=send_eoi, eos_mode=eos_mode) self.controller = Gpib(name=minor) # this is the bus controller device self.handle = self.interface.id # force timeout setting to interface self.set_attribute(constants.VI_ATTR_TMO_VALUE, attributes.AttributesByID[constants.VI_ATTR_TMO_VALUE].default) def _get_timeout(self, attribute): if self.interface: # 0x3 is the hexadecimal reference to the IbaTMO (timeout) configuration # option in linux-gpib. gpib_timeout = self.interface.ask(3) if gpib_timeout and gpib_timeout < len(TIMETABLE): self.timeout = TIMETABLE[gpib_timeout] else: # value is 0 or out of range -> infinite self.timeout = None return super(GPIBSession, self)._get_timeout(attribute) def _set_timeout(self, attribute, value): """ linux-gpib only supports 18 discrete timeout values. If a timeout value other than these is requested, it will be rounded up to the closest available value. Values greater than the largest available timout value will instead be rounded down. The available timeout values are: 0 Never timeout. 1 10 microseconds 2 30 microseconds 3 100 microseconds 4 300 microseconds 5 1 millisecond 6 3 milliseconds 7 10 milliseconds 8 30 milliseconds 9 100 milliseconds 10 300 milliseconds 11 1 second 12 3 seconds 13 10 seconds 14 30 seconds 15 100 seconds 16 300 seconds 17 1000 seconds """ status = super(GPIBSession, self)._set_timeout(attribute, value) if self.interface: if self.timeout is None: gpib_timeout = 0 else: # round up only values that are higher by 0.1% than discrete values gpib_timeout = min(bisect(TIMETABLE, 0.999 * self.timeout), 17) self.timeout = TIMETABLE[gpib_timeout] self.interface.timeout(gpib_timeout) return status def close(self): gpib.close(self.handle) def read(self, count): """Reads data from device or interface synchronously. Corresponds to viRead function of the VISA library. :param count: Number of bytes to be read. :return: data read, return value of the library call. :rtype: bytes, constants.StatusCode """ # 0x2000 = 8192 = END checker = lambda current: self.interface.ibsta() & 8192 reader = lambda: self.interface.read(count) return self._read(reader, count, checker, False, None, False, gpib.GpibError) def write(self, data): """Writes data to device or interface synchronously. Corresponds to viWrite function of the VISA library. :param data: data to be written. :type data: bytes :return: Number of bytes actually transferred, return value of the library call. :rtype: int, VISAStatus """ logger.debug('GPIB.write %r' % data) try: self.interface.write(data) count = self.interface.ibcnt() # number of bytes transmitted return count, StatusCode.success except gpib.GpibError: # 0x4000 = 16384 = TIMO if self.interface.ibsta() & 16384: return 0, StatusCode.error_timeout else: return 0, StatusCode.error_system_error def clear(self): """Clears a device. Corresponds to viClear function of the VISA library. :param session: Unique logical identifier to a session. :return: return value of the library call. :rtype: :class:`pyvisa.constants.StatusCode` """ logger.debug('GPIB.device clear') try: self.interface.clear() return 0, StatusCode.success except Exception: return 0, StatusCode.error_system_error def gpib_command(self, command_byte): """Write GPIB command byte on the bus. Corresponds to viGpibCommand function of the VISA library. See: https://linux-gpib.sourceforge.io/doc_html/gpib-protocol.html#REFERENCE-COMMAND-BYTES :param command_byte: command byte to send :type command_byte: int, must be [0 255] :return: return value of the library call :rtype: :class:`pyvisa.constants.StatusCode` """ if 0 <= command_byte <= 255: data = chr(command_byte) else: return StatusCode.error_nonsupported_operation try: self.controller.command(data) return StatusCode.success except gpib.GpibError: return StatusCode.error_system_error def trigger(self, protocol): """Asserts hardware trigger. Only supports protocol = constants.VI_TRIG_PROT_DEFAULT :return: return value of the library call. :rtype: :class:`pyvisa.constants.StatusCode` """ logger.debug('GPIB.device assert hardware trigger') try: if protocol == constants.VI_TRIG_PROT_DEFAULT: self.interface.trigger() return StatusCode.success else: return StatusCode.error_nonsupported_operation except gpib.GpibError: return StatusCode.error_system_error def gpib_send_ifc(self): """Pulse the interface clear line (IFC) for at least 100 microseconds. Corresponds to viGpibSendIFC function of the VISA library. :param session: Unique logical identifier to a session. :return: return value of the library call. :rtype: :class:`pyvisa.constants.StatusCode` """ logger.debug('GPIB.interface clear') try: self.controller.interface_clear() return 0, StatusCode.success except: return 0, StatusCode.error_system_error def _get_attribute(self, attribute): """Get the value for a given VISA attribute for this session. Use to implement custom logic for attributes. :param attribute: Resource attribute for which the state query is made :return: The state of the queried attribute for a specified resource, return value of the library call. :rtype: (unicode | str | list | int, VISAStatus) """ if attribute == constants.VI_ATTR_GPIB_READDR_EN: # IbaREADDR 0x6 # Setting has no effect in linux-gpib. return self.interface.ask(6), StatusCode.success elif attribute == constants.VI_ATTR_GPIB_PRIMARY_ADDR: # IbaPAD 0x1 return self.interface.ask(1), StatusCode.success elif attribute == constants.VI_ATTR_GPIB_SECONDARY_ADDR: # IbaSAD 0x2 # Remove 0x60 because National Instruments. sad = self.interface.ask(2) if self.interface.ask(2): return self.interface.ask(2) - 96, StatusCode.success else: return constants.VI_NO_SEC_ADDR, StatusCode.success elif attribute == constants.VI_ATTR_GPIB_REN_STATE: # I have no idea how to implement this. raise NotImplementedError elif attribute == constants.VI_ATTR_GPIB_UNADDR_EN: # IbaUnAddr 0x1b if self.interface.ask(27): return constants.VI_TRUE, StatusCode.success else: return constants.VI_FALSE, StatusCode.success elif attribute == constants.VI_ATTR_SEND_END_EN: # IbaEndBitIsNormal 0x1a if self.interface.ask(26): return constants.VI_TRUE, StatusCode.success else: return constants.VI_FALSE, StatusCode.success elif attribute == constants.VI_ATTR_INTF_NUM: # IbaBNA 0x200 return self.interface.ask(512), StatusCode.success elif attribute == constants.VI_ATTR_INTF_TYPE: return constants.InterfaceType.gpib, StatusCode.success raise UnknownAttribute(attribute) def _set_attribute(self, attribute, attribute_state): """Sets the state of an attribute. Corresponds to viSetAttribute function of the VISA library. :param attribute: Attribute for which the state is to be modified. (Attributes.*) :param attribute_state: The state of the attribute to be set for the specified object. :return: return value of the library call. :rtype: VISAStatus """ if attribute == constants.VI_ATTR_GPIB_READDR_EN: # IbcREADDR 0x6 # Setting has no effect in linux-gpib. if isinstance(attribute_state, int): self.interface.config(6, attribute_state) return StatusCode.success else: return StatusCode.error_nonsupported_attribute_state elif attribute == constants.VI_ATTR_GPIB_PRIMARY_ADDR: # IbcPAD 0x1 if isinstance(attribute_state, int) and 0 <= attribute_state <= 30: self.interface.config(1, attribute_state) return StatusCode.success else: return StatusCode.error_nonsupported_attribute_state elif attribute == constants.VI_ATTR_GPIB_SECONDARY_ADDR: # IbcSAD 0x2 # Add 0x60 because National Instruments. if isinstance(attribute_state, int) and 0 <= attribute_state <= 30: if self.interface.ask(2): self.interface.config(2, attribute_state + 96) return StatusCode.success else: return StatusCode.error_nonsupported_attribute else: return StatusCode.error_nonsupported_attribute_state elif attribute == constants.VI_ATTR_GPIB_UNADDR_EN: # IbcUnAddr 0x1b try: self.interface.config(27, attribute_state) return StatusCode.success except gpib.GpibError: return StatusCode.error_nonsupported_attribute_state elif attribute == constants.VI_ATTR_SEND_END_EN: # IbcEndBitIsNormal 0x1a if isinstance(attribute_state, int): self.interface.config(26, attribute_state) return StatusCode.success else: return StatusCode.error_nonsupported_attribute_state raise UnknownAttribute(attribute) def read_stb(self): return self.interface.serial_poll() pyvisa-py-0.3.1/pyvisa-py/highlevel.py000066400000000000000000000405531334632567300177610ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ pyvisa-py.highlevel ~~~~~~~~~~~~~~~~~~~ Highlevel wrapper of the VISA Library. :copyright: 2014 by PyVISA-py Authors, see AUTHORS for more details. :license: MIT, see LICENSE for more details. """ from __future__ import division, unicode_literals, print_function, absolute_import import warnings import random from pyvisa import constants, errors, highlevel, rname from pyvisa.compat import integer_types, OrderedDict from . import sessions from .common import logger StatusCode = constants.StatusCode class PyVisaLibrary(highlevel.VisaLibraryBase): """A pure Python backend for PyVISA. The object is basically a dispatcher with some common functions implemented. When a new resource object is requested to pyvisa, the library creates a Session object (that knows how to perform low-level communication operations) associated with a session handle (a number, usually refered just as session). A call to a library function is handled by PyVisaLibrary if it involves a resource agnosting function or dispatched to the correct session object (obtained from the session id). Importantly, the user is unaware of this. PyVisaLibrary behaves for the user just as NIVisaLibrary. """ # Try to import packages implementing lower level functionality. try: from .serial import SerialSession logger.debug('SerialSession was correctly imported.') except Exception as e: logger.debug('SerialSession was not imported %s.' % e) try: from .usb import USBSession, USBRawSession logger.debug('USBSession and USBRawSession were correctly imported.') except Exception as e: logger.debug('USBSession and USBRawSession were not imported %s.' % e) try: from .tcpip import TCPIPInstrSession, TCPIPSocketSession logger.debug('TCPIPSession was correctly imported.') except Exception as e: logger.debug('TCPIPSession was not imported %s.' % e) try: from .gpib import GPIBSession logger.debug('GPIBSession was correctly imported.') except Exception as e: logger.debug('GPIBSession was not imported %s.' % e) @classmethod def get_session_classes(cls): return sessions.Session._session_classes @classmethod def iter_session_classes_issues(cls): return sessions.Session.iter_session_classes_issues() @staticmethod def get_debug_info(): """Return a list of lines with backend info. """ from . import __version__ d = OrderedDict() d['Version'] = '%s' % __version__ for key, val in PyVisaLibrary.get_session_classes().items(): key_name = '%s %s' % (key[0].name.upper(), key[1]) try: d[key_name] = getattr(val, 'session_issue').split('\n') except AttributeError: d[key_name] = 'Available ' + val.get_low_level_info() return d def _init(self): #: map session handle to session object. #: dict[int, session.Session] self.sessions = {} def _register(self, obj): """Creates a random but unique session handle for a session object, register it in the sessions dictionary and return the value :param obj: a session object. :return: session handle :rtype: int """ session = None while session is None or session in self.sessions: session = random.randint(1000000, 9999999) self.sessions[session] = obj return session def _return_handler(self, ret_value, func, arguments): """Check return values for errors and warnings. TODO: THIS IS JUST COPIED PASTED FROM NIVisaLibrary. Needs to be adapted. """ logger.debug('%s%s -> %r', func.__name__, _args_to_str(arguments), ret_value, extra=self._logging_extra) try: ret_value = StatusCode(ret_value) except ValueError: pass self._last_status = ret_value # The first argument of almost all registered visa functions is a session. # We store the error code per session session = None if func.__name__ not in ('viFindNext', ): try: session = arguments[0] except KeyError: raise Exception('Function %r does not seem to be a valid ' 'visa function (len args %d)' % (func, len(arguments))) # Functions that use the first parameter to get a session value. if func.__name__ in ('viOpenDefaultRM', ): # noinspection PyProtectedMember session = session._obj.value if isinstance(session, integer_types): self._last_status_in_session[session] = ret_value else: # Functions that might or might have a session in the first argument. if func.__name__ not in ('viClose', 'viGetAttribute', 'viSetAttribute', 'viStatusDesc'): raise Exception('Function %r does not seem to be a valid ' 'visa function (type args[0] %r)' % (func, type(session))) if ret_value < 0: raise errors.VisaIOError(ret_value) if ret_value in self.issue_warning_on: if session and ret_value not in self._ignore_warning_in_session[session]: warnings.warn(errors.VisaIOWarning(ret_value), stacklevel=2) return ret_value # noinspection PyShadowingBuiltins def open(self, session, resource_name, access_mode=constants.AccessModes.no_lock, open_timeout=constants.VI_TMO_IMMEDIATE): """Opens a session to the specified resource. Corresponds to viOpen function of the VISA library. :param session: Resource Manager session (should always be a session returned from open_default_resource_manager()). :param resource_name: Unique symbolic name of a resource. :param access_mode: Specifies the mode by which the resource is to be accessed. (constants.AccessModes) :param open_timeout: Specifies the maximum time period (in milliseconds) that this operation waits before returning an error. :return: Unique logical identifier reference to a session, return value of the library call. :rtype: session, VISAStatus """ try: open_timeout = int(open_timeout) except ValueError: raise ValueError('open_timeout (%r) must be an integer (or compatible type)' % open_timeout) try: parsed = rname.parse_resource_name(resource_name) except rname.InvalidResourceName: return 0, StatusCode.error_invalid_resource_name cls = sessions.Session.get_session_class(parsed.interface_type_const, parsed.resource_class) sess = cls(session, resource_name, parsed, open_timeout) return self._register(sess), StatusCode.success def assert_trigger(self, session, protocol): """Asserts software or hardware trigger. Corresponds to viAssertTrigger function of the VISA library. :param session: Unique logical identifier to a session. :param protocol: Trigger protocol to use during assertion. (Constants.PROT*) :return: return value of the library call. :rtype: :class:`pyvisa.constants.StatusCode` """ try: sess = self.sessions[session] except KeyError: return 0, constants.StatusCode.error_invalid_object return sess.assert_trigger(protocol) def clear(self, session): """Clears a device. Corresponds to viClear function of the VISA library. :param session: Unique logical identifier to a session. :return: return value of the library call. :rtype: :class:`pyvisa.constants.StatusCode` """ try: sess = self.sessions[session] except KeyError: return 0, constants.StatusCode.error_invalid_object return sess.clear() def gpib_command(self, session, command_byte): """Write GPIB command byte on the bus. Corresponds to viGpibCommand function of the VISA library. See: https://linux-gpib.sourceforge.io/doc_html/gpib-protocol.html#REFERENCE-COMMAND-BYTES :param command_byte: command byte to send :type command_byte: int, must be [0 255] :return: return value of the library call :rtype: :class:`pyvisa.constants.StatusCode` """ try: return self.sessions[session].gpib_command(command_byte) except KeyError: return constants.StatusCode.error_invalid_object def assert_trigger(self, session, protocol): """Asserts software or hardware trigger. Corresponds to viAssertTrigger function of the VISA library. :param session: Unique logical identifier to a session. :param protocol: Trigger protocol to use during assertion. (Constants.PROT*) :return: return value of the library call. :rtype: :class:`pyvisa.constants.StatusCode` """ try: return self.sessions[session].trigger(protocol) except KeyError: return constants.StatusCode.error_invalid_object def gpib_send_ifc(self, session): """Pulse the interface clear line (IFC) for at least 100 microseconds. Corresponds to viGpibSendIFC function of the VISA library. :param session: Unique logical identifier to a session. :return: return value of the library call. :rtype: :class:`pyvisa.constants.StatusCode` """ try: sess = self.sessions[session] except KeyError: return 0, constants.StatusCode.error_invalid_object return sess.gpib_send_ifc() def read_stb(self, session): """Reads a status byte of the service request. Corresponds to viReadSTB function of the VISA library. :param session: Unique logical identifier to a session. :return: Service request status byte, return value of the library call. :rtype: int, :class:`pyvisa.constants.StatusCode` """ try: sess = self.sessions[session] except KeyError: return 0, constants.StatusCode.error_invalid_object return sess.read_stb() def close(self, session): """Closes the specified session, event, or find list. Corresponds to viClose function of the VISA library. :param session: Unique logical identifier to a session, event, or find list. :return: return value of the library call. :rtype: VISAStatus """ try: sess = self.sessions[session] if sess is not self: sess.close() except KeyError: return StatusCode.error_invalid_object def open_default_resource_manager(self): """This function returns a session to the Default Resource Manager resource. Corresponds to viOpenDefaultRM function of the VISA library. :return: Unique logical identifier to a Default Resource Manager session, return value of the library call. :rtype: session, VISAStatus """ return self._register(self), StatusCode.success def list_resources(self, session, query='?*::INSTR'): """Returns a tuple of all connected devices matching query. :param query: regular expression used to match devices. """ # For each session type, ask for the list of connected resources and # merge them into a single list. resources = sum([st.list_resources() for key, st in sessions.Session.iter_valid_session_classes()], []) resources = rname.filter(resources, query) return resources def read(self, session, count): """Reads data from device or interface synchronously. Corresponds to viRead function of the VISA library. :param session: Unique logical identifier to a session. :param count: Number of bytes to be read. :return: data read, return value of the library call. :rtype: bytes, VISAStatus """ # from the session handle, dispatch to the read method of the session object. try: ret = self.sessions[session].read(count) except KeyError: return 0, StatusCode.error_invalid_object if ret[1] < 0: raise errors.VisaIOError(ret[1]) return ret def write(self, session, data): """Writes data to device or interface synchronously. Corresponds to viWrite function of the VISA library. :param session: Unique logical identifier to a session. :param data: data to be written. :type data: str :return: Number of bytes actually transferred, return value of the library call. :rtype: int, VISAStatus """ # from the session handle, dispatch to the write method of the session object. try: ret = self.sessions[session].write(data) except KeyError: return 0, StatusCode.error_invalid_object if ret[1] < 0: raise errors.VisaIOError(ret[1]) return ret def get_attribute(self, session, attribute): """Retrieves the state of an attribute. Corresponds to viGetAttribute function of the VISA library. :param session: Unique logical identifier to a session, event, or find list. :param attribute: Resource attribute for which the state query is made (see Attributes.*) :return: The state of the queried attribute for a specified resource, return value of the library call. :rtype: unicode | str | list | int, VISAStatus """ try: sess = self.sessions[session] except KeyError: return None, StatusCode.error_invalid_object return sess.get_attribute(attribute) def set_attribute(self, session, attribute, attribute_state): """Sets the state of an attribute. Corresponds to viSetAttribute function of the VISA library. :param session: Unique logical identifier to a session. :param attribute: Attribute for which the state is to be modified. (Attributes.*) :param attribute_state: The state of the attribute to be set for the specified object. :return: return value of the library call. :rtype: VISAStatus """ try: sess = self.sessions[session] except KeyError: return StatusCode.error_invalid_object return sess.set_attribute(attribute, attribute_state) def lock(self, session, lock_type, timeout, requested_key=None): """Establishes an access mode to the specified resources. Corresponds to viLock function of the VISA library. :param session: Unique logical identifier to a session. :param lock_type: Specifies the type of lock requested, either Constants.EXCLUSIVE_LOCK or Constants.SHARED_LOCK. :param timeout: Absolute time period (in milliseconds) that a resource waits to get unlocked by the locking session before returning an error. :param requested_key: This parameter is not used and should be set to VI_NULL when lockType is VI_EXCLUSIVE_LOCK. :return: access_key that can then be passed to other sessions to share the lock, return value of the library call. :rtype: str, :class:`pyvisa.constants.StatusCode` """ try: sess = self.sessions[session] except KeyError: return StatusCode.error_invalid_object return sess.lock(lock_type, timeout, requested_key) def unlock(self, session): """Relinquishes a lock for the specified resource. Corresponds to viUnlock function of the VISA library. :param session: Unique logical identifier to a session. :return: return value of the library call. :rtype: :class:`pyvisa.constants.StatusCode` """ try: sess = self.sessions[session] except KeyError: return StatusCode.error_invalid_object return sess.unlock() def disable_event(self, session, event_type, mechanism): # TODO: implement this for GPIB finalization pass def discard_events(self, session, event_type, mechanism): # TODO: implement this for GPIB finalization pass pyvisa-py-0.3.1/pyvisa-py/protocols/000077500000000000000000000000001334632567300174555ustar00rootroot00000000000000pyvisa-py-0.3.1/pyvisa-py/protocols/__init__.py000066400000000000000000000005621334632567300215710ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ pyvisa-py.protocols ~~~~~~~~~~~~~~~~~~~ Implements protocols on top of lower level libraries to talk to instruments. :copyright: 2014 by PyVISA-py Authors, see AUTHORS for more details. :license: MIT, see LICENSE for more details. """ from __future__ import division, unicode_literals, print_function, absolute_import pyvisa-py-0.3.1/pyvisa-py/protocols/rpc.py000066400000000000000000000717231334632567300206250ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ pyvisa-py.protocols.rpc ~~~~~~~~~~~~~~~~~~~~~~~ Sun RPC version 2 -- RFC1057 This file is drawn from Python's RPC demo, updated for python 3. XXX There should be separate exceptions for the various reasons why XXX an RPC can fail, rather than using RuntimeError for everything XXX The UDP version of the protocol resends requests when it does XXX not receive a timely reply -- use only for idempotent calls! Original source: http://svn.python.org/projects/python/trunk/Demo/rpc/rpc.py :copyright: 2014 by PyVISA-py Authors, see AUTHORS for more details. :license: MIT, see LICENSE for more details. """ from __future__ import (division, unicode_literals, print_function, absolute_import) import sys import enum import xdrlib import socket import select import time from pyvisa.compat import struct from ..common import logger #: Version of the protocol RPCVERSION = 2 class MessagegType(enum.IntEnum): call = 0 reply = 1 class AuthorizationFlavor(enum.IntEnum): null = 0 unix = 1 short = 2 des = 3 class ReplyStatus(enum.IntEnum): accepted = 0 denied = 1 class AcceptStatus(enum.IntEnum): #: RPC executed successfully success = 0 #: remote hasn't exported program program_unavailable = 1 #: remote can't support version program_mismatch = 2 #: program can't support procedure procedure_unavailable = 3 #: procedure can't decode params garbage_args = 4 class RejectStatus(enum.IntEnum): #: RPC version number != 2 rpc_mismatch = 0 #: remote can't authenticate caller auth_error = 1 class AuthStatus(enum.IntEnum): ok = 0 #: bad credentials (seal broken) bad_credentials = 1 #: client must begin new session rejected_credentials = 2 #: bad verifier (seal broken) bad_verifier = 3 #: verifier expired or replayed rejected_verifier = 4 #: rejected for security reasons too_weak = 5 # Exceptions class RPCError(Exception): pass class RPCBadFormat(RPCError): pass class RPCBadVersion(RPCError): pass class RPCGarbageArgs(RPCError): pass class RPCUnpackError(RPCError): pass def make_auth_null(): return b'' class Packer(xdrlib.Packer): def pack_auth(self, auth): flavor, stuff = auth self.pack_enum(flavor) self.pack_opaque(stuff) def pack_auth_unix(self, stamp, machinename, uid, gid, gids): self.pack_uint(stamp) self.pack_string(machinename) self.pack_uint(uid) self.pack_uint(gid) self.pack_uint(len(gids)) for i in gids: self.pack_uint(i) def pack_callheader(self, xid, prog, vers, proc, cred, verf): self.pack_uint(xid) self.pack_enum(MessagegType.call) self.pack_uint(RPCVERSION) self.pack_uint(prog) self.pack_uint(vers) self.pack_uint(proc) self.pack_auth(cred) self.pack_auth(verf) # Caller must add procedure-specific part of call def pack_replyheader(self, xid, verf): self.pack_uint(xid) self.pack_enum(MessagegType.reply) self.pack_uint(ReplyStatus.accepted) self.pack_auth(verf) self.pack_enum(AcceptStatus.success) # Caller must add procedure-specific part of reply class Unpacker(xdrlib.Unpacker): def unpack_auth(self): flavor = self.unpack_enum() stuff = self.unpack_opaque() return flavor, stuff def unpack_callheader(self): xid = self.unpack_uint() temp = self.unpack_enum() if temp != MessagegType.call: raise RPCBadFormat('no CALL but %r' % (temp,)) temp = self.unpack_uint() if temp != RPCVERSION: raise RPCBadVersion('bad RPC version %r' % (temp,)) prog = self.unpack_uint() vers = self.unpack_uint() proc = self.unpack_uint() cred = self.unpack_auth() verf = self.unpack_auth() return xid, prog, vers, proc, cred, verf # Caller must add procedure-specific part of call def unpack_replyheader(self): xid = self.unpack_uint() mtype = self.unpack_enum() if mtype != MessagegType.reply: raise RPCUnpackError('no reply but %r' % (mtype,)) stat = self.unpack_enum() if stat == ReplyStatus.denied: stat = self.unpack_enum() if stat == RejectStatus.rpc_mismatch: low = self.unpack_uint() high = self.unpack_uint() raise RPCUnpackError('denied: rpc_mismatch: %r' % ((low, high),)) if stat == RejectStatus.auth_error: stat = self.unpack_uint() raise RPCUnpackError('denied: auth_error: %r' % (stat,)) raise RPCUnpackError('denied: %r' % (stat,)) if stat != ReplyStatus.accepted: raise RPCUnpackError('Neither denied nor accepted: %r' % (stat,)) verf = self.unpack_auth() stat = self.unpack_enum() if stat == AcceptStatus.program_unavailable: raise RPCUnpackError('call failed: program_unavailable') if stat == AcceptStatus.program_mismatch: low = self.unpack_uint() high = self.unpack_uint() raise RPCUnpackError('call failed: program_mismatch: %r' % ((low, high),)) if stat == AcceptStatus.procedure_unavailable: raise RPCUnpackError('call failed: procedure_unavailable') if stat == AcceptStatus.garbage_args: raise RPCGarbageArgs if stat != AcceptStatus.success: raise RPCUnpackError('call failed: %r' % (stat,)) return xid, verf # Caller must get procedure-specific part of reply class Client(object): """Common base class for clients. """ def __init__(self, host, prog, vers, port): self.host = host self.prog = prog self.vers = vers self.port = port self.lastxid = 0 # XXX should be more random? self.cred = None self.verf = None def make_call(self, proc, args, pack_func, unpack_func): # Don't normally override this (but see Broadcast) logger.debug('Make call %r, %r, %r, %r', proc, args, pack_func, unpack_func) if pack_func is None and args is not None: raise TypeError('non-null args with null pack_func') self.start_call(proc) if pack_func: pack_func(args) self.do_call() if unpack_func: result = unpack_func() else: result = None self.unpacker.done() return result def start_call(self, proc): # Don't override this self.lastxid += 1 cred = self.mkcred() verf = self.mkverf() p = self.packer p.reset() p.pack_callheader(self.lastxid, self.prog, self.vers, proc, cred, verf) def do_call(self): # This MUST be overridden raise RPCError('do_call not defined') def mkcred(self): # Override this to use more powerful credentials if self.cred is None: self.cred = (AuthorizationFlavor.null, make_auth_null()) return self.cred def mkverf(self): # Override this to use a more powerful verifier if self.verf is None: self.verf = (AuthorizationFlavor.null, make_auth_null()) return self.verf def call_0(self): # Procedure 0 is always like this return self.make_call(0, None, None, None) # Record-Marking standard support def sendfrag(sock, last, frag): x = len(frag) if last: x = x | 0x80000000 header = struct.pack(">I", x) sock.send(header + frag) def _sendrecord(sock, record, fragsize=None, timeout=None): logger.debug('Sending record through %s: %r', sock, record) if timeout is not None: r, w, x = select.select([], [sock], [], timeout) if sock not in w: msg = ("socket.timeout: The instrument seems to have stopped " "responding.") raise socket.timeout(msg) last = False if not fragsize: fragsize = 0x7fffffff while not last: record_len = len(record) if record_len <= fragsize: fragsize = record_len last = True if last: fragsize = fragsize | 0x80000000 header = struct.pack(">I", fragsize) sock.send(header + record[:fragsize]) record = record[fragsize:] def _recvrecord(sock, timeout, read_fun=None): record = bytearray() buffer = bytearray() if not read_fun: read_fun = sock.recv wait_header = True last = False exp_length = 4 # minimum is in interval 1 - 100ms based on timeout or for infinite it is # 1 sec min_select_timeout = (max(min(timeout/100.0, 0.1), 0.001) if timeout is not None else 1.0) # initial 'select_timout' is half of timeout or max 2 secs # (max blocking time). # min is from 'min_select_timeout' select_timout = (max(min(timeout/2.0, 2.0), min_select_timeout) if timeout is not None else 1.0) # time, when loop shall finish finish_time = time.time() + timeout if timeout is not None else 0 while True: # use select to wait for read ready, max `select_timout` seconds r, w, x = select.select([sock], [], [], select_timout) read_data = b'' if sock in r: read_data = read_fun(exp_length) buffer.extend(read_data) elif timeout is not None and time.time() >= finish_time: # reached timeout logger.debug(('Time out encountered in %s.' 'Already receieved %d bytes. Last fragment is %d ' 'bytes long and we were expecting %d'), sock, len(record), len(buffer), exp_length) msg = ("socket.timeout: The instrument seems to have stopped " "responding.") raise socket.timeout(msg) else: # `select_timout` decreased to 50% of previous or # min_select_timeout select_timout = max(select_timout/2.0, min_select_timeout) continue if wait_header: # need to find header if len(buffer) >= exp_length: header = buffer[:exp_length] buffer = buffer[exp_length:] x = struct.unpack(">I", header)[0] last = ((x & 0x80000000) != 0) exp_length = int(x & 0x7fffffff) wait_header = False else: if len(buffer) >= exp_length: record.extend(buffer[:exp_length]) buffer = buffer[exp_length:] if last: logger.debug('Received record through %s: %r', sock, record) return bytes(record) else: wait_header = True exp_length = 4 def _connect(sock, host, port, timeout=0): try: sock.setblocking(0) sock.connect_ex((host, port)) except Exception as e: sock.close() return False finally: sock.setblocking(1) # minimum is in interval 100 - 500ms based on timeout min_select_timeout = max(min(timeout/10.0, 0.5), 0.1) # initial 'select_timout' is half of timeout or max 2 secs # (max blocking time). # min is from 'min_select_timeout' select_timout = max(min(timeout/2.0, 2.0), min_select_timeout) # time, when loop shall finish finish_time = time.time() + timeout while True: # use select to wait for socket ready, max `select_timout` seconds r, w, x = select.select([sock], [sock], [], select_timout) if sock in r or sock in w: return True if time.time() >= finish_time: # reached timeout return False # `select_timout` decreased to 50% of previous or min_select_timeout select_timout = max(select_timout/2.0, min_select_timeout) class RawTCPClient(Client): """Client using TCP to a specific port. """ def __init__(self, host, prog, vers, port, open_timeout=5000): Client.__init__(self, host, prog, vers, port) self.connect((open_timeout / 1000.0) + 1.0) # self.timeout defaults higher than the default 2 second VISA timeout, # ensuring that VISA timeouts take precedence. self.timeout = 4.0 def make_call(self, proc, args, pack_func, unpack_func): """Overridden to allow for utilizing io_timeout (passed in args). """ if proc == 11: # vxi11.DEVICE_WRITE self.timeout = (args[1] / 1000.0) + 2.0 elif proc in (12, 22): # vxi11.DEVICE_READ or vxi11.DEVICE_DOCMD self.timeout = (args[2] / 1000.0) + 2.0 elif proc in (13, 14, 15, 16, 17): # vxi11.DEVICE_READSTB, vxi11.DEVICE_TRIGGER, vxi11.DEVICE_CLEAR, # vxi11.DEVICE_REMOTE, or vxi11.DEVICE_LOCAL self.timeout = (args[3] / 1000.0) + 2.0 else: self.timeout = 4.0 return super(RawTCPClient, self).make_call(proc, args, pack_func, unpack_func) def connect(self, timeout=5.0): logger.debug('RawTCPClient: connecting to socket at (%s, %s)', self.host, self.port) self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if not _connect(self.sock, self.host, self.port, timeout): raise RPCError('can\'t connect to server') def close(self): logger.debug('RawTCPClient: closing socket') self.sock.close() def do_call(self): call = self.packer.get_buf() _sendrecord(self.sock, call, timeout=self.timeout) reply = _recvrecord(self.sock, self.timeout) u = self.unpacker u.reset(reply) xid, verf = u.unpack_replyheader() if xid != self.lastxid: # Can't really happen since this is TCP... msg = 'wrong xid in reply {0} instead of {1}' raise RPCError(msg.format(xid, self.lastxid)) class RawUDPClient(Client): """Client using UDP to a specific port. """ def __init__(self, host, prog, vers, port): Client.__init__(self, host, prog, vers, port) self.connect() def connect(self): logger.debug('RawTCPClient: connecting to socket at (%s, %s)', self.host, self.port) self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.connect((self.host, self.port)) def close(self): logger.debug('RawTCPClient: closing socket') self.sock.close() def do_call(self): call = self.packer.get_buf() self.sock.send(call) BUFSIZE = 8192 # Max UDP buffer size timeout = 1 count = 5 while 1: r, w, x = [self.sock], [], [] if select: r, w, x = select.select(r, w, x, timeout) if self.sock not in r: count = count - 1 if count < 0: raise RPCError('timeout') if timeout < 25: timeout = timeout * 2 self.sock.send(call) continue reply = self.sock.recv(BUFSIZE) u = self.unpacker u.reset(reply) xid, verf = u.unpack_replyheader() if xid != self.lastxid: continue break class RawBroadcastUDPClient(RawUDPClient): """Client using UDP broadcast to a specific port. """ def __init__(self, bcastaddr, prog, vers, port): RawUDPClient.__init__(self, bcastaddr, prog, vers, port) self.reply_handler = None self.timeout = 30 def connect(self): self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) def set_reply_handler(self, reply_handler): self.reply_handler = reply_handler def set_timeout(self, timeout): self.timeout = timeout # Use None for infinite timeout def make_call(self, proc, args, pack_func, unpack_func): if pack_func is None and args is not None: raise TypeError('non-null args with null pack_func') self.start_call(proc) if pack_func: pack_func(args) call = self.packer.get_buf() self.sock.sendto(call, (self.host, self.port)) BUFSIZE = 8192 # Max UDP buffer size (for reply) replies = [] if unpack_func is None: def dummy(): pass unpack_func = dummy while 1: r, w, x = [self.sock], [], [] if select: if self.timeout is None: r, w, x = select.select(r, w, x) else: r, w, x = select.select(r, w, x, self.timeout) if self.sock not in r: break reply, fromaddr = self.sock.recvfrom(BUFSIZE) u = self.unpacker u.reset(reply) xid, verf = u.unpack_replyheader() if xid != self.lastxid: continue reply = unpack_func() self.unpacker.done() replies.append((reply, fromaddr)) if self.reply_handler: self.reply_handler(reply, fromaddr) return replies # Port mapper interface # Program number, version and port number PMAP_PROG = 100000 PMAP_VERS = 2 PMAP_PORT = 111 class PortMapperVersion(enum.IntEnum): #: (void) -> void null = 0 #: (mapping) -> bool set = 1 #: (mapping) -> bool unset = 2 #: (mapping) -> unsigned int get_port = 3 #: (void) -> pmaplist dump = 4 #: (call_args) -> call_result call_it = 5 # A mapping is (prog, vers, prot, port) and prot is one of: IPPROTO_TCP = 6 IPPROTO_UDP = 17 # A pmaplist is a variable-length list of mappings, as follows: # either (1, mapping, pmaplist) or (0). # A call_args is (prog, vers, proc, args) where args is opaque; # a call_result is (port, res) where res is opaque. class PortMapperPacker(Packer): def pack_mapping(self, mapping): prog, vers, prot, port = mapping self.pack_uint(prog) self.pack_uint(vers) self.pack_uint(prot) self.pack_uint(port) def pack_pmaplist(self, list): self.pack_list(list, self.pack_mapping) def pack_call_args(self, ca): prog, vers, proc, args = ca self.pack_uint(prog) self.pack_uint(vers) self.pack_uint(proc) self.pack_opaque(args) class PortMapperUnpacker(Unpacker): def unpack_mapping(self): prog = self.unpack_uint() vers = self.unpack_uint() prot = self.unpack_uint() port = self.unpack_uint() return prog, vers, prot, port def unpack_pmaplist(self): return self.unpack_list(self.unpack_mapping) def unpack_call_result(self): port = self.unpack_uint() res = self.unpack_opaque() return port, res class PartialPortMapperClient(object): def __init__(self): self.packer = PortMapperPacker() self.unpacker = PortMapperUnpacker('') def set(self, mapping): return self.make_call(PortMapperVersion.set, mapping, self.packer.pack_mapping, self.unpacker.unpack_uint) def unset(self, mapping): return self.make_call(PortMapperVersion.unset, mapping, self.packer.pack_mapping, self.unpacker.unpack_uint) def get_port(self, mapping): return self.make_call(PortMapperVersion.get_port, mapping, self.packer.pack_mapping, self.unpacker.unpack_uint) def dump(self): return self.make_call(PortMapperVersion.dump, None, None, self.unpacker.unpack_pmaplist) def callit(self, ca): return self.make_call(PortMapperVersion.call_it, ca, self.packer.pack_call_args, self.unpacker.unpack_call_result) class TCPPortMapperClient(PartialPortMapperClient, RawTCPClient): def __init__(self, host, open_timeout=5000): RawTCPClient.__init__(self, host, PMAP_PROG, PMAP_VERS, PMAP_PORT, open_timeout) PartialPortMapperClient.__init__(self) class UDPPortMapperClient(PartialPortMapperClient, RawUDPClient): def __init__(self, host): RawUDPClient.__init__(self, host, PMAP_PROG, PMAP_VERS, PMAP_PORT) PartialPortMapperClient.__init__(self) class BroadcastUDPPortMapperClient(PartialPortMapperClient, RawBroadcastUDPClient): def __init__(self, bcastaddr): RawBroadcastUDPClient.__init__(self, bcastaddr, PMAP_PROG, PMAP_VERS, PMAP_PORT) PartialPortMapperClient.__init__(self) class TCPClient(RawTCPClient): """A TCP Client that find their server through the Port mapper """ def __init__(self, host, prog, vers, open_timeout=5000): pmap = TCPPortMapperClient(host, open_timeout) port = pmap.get_port((prog, vers, IPPROTO_TCP, 0)) pmap.close() if port == 0: raise RPCError('program not registered') RawTCPClient.__init__(self, host, prog, vers, port, open_timeout) class UDPClient(RawUDPClient): """A UDP Client that find their server through the Port mapper """ def __init__(self, host, prog, vers): pmap = UDPPortMapperClient(host) port = pmap.get_port((prog, vers, IPPROTO_UDP, 0)) pmap.close() if port == 0: raise RPCError('program not registered') RawUDPClient.__init__(self, host, prog, vers, port) class BroadcastUDPClient(Client): """A Broadcast UDP Client that find their server through the Port mapper """ def __init__(self, bcastaddr, prog, vers): self.pmap = BroadcastUDPPortMapperClient(bcastaddr) self.pmap.set_reply_handler(self.my_reply_handler) self.prog = prog self.vers = vers self.user_reply_handler = None self.addpackers() def close(self): self.pmap.close() def set_reply_handler(self, reply_handler): self.user_reply_handler = reply_handler def set_timeout(self, timeout): self.pmap.set_timeout(timeout) def my_reply_handler(self, reply, fromaddr): port, res = reply self.unpacker.reset(res) result = self.unpack_func() self.unpacker.done() self.replies.append((result, fromaddr)) if self.user_reply_handler is not None: self.user_reply_handler(result, fromaddr) def make_call(self, proc, args, pack_func, unpack_func): self.packer.reset() if pack_func: pack_func(args) if unpack_func is None: def dummy(): pass self.unpack_func = dummy else: self.unpack_func = unpack_func self.replies = [] packed_args = self.packer.get_buf() dummy_replies = self.pmap.Callit((self.prog, self.vers, proc, packed_args)) return self.replies # Server classes # These are not symmetric to the Client classes # XXX No attempt is made to provide authorization hooks yet class Server(object): def __init__(self, host, prog, vers, port): self.host = host # Should normally be '' for default interface self.prog = prog self.vers = vers self.port = port # Should normally be 0 for random port self.port = port self.addpackers() def register(self): mapping = self.prog, self.vers, self.prot, self.port p = TCPPortMapperClient(self.host) if not p.set(mapping): raise RPCError('register failed') def unregister(self): mapping = self.prog, self.vers, self.prot, self.port p = TCPPortMapperClient(self.host) if not p.unset(mapping): raise RPCError('unregister failed') def handle(self, call): # Don't use unpack_header but parse the header piecewise # XXX I have no idea if I am using the right error responses! self.unpacker.reset(call) self.packer.reset() xid = self.unpacker.unpack_uint() self.packer.pack_uint(xid) temp = self.unpacker.unpack_enum() if temp != MessagegType.call: return None # Not worthy of a reply self.packer.pack_uint(MessagegType.reply) temp = self.unpacker.unpack_uint() if temp != RPCVERSION: self.packer.pack_uint(ReplyStatus.denied) self.packer.pack_uint(RejectStatus.rpc_mismatch) self.packer.pack_uint(RPCVERSION) self.packer.pack_uint(RPCVERSION) return self.packer.get_buf() self.packer.pack_uint(ReplyStatus.accepted) self.packer.pack_auth((AuthorizationFlavor.null, make_auth_null())) prog = self.unpacker.unpack_uint() if prog != self.prog: self.packer.pack_uint(AcceptStatus.program_unavailable) return self.packer.get_buf() vers = self.unpacker.unpack_uint() if vers != self.vers: self.packer.pack_uint(AcceptStatus.program_mismatch) self.packer.pack_uint(self.vers) self.packer.pack_uint(self.vers) return self.packer.get_buf() proc = self.unpacker.unpack_uint() methname = 'handle_' + repr(proc) try: meth = getattr(self, methname) except AttributeError: self.packer.pack_uint(AcceptStatus.procedure_unavailable) return self.packer.get_buf() cred = self.unpacker.unpack_auth() verf = self.unpacker.unpack_auth() try: meth() # Unpack args, call turn_around(), pack reply except (EOFError, RPCGarbageArgs): # Too few or too many arguments self.packer.reset() self.packer.pack_uint(xid) self.packer.pack_uint(MessagegType.reply) self.packer.pack_uint(ReplyStatus.accepted) self.packer.pack_auth((AuthorizationFlavor.null, make_auth_null())) self.packer.pack_uint(AcceptStatus.garbage_args) return self.packer.get_buf() def turn_around(self): try: self.unpacker.done() except RuntimeError: raise RPCGarbageArgs self.packer.pack_uint(AcceptStatus.success) def handle_0(self): # Handle NULL message self.turn_around() def addpackers(self): # Override this to use derived classes from Packer/Unpacker self.packer = Packer() self.unpacker = Unpacker('') class TCPServer(Server): def __init__(self, host, prog, vers, port): Server.__init__(self, host, prog, vers, port) self.connect() def connect(self): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.prot = IPPROTO_TCP self.sock.bind((self.host, self.port)) def loop(self): self.sock.listen(0) while 1: self.session(self.sock.accept()) def session(self, connection): sock, (host, port) = connection while 1: try: call = _recvrecord(sock, None) except EOFError: break except socket.error: logger.exception('socket error: %r', sys.exc_info()[0]) break reply = self.handle(call) if reply is not None: _sendrecord(sock, reply) def forkingloop(self): # Like loop but uses forksession() self.sock.listen(0) while 1: self.forksession(self.sock.accept()) def forksession(self, connection): # Like session but forks off a subprocess import os # Wait for deceased children try: while 1: pid, sts = os.waitpid(0, 1) except os.error: pass pid = None try: pid = os.fork() if pid: # Parent connection[0].close() return # Child self.session(connection) finally: # Make sure we don't fall through in the parent if pid == 0: os._exit(0) class UDPServer(Server): def __init__(self, host, prog, vers, port): Server.__init__(self, host, prog, vers, port) self.connect() def connect(self): self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.prot = IPPROTO_UDP self.sock.bind((self.host, self.port)) def loop(self): while 1: self.session() def session(self): call, host_port = self.sock.recvfrom(8192) reply = self.handle(call) if reply is not None: self.sock.sendto(reply, host_port) pyvisa-py-0.3.1/pyvisa-py/protocols/usbraw.py000066400000000000000000000047331334632567300213410ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ pyvisa-py.protocols.usbraw ~~~~~~~~~~~~~~~~~~~~~~~~~~ Implements Session to control USB Raw devices Loosely based on PyUSBTMC:python module to handle USB-TMC(Test and Measurement class) devices. by Noboru Yamamot, Accl. Lab, KEK, JAPAN This file is an offspring of the Lantz Project. :copyright: 2014 by PyVISA-py Authors, see AUTHORS for more details. :license: MIT, see LICENSE for more details. """ from __future__ import division, unicode_literals, print_function, absolute_import from .usbtmc import USBRaw as USBRaw from .usbutil import find_devices, find_interfaces def find_raw_devices(vendor=None, product=None, serial_number=None, custom_match=None, **kwargs): """Find connected USB RAW devices. See usbutil.find_devices for more info. """ def is_usbraw(dev): if custom_match and not custom_match(dev): return False return bool(find_interfaces(dev, bInterfaceClass=0xFF, bInterfaceSubClass=0xFF)) return find_devices(vendor, product, serial_number, is_usbraw, **kwargs) class USBRawDevice(USBRaw): RECV_CHUNK = 1024 ** 2 find_devices = staticmethod(find_raw_devices) def __init__(self, vendor=None, product=None, serial_number=None, **kwargs): super(USBRawDevice, self).__init__(vendor, product, serial_number, **kwargs) if not (self.usb_recv_ep and self.usb_send_ep): raise ValueError("USBRAW device must have both Bulk-In and Bulk-out endpoints.") def write(self, data): """Send raw bytes to the instrument. :param data: bytes to be sent to the instrument :type data: bytes """ begin, end, size = 0, 0, len(data) bytes_sent = 0 raw_write = super(USBRawDevice, self).write while not end > size: begin = end end = begin + self.RECV_CHUNK bytes_sent += raw_write(data[begin:end]) return bytes_sent def read(self, size): """Read raw bytes from the instrument. :param size: amount of bytes to be sent to the instrument :type size: integer :return: received bytes :return type: bytes """ raw_read = super(USBRawDevice, self).read received = bytearray() while not len(received) >= size: resp = raw_read(self.RECV_CHUNK) received.extend(resp) return bytes(received) pyvisa-py-0.3.1/pyvisa-py/protocols/usbtmc.py000066400000000000000000000232401334632567300213250ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ pyvisa-py.protocols.usbtmc ~~~~~~~~~~~~~~~~~~~~~~~~~~ Implements Session to control USBTMC instruments Loosely based on PyUSBTMC:python module to handle USB-TMC(Test and Measurement class) devices. by Noboru Yamamot, Accl. Lab, KEK, JAPAN This file is an offspring of the Lantz Project. :copyright: 2014 by PyVISA-py Authors, see AUTHORS for more details. :license: MIT, see LICENSE for more details. """ from __future__ import (division, unicode_literals, print_function, absolute_import) import enum from pyvisa.compat import struct import time from collections import namedtuple import usb from .usbutil import (find_devices, find_interfaces, find_endpoint, usb_find_desc) import sys if sys.version_info < (3, 2): def array_to_bytes(arr): return arr.tostring() else: def array_to_bytes(arr): return arr.tobytes() class MsgID(enum.IntEnum): """From USB-TMC table2 """ dev_dep_msg_out = 1 request_dev_dep_msg_in = 2 dev_dep_msg_in = 2 vendor_specific_out = 126 request_vendor_specific_in = 127 vendor_specific_in = 127 trigger = 128 # for USB488 class Request(enum.IntEnum): initiate_abort_bulk_out = 1 check_abort_bulk_out_status = 2 initiate_abort_bulk_in = 3 check_abort_bulk_in_status = 4 initiate_clear = 5 check_clear_status = 6 get_capabilities = 7 indicator_pulse = 64 def find_tmc_devices(vendor=None, product=None, serial_number=None, custom_match=None, **kwargs): """Find connected USBTMC devices. See usbutil.find_devices for more info. """ def is_usbtmc(dev): if custom_match and not custom_match(dev): return False return bool(find_interfaces(dev, bInterfaceClass=0xfe, bInterfaceSubClass=3)) return find_devices(vendor, product, serial_number, is_usbtmc, **kwargs) class BulkOutMessage(object): """The Host uses the Bulk-OUT endpoint to send USBTMC command messages to the device. """ @staticmethod def build_array(btag, eom, chunk): size = len(chunk) return (struct.pack('BBBx', MsgID.dev_dep_msg_out, btag, ~btag & 0xFF) + struct.pack(" 1: desc = '\n'.join(str(dev) for dev in devices) raise ValueError('{} devices found:\n{}\nPlease narrow the search' ' criteria'.format(len(devices), desc)) self.usb_dev = devices[0] try: if self.usb_dev.is_kernel_driver_active(0): self.usb_dev.detach_kernel_driver(0) except (usb.core.USBError, NotImplementedError) as e: pass try: self.usb_dev.set_configuration() except usb.core.USBError as e: raise Exception('failed to set configuration\n %s' % e) try: self.usb_dev.set_interface_altsetting() except usb.core.USBError as e: pass self.usb_intf = self._find_interface(self.usb_dev, self.INTERFACE) self.usb_recv_ep, self.usb_send_ep =\ self._find_endpoints(self.usb_intf, self.ENDPOINTS) def _find_interface(self, dev, setting): return self.usb_dev.get_active_configuration()[self.INTERFACE] def _find_endpoints(self, interface, setting): recv, send = setting if recv is None: recv = find_endpoint(interface, usb.ENDPOINT_IN, usb.ENDPOINT_TYPE_BULK) else: recv = usb_find_desc(interface, bEndpointAddress=recv) if send is None: send = find_endpoint(interface, usb.ENDPOINT_OUT, usb.ENDPOINT_TYPE_BULK) else: send = usb_find_desc(interface, bEndpointAddress=send) return recv, send def write(self, data): """Send raw bytes to the instrument. :param data: bytes to be sent to the instrument :type data: bytes """ try: return self.usb_send_ep.write(data) except usb.core.USBError as e: raise ValueError(str(e)) def read(self, size): """Receive raw bytes to the instrument. :param size: number of bytes to receive :return: received bytes :return type: bytes """ if size <= 0: size = 1 data = array_to_bytes(self.usb_recv_ep.read(size, self.timeout)) return data def close(self): return usb.util.dispose_resources(self.usb_dev) class USBTMC(USBRaw): RECV_CHUNK = 1024 ** 2 find_devices = staticmethod(find_tmc_devices) def __init__(self, vendor=None, product=None, serial_number=None, **kwargs): super(USBTMC, self).__init__(vendor, product, serial_number, **kwargs) self.usb_intr_in = find_endpoint(self.usb_intf, usb.ENDPOINT_IN, usb.ENDPOINT_TYPE_INTERRUPT) self.usb_dev.reset() self.usb_dev.set_configuration() time.sleep(0.01) self._get_capabilities() self._btag = 0 if not (self.usb_recv_ep and self.usb_send_ep): msg = "TMC device must have both Bulk-In and Bulk-out endpoints." raise ValueError(msg) def _get_capabilities(self): self.usb_dev.ctrl_transfer( usb.util.build_request_type(usb.util.CTRL_IN, usb.util.CTRL_TYPE_CLASS, usb.util.CTRL_RECIPIENT_INTERFACE), Request.get_capabilities, 0x0000, self.usb_intf.index, 0x0018, timeout=self.timeout) def _find_interface(self, dev, setting): interfaces = find_interfaces(dev, bInterfaceClass=0xFE, bInterfaceSubClass=3) if not interfaces: raise ValueError('USB TMC interface not found.') elif len(interfaces) > 1: pass return interfaces[0] def write(self, data): """Send raw bytes to the instrument. :param data: bytes to be sent to the instrument :type data: bytes """ begin, end, size = 0, 0, len(data) bytes_sent = 0 raw_write = super(USBTMC, self).write while not end > size: begin, end = end, begin + self.RECV_CHUNK self._btag = (self._btag % 255) + 1 data = BulkOutMessage.build_array(self._btag, end > size, data[begin:end]) bytes_sent += raw_write(data) return bytes_sent def read(self, size): recv_chunk = self.RECV_CHUNK eom = False raw_read = super(USBTMC, self).read raw_write = super(USBTMC, self).write received = bytearray() while not eom: self._btag = (self._btag % 255) + 1 req = BulkInMessage.build_array(self._btag, recv_chunk, None) raw_write(req) resp = raw_read(recv_chunk) response = BulkInMessage.from_bytes(resp) received.extend(response.data) eom = response.transfer_attributes & 1 return bytes(received) pyvisa-py-0.3.1/pyvisa-py/protocols/usbutil.py000066400000000000000000000230401334632567300215150ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ pyvisa-py.usb ~~~~~~~~~~~~~ Serial Session implementation using PyUSB. See the following link for more information about USB. http://www.beyondlogic.org/usbnutshell/usb5.shtml This file is an offspring of the Lantz Project. :copyright: 2014 by PyVISA-py Authors, see AUTHORS for more details. :license: MIT, see LICENSE for more details. """ from __future__ import division, unicode_literals, print_function, absolute_import from fnmatch import fnmatch import usb from usb.util import (get_string as usb_get_string, find_descriptor as usb_find_desc) ClassCodes = { 0x00: ('Device', 'Use class information in the Interface Descriptors'), 0x01: ('Interface', 'Audio'), 0x02: ('Both', 'Communications and CDC Control'), 0x03: ('Interface', 'HID (Human Interface Device)'), 0x05: ('Interface', 'Physical'), 0x06: ('Interface', 'Image'), 0x07: ('Interface', 'Printer'), 0x08: ('Interface', 'Mass Storage'), 0x09: ('Device', 'Hub'), 0x0A: ('Interface', 'CDC-Data'), 0x0B: ('Interface', 'Smart Card'), 0x0D: ('Interface', 'Content Security'), 0x0E: ('Interface', 'Video'), 0x0F: ('Interface', 'Personal Healthcare'), 0x10: ('Interface', 'Audio/Video Devices'), 0xDC: ('Both', 'Diagnostic Device'), 0xE0: ('Interface', 'Wireless Controller'), 0xEF: ('Both', 'Miscellaneous'), 0xFE: ('Interface', 'Application Specific'), 0xFF: ('Both', 'Vendor Specific') } # None is 0xxx AllCodes = { (0x00, 0x00, 0x00): 'Use class code info from Interface Descriptors', (0x01, None, None): 'Audio device', (0x02, None, None): 'Communication device class', (0x03, None, None): 'HID device class', (0x05, None, None): 'Physical device class', (0x06, 0x01, 0x01): 'Still Imaging device', (0x07, None, None): 'Printer device', (0x08, None, None): 'Mass Storage device', (0x09, 0x00, 0x00): 'Full speed Hub', (0x09, 0x00, 0x01): 'Hi-speed hub with single TT', (0x09, 0x00, 0x02): 'Hi-speed hub with multiple TTs', (0x0A, None, None): 'CDC data device', (0x0B, None, None): 'Smart Card device', (0x0D, 0x00, 0x00): 'Content Security device', (0x0E, None, None): 'Video device', (0x0F, None, None): 'Personal Healthcare device', (0x10, 0x01, 0x00): 'Control Interface', (0x10, 0x02, 0x00): 'Data Video Streaming Interface', (0x10, 0x03, 0x00): 'VData Audio Streaming Interface', (0xDC, 0x01, 0x01): 'USB2 Compliance Device', (0xE0, 0x01, 0x01): 'Bluetooth Programming Interface.', (0xE0, 0x01, 0x02): 'UWB Radio Control Interface.', (0xE0, 0x01, 0x03): 'Remote NDIS', (0xE0, 0x01, 0x04): 'Bluetooth AMP Controller.', (0xE0, 0x2, 0x01): 'Host Wire Adapter Control/Data interface.', (0xE0, 0x2, 0x02): 'Device Wire Adapter Control/Data interface.', (0xE0, 0x2, 0x03): 'Device Wire Adapter Isochronous interface.', (0xEF, 0x01, 0x01): 'Active Sync device.', (0xEF, 0x01, 0x02): 'Palm Sync. This class code can be used in either ' 'Device or Interface Descriptors.', (0xEF, 0x02, 0x01): 'Interface Association Descriptor.', (0xEF, 0x02, 0x02): 'Wire Adapter Multifunction Peripheral programming interface.', (0xEF, 0x03, 0x01): 'Cable Based Association Framework.', (0xEF, 0x04, 0x01): 'RNDIS over Ethernet. Connecting a host to the Internet via ' 'Ethernet mobile device. The device appears to the host as an' 'Ethernet gateway device. This class code may only be used in ' 'Interface Descriptors.', (0xEF, 0x04, 0x02): 'RNDIS over WiFi. Connecting a host to the Internet via WiFi ' 'enabled mobile device. The device represents itself to the host' 'as an 802.11 compliant network device. This class code may only' 'be used in Interface Descriptors.', (0xEF, 0x04, 0x03): 'RNDIS over WiMAX. Connecting a host to the Internet via WiMAX ' 'enabled mobile device. The device is represented to the host ' 'as an 802.16 network device. This class code may only be used ' 'in Interface Descriptors.', (0xEF, 0x04, 0x04): 'RNDIS over WWAN. Connecting a host to the Internet via a device ' 'using mobile broadband, i.e. WWAN (GSM/CDMA). This class code may ' 'only be used in Interface Descriptors.', (0xEF, 0x04, 0x05): 'RNDIS for Raw IPv4. Connecting a host to the Internet using raw ' 'IPv4 via non-Ethernet mobile device. Devices that provide raw ' 'IPv4, not in an Ethernet packet, may use this form to in lieu of ' 'other stock types. ' 'This class code may only be used in Interface Descriptors.', (0xEF, 0x04, 0x06): 'RNDIS for Raw IPv6. Connecting a host to the Internet using raw ' 'IPv6 via non-Ethernet mobile device. Devices that provide raw ' 'IPv6, not in an Ethernet packet, may use this form to in lieu of ' 'other stock types. ' 'This class code may only be used in Interface Descriptors.', (0xEF, 0x04, 0x07): 'RNDIS for GPRS. Connecting a host to the Internet over GPRS mobile ' 'device using the device‚Äôs cellular radio.', (0xEF, 0x05, 0x00): 'USB3 Vision Control Interface', (0xEF, 0x05, 0x01): 'USB3 Vision Event Interface', (0xEF, 0x05, 0x02): 'USB3 Vision Streaming Interface', (0xFE, 0x01, 0x01): 'Device Firmware Upgrade.', (0xFE, 0x02, 0x00): 'IRDA Bridge device.', (0xFE, 0x03, 0x00): 'USB Test and Measurement Device.', (0xFE, 0x03, 0x01): 'USB Test and Measurement Device conforming to the USBTMC USB488 Subclass', (0xFF, None, None): 'Vendor specific' } def ep_attributes(ep): c = ep.bmAttributes attrs = [] tp = c & usb.ENDPOINT_TYPE_MASK if tp == usb.ENDPOINT_TYPE_CONTROL: attrs.append('Control') elif tp == usb.ENDPOINT_TYPE_ISOCHRONOUS: attrs.append('Isochronous') elif tp == usb.ENDPOINT_TYPE_BULK: attrs.append('Bulk') elif tp == usb.ENDPOINT_TYPE_INTERRUPT: attrs.append('Interrupt') sync = (c & 12) >> 2 if sync == 0: attrs.append('No sync') elif sync == 1: attrs.append('Async') elif sync == 2: attrs.append('Adaptive') elif sync == 3: attrs.append('Sync') usage = (c & 48) >> 4 if usage == 0: attrs.append('Data endpoint') elif usage == 1: attrs.append('Feedback endpoint') elif usage == 2: attrs.append('Subordinate Feedback endpoint') elif usage == 3: attrs.append('Reserved') return ', '.join(attrs) def find_devices(vendor=None, product=None, serial_number=None, custom_match=None, **kwargs): """Find connected USB devices matching certain keywords. Wildcards can be used for vendor, product and serial_number. :param vendor: name or id of the vendor (manufacturer) :param product: name or id of the product :param serial_number: serial number. :param custom_match: callable returning True or False that takes a device as only input. :param kwargs: other properties to match. See usb.core.find :return: """ kwargs = kwargs or {} attrs = {} if isinstance(vendor, str): attrs['manufacturer'] = vendor elif vendor is not None: kwargs['idVendor'] = vendor if isinstance(product, str): attrs['product'] = product elif product is not None: kwargs['idProduct'] = product if serial_number: attrs['serial_number'] = str(serial_number) if attrs: def cm(dev): if custom_match is not None and not custom_match(dev): return False for attr, pattern in attrs.items(): if not fnmatch(getattr(dev, attr).lower(), pattern.lower()): return False return True else: cm = custom_match return usb.core.find(find_all=True, custom_match=cm, **kwargs) def find_interfaces(device, **kwargs): """ :param device: :return: """ interfaces = [] try: for cfg in device: try: interfaces.extend(usb_find_desc(cfg, find_all=True, **kwargs)) except: pass except: pass return interfaces def find_endpoint(interface, direction, type): ep = usb_find_desc(interface, custom_match= lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == direction and usb.util.endpoint_type(e.bmAttributes) == type ) return ep def _patch_endpoint(ep, log_func=print): _read = ep.read _write = ep.write def new_read(*args, **kwargs): log_func('---') log_func('reading from {}'.format(ep.bEndpointAddress)) log_func('args: {}'.format(args)) log_func('kwargs: {}'.format(kwargs)) ret = _read(*args, **kwargs) log_func('returned', ret) log_func('---') return ret def new_write(*args, **kwargs): log_func('---') log_func('writing to {}'.format(ep.bEndpointAddress)) log_func('args: {}'.format(args)) log_func('kwargs: {}'.format(kwargs)) ret = _write(*args, **kwargs) log_func('returned', ret) log_func('---') return ret ep.read = new_read ep.write = new_write pyvisa-py-0.3.1/pyvisa-py/protocols/vxi11.py000066400000000000000000000237641334632567300210130ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ pyvisa-py.protocols.vxi11 ~~~~~~~~~~~~~~~~~~~~~~~~~ Implements a VX11 Session using Python Standard Library. Based on Python Sun RPC Demo and Alex Forencich python-vx11 This file is an offspring of the Lantz project. :copyright: 2014 by PyVISA-py Authors, see AUTHORS for more details. :license: MIT, see LICENSE for more details. """ from __future__ import (division, unicode_literals, print_function, absolute_import) import enum import socket from . import rpc # VXI-11 RPC constants # Device async DEVICE_ASYNC_PROG = 0x0607b0 DEVICE_ASYNC_VERS = 1 DEVICE_ABORT = 1 # Device core DEVICE_CORE_PROG = 0x0607af DEVICE_CORE_VERS = 1 CREATE_LINK = 10 DEVICE_WRITE = 11 DEVICE_READ = 12 DEVICE_READSTB = 13 DEVICE_TRIGGER = 14 DEVICE_CLEAR = 15 DEVICE_REMOTE = 16 DEVICE_LOCAL = 17 DEVICE_LOCK = 18 DEVICE_UNLOCK = 19 DEVICE_ENABLE_SRQ = 20 DEVICE_DOCMD = 22 DESTROY_LINK = 23 CREATE_INTR_CHAN = 25 DESTROY_INTR_CHAN = 26 # Device intr DEVICE_INTR_PROG = 0x0607b1 DEVICE_INTR_VERS = 1 DEVICE_INTR_SRQ = 30 # Error states class ErrorCodes(enum.IntEnum): no_error = 0 syntax_error = 1 device_not_accessible = 3 invalid_link_identifier = 4 parameter_error = 5 channel_not_established = 6 operation_not_supported = 8 out_of_resources = 9 device_locked_by_another_link = 11 no_lock_held_by_this_link = 12 io_timeout = 15 io_error = 17 abort = 23 channel_already_established = 29 # Flags OP_FLAG_WAIT_BLOCK = 1 OP_FLAG_END = 8 OP_FLAG_TERMCHAR_SET = 128 RX_REQCNT = 1 RX_CHR = 2 RX_END = 4 class Vxi11Error(Exception): pass class Vxi11Packer(rpc.Packer): def pack_device_link(self, link): self.pack_int(link) def pack_create_link_parms(self, params): id, lock_device, lock_timeout, device = params self.pack_int(id) self.pack_bool(lock_device) self.pack_uint(lock_timeout) self.pack_string(device.encode('ascii')) def pack_device_write_parms(self, params): link, io_timeout, lock_timeout, flags, data = params self.pack_int(link) self.pack_uint(io_timeout) self.pack_uint(lock_timeout) self.pack_int(flags) self.pack_opaque(data) def pack_device_read_parms(self, params): link, request_size, io_timeout, lock_timeout, flags, term_char = params self.pack_int(link) self.pack_uint(request_size) self.pack_uint(io_timeout) self.pack_uint(lock_timeout) self.pack_int(flags) self.pack_int(term_char) def pack_device_generic_parms(self, params): link, flags, lock_timeout, io_timeout = params self.pack_int(link) self.pack_int(flags) self.pack_uint(lock_timeout) self.pack_uint(io_timeout) def pack_device_remote_func_parms(self, params): host_addr, host_port, prog_num, prog_vers, prog_family = params self.pack_uint(host_addr) self.pack_uint(host_port) self.pack_uint(prog_num) self.pack_uint(prog_vers) self.pack_int(prog_family) def pack_device_enable_srq_parms(self, params): link, enable, handle = params self.pack_int(link) self.pack_bool(enable) if len(handle) > 40: raise Vxi11Error("array length too long") self.pack_opaque(handle) def pack_device_lock_parms(self, params): link, flags, lock_timeout = params self.pack_int(link) self.pack_int(flags) self.pack_uint(lock_timeout) def pack_device_docmd_parms(self, params): (link, flags, io_timeout, lock_timeout, cmd, network_order, datasize, data_in) = params self.pack_int(link) self.pack_int(flags) self.pack_uint(io_timeout) self.pack_uint(lock_timeout) self.pack_int(cmd) self.pack_bool(network_order) self.pack_int(datasize) self.pack_opaque(data_in) class Vxi11Unpacker(rpc.Unpacker): def unpack_device_link(self): return self.unpack_int() def unpack_device_error(self): return self.unpack_int() def unpack_create_link_resp(self): error = self.unpack_int() link = self.unpack_int() abort_port = self.unpack_uint() max_recv_size = self.unpack_uint() return error, link, abort_port, max_recv_size def unpack_device_write_resp(self): error = self.unpack_int() size = self.unpack_uint() return error, size def unpack_device_read_resp(self): error = self.unpack_int() reason = self.unpack_int() data = self.unpack_opaque() return error, reason, data def unpack_device_read_stb_resp(self): error = self.unpack_int() stb = self.unpack_uint() return error, stb def unpack_device_docmd_resp(self): error = self.unpack_int() data_out = self.unpack_opaque() return error, data_out class CoreClient(rpc.TCPClient): def __init__(self, host, open_timeout=5000): self.packer = Vxi11Packer() self.unpacker = Vxi11Unpacker('') super(CoreClient, self).__init__(host, DEVICE_CORE_PROG, DEVICE_CORE_VERS, open_timeout) def create_link(self, id, lock_device, lock_timeout, name): params = (id, lock_device, lock_timeout, name) return self.make_call(CREATE_LINK, params, self.packer.pack_create_link_parms, self.unpacker.unpack_create_link_resp) def device_write(self, link, io_timeout, lock_timeout, flags, data): params = (link, io_timeout, lock_timeout, flags, data) try: return self.make_call(DEVICE_WRITE, params, self.packer.pack_device_write_parms, self.unpacker.unpack_device_write_resp) except socket.timeout as e: return ErrorCodes.io_timeout, e.args[0], '' def device_read(self, link, request_size, io_timeout, lock_timeout, flags, term_char): params = (link, request_size, io_timeout, lock_timeout, flags, term_char) try: return self.make_call(DEVICE_READ, params, self.packer.pack_device_read_parms, self.unpacker.unpack_device_read_resp) except socket.timeout as e: return ErrorCodes.io_timeout, e.args[0], '' def device_read_stb(self, link, flags, lock_timeout, io_timeout): params = (link, flags, lock_timeout, io_timeout) return self.make_call(DEVICE_READSTB, params, self.packer.pack_device_generic_parms, self.unpacker.unpack_device_read_stb_resp) def device_trigger(self, link, flags, lock_timeout, io_timeout): params = (link, flags, lock_timeout, io_timeout) return self.make_call(DEVICE_TRIGGER, params, self.packer.pack_device_generic_parms, self.unpacker.unpack_device_error) def device_clear(self, link, flags, lock_timeout, io_timeout): params = (link, flags, lock_timeout, io_timeout) return self.make_call(DEVICE_CLEAR, params, self.packer.pack_device_generic_parms, self.unpacker.unpack_device_error) def device_remote(self, link, flags, lock_timeout, io_timeout): params = (link, flags, lock_timeout, io_timeout) return self.make_call(DEVICE_REMOTE, params, self.packer.pack_device_generic_parms, self.unpacker.unpack_device_error) def device_local(self, link, flags, lock_timeout, io_timeout): params = (link, flags, lock_timeout, io_timeout) return self.make_call(DEVICE_LOCAL, params, self.packer.pack_device_generic_parms, self.unpacker.unpack_device_error) def device_lock(self, link, flags, lock_timeout): params = (link, flags, lock_timeout) return self.make_call(DEVICE_LOCK, params, self.packer.pack_device_lock_parms, self.unpacker.unpack_device_error) def device_unlock(self, link): return self.make_call(DEVICE_UNLOCK, link, self.packer.pack_device_link, self.unpacker.unpack_device_error) def device_enable_srq(self, link, enable, handle): params = (link, enable, handle) return self.make_call(DEVICE_ENABLE_SRQ, params, self.packer.pack_device_enable_srq_parms, self.unpacker.unpack_device_error) def device_docmd(self, link, flags, io_timeout, lock_timeout, cmd, network_order, datasize, data_in): params = (link, flags, io_timeout, lock_timeout, cmd, network_order, datasize, data_in) return self.make_call(DEVICE_DOCMD, params, self.packer.pack_device_docmd_parms, self.unpacker.unpack_device_docmd_resp) def destroy_link(self, link): return self.make_call(DESTROY_LINK, link, self.packer.pack_device_link, self.unpacker.unpack_device_error) def create_intr_chan(self, host_addr, host_port, prog_num, prog_vers, prog_family): params = (host_addr, host_port, prog_num, prog_vers, prog_family) return self.make_call(CREATE_INTR_CHAN, params, self.packer.pack_device_docmd_parms, self.unpacker.unpack_device_error) def destroy_intr_chan(self): return self.make_call(DESTROY_INTR_CHAN, None, None, self.unpacker.unpack_device_error) pyvisa-py-0.3.1/pyvisa-py/serial.py000066400000000000000000000321071334632567300172650ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ pyvisa-py.serial ~~~~~~~~~~~~~~~~ Serial Session implementation using PySerial. :copyright: 2014 by PyVISA-py Authors, see AUTHORS for more details. :license: MIT, see LICENSE for more details. """ from __future__ import division, unicode_literals, print_function, absolute_import from pyvisa import constants, attributes, logger from .sessions import Session, UnknownAttribute from . import common try: import serial from serial.tools.list_ports import comports except ImportError as e: Session.register_unavailable(constants.InterfaceType.asrl, 'INSTR', 'Please install PySerial (>=3.0) to use this resource type.\n%s' % e) raise def to_state(boolean_input): """Convert a boolean input into a LineState value """ if boolean_input: return constants.LineState.asserted return constants.LineState.unasserted StatusCode = constants.StatusCode SerialTermination = constants.SerialTermination @Session.register(constants.InterfaceType.asrl, 'INSTR') class SerialSession(Session): """A serial Session that uses PySerial to do the low level communication. """ @staticmethod def list_resources(): return ['ASRL%s::INSTR' % port[0] for port in comports()] @classmethod def get_low_level_info(cls): try: ver = serial.VERSION except AttributeError: ver = 'N/A' return 'via PySerial (%s)' % ver def after_parsing(self): if 'mock' in self.parsed: cls = self.parsed.mock else: cls = serial.Serial self.interface = cls(port=self.parsed.board, timeout=self.timeout, write_timeout=self.timeout) for name in ('ASRL_END_IN', 'ASRL_END_OUT', 'SEND_END_EN', 'TERMCHAR', 'TERMCHAR_EN', 'SUPPRESS_END_EN'): attribute = getattr(constants, 'VI_ATTR_' + name) self.attrs[attribute] = attributes.AttributesByID[attribute].default def _get_timeout(self, attribute): if self.interface: self.timeout = self.interface.timeout return super(SerialSession, self)._get_timeout(attribute) def _set_timeout(self, attribute, value): status = super(SerialSession, self)._set_timeout(attribute, value) if self.interface: self.interface.timeout = self.timeout self.interface.write_timeout = self.timeout return status def close(self): self.interface.close() def read(self, count): """Reads data from device or interface synchronously. Corresponds to viRead function of the VISA library. :param count: Number of bytes to be read. :return: data read, return value of the library call. :rtype: bytes, constants.StatusCode """ end_in, _ = self.get_attribute(constants.VI_ATTR_ASRL_END_IN) suppress_end_en, _ = self.get_attribute(constants.VI_ATTR_SUPPRESS_END_EN) reader = lambda: self.interface.read(1) if end_in == SerialTermination.none: checker = lambda current: False elif end_in == SerialTermination.last_bit: mask = 2 ** self.interface.bytesize checker = lambda current: bool(common.last_int(current) & mask) elif end_in == SerialTermination.termination_char: end_char, _ = self.get_attribute(constants.VI_ATTR_TERMCHAR) checker = lambda current: common.last_int(current) == end_char else: raise ValueError('Unknown value for VI_ATTR_ASRL_END_IN: %s' % end_in) return self._read(reader, count, checker, suppress_end_en, None, False, serial.SerialTimeoutException) def write(self, data): """Writes data to device or interface synchronously. Corresponds to viWrite function of the VISA library. :param data: data to be written. :type data: bytes :return: Number of bytes actually transferred, return value of the library call. :rtype: int, VISAStatus """ logger.debug('Serial.write %r' % data) # TODO: How to deal with VI_ATTR_TERMCHAR_EN end_out, _ = self.get_attribute(constants.VI_ATTR_ASRL_END_OUT) send_end, _ = self.get_attribute(constants.VI_ATTR_SEND_END_EN) try: # We need to wrap data in common.iter_bytes to Provide Python 2 and 3 compatibility if end_out in (SerialTermination.none, SerialTermination.termination_break): data = common.iter_bytes(data) elif end_out == SerialTermination.last_bit: last_bit, _ = self.get_attribute(constants.VI_ATTR_ASRL_DATA_BITS) mask = 1 << (last_bit - 1) data = common.iter_bytes(data, mask, send_end) elif end_out == SerialTermination.termination_char: term_char, _ = self.get_attribute(constants.VI_ATTR_TERMCHAR) data = common.iter_bytes(data + common.int_to_byte(term_char)) else: raise ValueError('Unknown value for VI_ATTR_ASRL_END_OUT: %s' % end_out) count = 0 for d in data: count += self.interface.write(d) if end_out == SerialTermination.termination_break: logger.debug('Serial.sendBreak') self.interface.sendBreak() return count, StatusCode.success except serial.SerialTimeoutException: return 0, StatusCode.error_timeout def _get_attribute(self, attribute): """Get the value for a given VISA attribute for this session. Use to implement custom logic for attributes. :param attribute: Resource attribute for which the state query is made :return: The state of the queried attribute for a specified resource, return value of the library call. :rtype: (unicode | str | list | int, VISAStatus) """ if attribute == constants.VI_ATTR_ASRL_ALLOW_TRANSMIT: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_AVAIL_NUM: return self.interface.inWaiting(), StatusCode.success elif attribute == constants.VI_ATTR_ASRL_BAUD: return self.interface.baudrate, StatusCode.success elif attribute == constants.VI_ATTR_ASRL_BREAK_LEN: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_BREAK_STATE: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_CONNECTED: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_CTS_STATE: return to_state(self.interface.getCTS()), StatusCode.success elif attribute == constants.VI_ATTR_ASRL_DATA_BITS: return self.interface.bytesize, StatusCode.success elif attribute == constants.VI_ATTR_ASRL_DCD_STATE: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_DISCARD_NULL: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_DSR_STATE: return to_state(self.interface.getDSR()), StatusCode.success elif attribute == constants.VI_ATTR_ASRL_DTR_STATE: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_FLOW_CNTRL: return (self.interface.xonxoff * constants.VI_ASRL_FLOW_XON_XOFF | self.interface.rtscts * constants.VI_ASRL_FLOW_RTS_CTS | self.interface.dsrdtr * constants.VI_ASRL_FLOW_DTR_DSR), StatusCode.success elif attribute == constants.VI_ATTR_ASRL_PARITY: parity = self.interface.parity if parity == serial.PARITY_NONE: return constants.Parity.none, StatusCode.success elif parity == serial.PARITY_EVEN: return constants.Parity.even, StatusCode.success elif parity == serial.PARITY_ODD: return constants.Parity.odd, StatusCode.success elif parity == serial.PARITY_MARK: return constants.Parity.mark, StatusCode.success elif parity == serial.PARITY_SPACE: return constants.Parity.space, StatusCode.success raise Exception('Unknown parity value: %r' % parity) elif attribute == constants.VI_ATTR_ASRL_RI_STATE: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_RTS_STATE: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_STOP_BITS: bits = self.interface.stopbits if bits == serial.STOPBITS_ONE: return constants.StopBits.one, StatusCode.success elif bits == serial.STOPBITS_ONE_POINT_FIVE: return constants.StopBits.one_and_a_half, StatusCode.success elif bits == serial.STOPBITS_TWO: return constants.StopBits.two, StatusCode.success raise Exception('Unknown bits value: %r' % bits) elif attribute == constants.VI_ATTR_ASRL_XOFF_CHAR: raise NotImplementedError elif attribute == constants.VI_ATTR_INTF_TYPE: return constants.InterfaceType.asrl, StatusCode.success raise UnknownAttribute(attribute) def _set_attribute(self, attribute, attribute_state): """Sets the state of an attribute. Corresponds to viSetAttribute function of the VISA library. :param attribute: Attribute for which the state is to be modified. (Attributes.*) :param attribute_state: The state of the attribute to be set for the specified object. :return: return value of the library call. :rtype: VISAStatus """ if attribute == constants.VI_ATTR_ASRL_ALLOW_TRANSMIT: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_BAUD: self.interface.baudrate = attribute_state return StatusCode.success elif attribute == constants.VI_ATTR_ASRL_BREAK_LEN: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_BREAK_STATE: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_CONNECTED: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_DATA_BITS: self.interface.bytesize = attribute_state return StatusCode.success elif attribute == constants.VI_ATTR_ASRL_DCD_STATE: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_DISCARD_NULL: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_DSR_STATE: return to_state(self.interface.getDSR()) elif attribute == constants.VI_ATTR_ASRL_DTR_STATE: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_FLOW_CNTRL: if not isinstance(attribute_state, int): return StatusCode.error_nonsupported_attribute_state if not 0 < attribute_state < 8: return StatusCode.error_nonsupported_attribute_state try: self.interface.xonxoff = attribute_state & constants.VI_ASRL_FLOW_XON_XOFF self.interface.rtscts = attribute_state & constants.VI_ASRL_FLOW_RTS_CTS self.interface.dsrdtr = attribute_state & constants.VI_ASRL_FLOW_DTR_DSR return StatusCode.success except: return StatusCode.error_nonsupported_attribute_state elif attribute == constants.VI_ATTR_ASRL_PARITY: if attribute_state == constants.Parity.none: self.interface.parity = serial.PARITY_NONE return StatusCode.success elif attribute_state == constants.Parity.even: self.interface.parity = serial.PARITY_EVEN return StatusCode.success elif attribute_state == constants.Parity.odd: self.interface.parity = serial.PARITY_ODD return StatusCode.success elif attribute_state == serial.PARITY_MARK: self.interface.parity = serial.PARITY_MARK return StatusCode.success elif attribute_state == constants.Parity.space: self.interface.parity = serial.PARITY_SPACE return StatusCode.success return StatusCode.error_nonsupported_attribute_state elif attribute == constants.VI_ATTR_ASRL_RI_STATE: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_RTS_STATE: raise NotImplementedError elif attribute == constants.VI_ATTR_ASRL_STOP_BITS: bits = self.interface.stopbits if bits == serial.STOPBITS_ONE: return constants.StopBits.one elif bits == serial.STOPBITS_ONE_POINT_FIVE: return constants.StopBits.one_and_a_half elif bits == serial.STOPBITS_TWO: return constants.StopBits.two raise Exception('Unknown bits value: %r' % bits) elif attribute == constants.VI_ATTR_ASRL_XOFF_CHAR: raise NotImplementedError raise UnknownAttribute(attribute) pyvisa-py-0.3.1/pyvisa-py/sessions.py000066400000000000000000000503011334632567300176500ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ pyvisa-py.session ~~~~~~~~~~~~~~~~~ Base Session class. :copyright: 2014 by PyVISA-py Authors, see AUTHORS for more details. :license: MIT, see LICENSE for more details. """ from __future__ import (division, unicode_literals, print_function, absolute_import) import abc import time from pyvisa import logger, constants, attributes, compat, rname from . import common StatusCode = constants.StatusCode class UnknownAttribute(Exception): def __init__(self, attribute): self.attribute = attribute def __str__(self): attr = self.attribute if isinstance(attr, int): try: name = attributes.AttributesByID[attr].visa_name except KeyError: name = 'Name not found' return 'Unknown attribute %s (%s - %s)' % (attr, hex(attr), name) return 'Unknown attribute %s' % attr __repr__ = __str__ class Session(compat.with_metaclass(abc.ABCMeta)): """A base class for Session objects. Just makes sure that common methods are defined and information is stored. :param resource_manager_session: The session handle of the parent Resource Manager :param resource_name: The resource name. :param parsed: the parsed resource name (optional). If not provided, the resource_name will be parsed. """ @abc.abstractmethod def _get_attribute(self, attribute): """Get the value for a given VISA attribute for this session. Use to implement custom logic for attributes. :param attribute: Resource attribute for which the state query is made :return: The state of the queried attribute for a specified resource, return value of the library call. :rtype: (unicode | str | list | int, VISAStatus) """ @abc.abstractmethod def _set_attribute(self, attribute, attribute_state): """Set the attribute_state value for a given VISA attribute for this session. Use to implement custom logic for attributes. :param attribute: Resource attribute for which the state query is made. :param attribute_state: value. :return: The return value of the library call. :rtype: VISAStatus """ @abc.abstractmethod def close(self): """Close the session. Use it to do final clean ups. """ #: Maps (Interface Type, Resource Class) to Python class encapsulating that #: resource. #: dict[(Interface Type, Resource Class) , Session] _session_classes = dict() #: Session type as (Interface Type, Resource Class) session_type = None @classmethod def get_low_level_info(cls): return '' @classmethod def iter_valid_session_classes(cls): """Yield (Interface Type, Resource Class), Session class pair for valid sessions classes. """ for key, val in cls._session_classes.items(): if issubclass(val, Session): yield key, val @classmethod def iter_session_classes_issues(cls): """Yield (Interface Type, Resource Class), Issues class pair for invalid sessions classes (i.e. those with import errors). """ for key, val in cls._session_classes.items(): try: yield key, getattr(val, 'session_issue') except AttributeError: pass @classmethod def get_session_class(cls, interface_type, resource_class): """Return the session class for a given interface type and resource class. :type interface_type: constants.InterfaceType :type resource_class: str :return: Session """ try: return cls._session_classes[(interface_type, resource_class)] except KeyError: raise ValueError('No class registered for %s, %s' % (interface_type, resource_class)) @classmethod def register(cls, interface_type, resource_class): """Register a session class for a given interface type and resource class. :type interface_type: constants.InterfaceType :type resource_class: str """ def _internal(python_class): if (interface_type, resource_class) in cls._session_classes: logger.warning('%s is already registered in the ' 'ResourceManager. Overwriting with %s', ((interface_type, resource_class), python_class) ) python_class.session_type = (interface_type, resource_class) cls._session_classes[(interface_type, resource_class)] = python_class return python_class return _internal @classmethod def register_unavailable(cls, interface_type, resource_class, msg): """Register an unavailable session class for a given interface type and resource class. raising a ValueError if called. :type interface_type: constants.InterfaceType :type resource_class: str """ # noinspection PyUnusedLocal class _internal(object): session_issue = msg def __init__(self, *args, **kwargs): raise ValueError(msg) _internal.session_issue = msg if (interface_type, resource_class) in cls._session_classes: logger.warning('%s is already registered in the ResourceManager. ' 'Overwriting with unavailable %s', ((interface_type, resource_class), msg)) cls._session_classes[(interface_type, resource_class)] = _internal def __init__(self, resource_manager_session, resource_name, parsed=None, open_timeout=None): if isinstance(resource_name, common.MockInterface): parsed = rname.parse_resource_name(resource_name.resource_name) parsed['mock'] = resource_name elif parsed is None: parsed = rname.parse_resource_name(resource_name) self.parsed = parsed self.open_timeout = open_timeout #: Used as a place holder for the object doing the lowlevel #: communication. self.interface = None #: Used for attributes not handled by the underlying interface. #: Values are get or set automatically by get_attribute and #: set_attribute #: Add your own by overriding after_parsing. self.attrs = {constants.VI_ATTR_RM_SESSION: resource_manager_session, constants.VI_ATTR_RSRC_NAME: str(parsed), constants.VI_ATTR_RSRC_CLASS: parsed.resource_class, constants.VI_ATTR_INTF_TYPE: parsed.interface_type, constants.VI_ATTR_TMO_VALUE: (self._get_timeout, self._set_timeout)} #: Set the default timeout from constants attr = constants.VI_ATTR_TMO_VALUE default_timeout = attributes.AttributesByID[attr].default self.set_attribute(attr, default_timeout) self.after_parsing() def after_parsing(self): """Override this method to provide custom initialization code, to be called after the resourcename is properly parsed ResourceSession can register resource specific attributes handling of them into self.attrs. It is also possible to change handling of already registerd common attributes. List of attributes is available in pyvisa package: * name is in constants module as: VI_ATTR_ * validity of attribute for resource is defined module attributes, AttrVI_ATTR_.resources For static (read only) values, simple readonly and also readwrite attributes simplified construction can be used: ` self.attrs[constants.VI_ATTR_] = 100` or ` self.attrs[constants.VI_ATTR_] = ` For more complex handling of attributes, it is possible to register getter and/or setter. When Null is used, NotSupported error is returned. Getter has same signature as see Session._get_attribute and setter has same signature as see Session._set_attribute. (It is possible to register also see Session._get_attribute and see Session._set_attribute as getter/setter). Getter and Setter are registered as tupple. For readwrite attribute: ` self.attrs[constants.VI_ATTR_] = (, )` For readonly attribute: ` self.attrs[constants.VI_ATTR_] = (, None)` For reusing of see Session._get_attribute and see Session._set_attribute ` self.attrs[constants.VI_ATTR_] = (self._get_attribute, self._set_attribute)` """ pass def gpib_command(self, command_byte): """Write GPIB command byte on the bus. Corresponds to viGpibCommand function of the VISA library. See: https://linux-gpib.sourceforge.io/doc_html/gpib-protocol.html#REFERENCE-COMMAND-BYTES :param command_byte: command byte to send :type command_byte: int, must be [0 255] :return: return value of the library call :rtype: :class:`pyvisa.constants.StatusCode` """ try: return self.sessions[session].gpib_command(command_byte) except KeyError: return constants.StatusCode.error_invalid_object def assert_trigger(self, protocol): """Asserts software or hardware trigger. Corresponds to viAssertTrigger function of the VISA library. :param protocol: Trigger protocol to use during assertion. (Constants.PROT*) :return: return value of the library call. :rtype: :class:`pyvisa.constants.StatusCode` """ raise NotImplementedError def gpib_send_ifc(self): """Pulse the interface clear line (IFC) for at least 100 microseconds. Corresponds to viGpibSendIFC function of the VISA library. :return: return value of the library call. :rtype: :class:`pyvisa.constants.StatusCode` """ return StatusCode.error_nonsupported_operation def clear(self): """Clears a device. Corresponds to viClear function of the VISA library. :return: return value of the library call. :rtype: :class:`pyvisa.constants.StatusCode` """ return StatusCode.error_nonsupported_operation def read_stb(self): """Reads a status byte of the service request. Corresponds to viReadSTB function of the VISA library. :return: Service request status byte, return value of the library call. :rtype: int, :class:`pyvisa.constants.StatusCode` """ return 0, StatusCode.error_nonsupported_operation def lock(self, session, lock_type, timeout, requested_key=None): """Establishes an access mode to the specified resources. Corresponds to viLock function of the VISA library. :param session: Unique logical identifier to a session. :param lock_type: Specifies the type of lock requested, either Constants.EXCLUSIVE_LOCK or Constants.SHARED_LOCK. :param timeout: Absolute time period (in milliseconds) that a resource waits to get unlocked by the locking session before returning an error. :param requested_key: This parameter is not used and should be set to VI_NULL when lockType is VI_EXCLUSIVE_LOCK. :return: access_key that can then be passed to other sessions to share the lock, return value of the library call. :rtype: str, :class:`pyvisa.constants.StatusCode` """ return '', StatusCode.error_nonsupported_operation def unlock(self, session): """Relinquishes a lock for the specified resource. Corresponds to viUnlock function of the VISA library. :param session: Unique logical identifier to a session. :return: return value of the library call. :rtype: :class:`pyvisa.constants.StatusCode` """ return StatusCode.error_nonsupported_operation def get_attribute(self, attribute): """Get the value for a given VISA attribute for this session. Does a few checks before and calls before dispatching to `_get_attribute`. :param attribute: Resource attribute for which the state query is made :return: The state of the queried attribute for a specified resource, return value of the library call. :rtype: (unicode | str | list | int, VISAStatus) """ # Check if the attribute value is defined. try: attr = attributes.AttributesByID[attribute] except KeyError: return 0, StatusCode.error_nonsupported_attribute # Check if the attribute is defined for this session type. if not attr.in_resource(self.session_type): return 0, StatusCode.error_nonsupported_attribute # Check if reading the attribute is allowed. if not attr.read: raise Exception('Do not now how to handle write only attributes.') # First try to answer those attributes that are registered in # self.attrs, see Session.after_parsing if attribute in self.attrs: value = self.attrs[attribute] status = StatusCode.success if isinstance(value, tuple): getter = value[0] value, status = (getter(attribute) if getter else (0, StatusCode.error_nonsupported_attribute)) return value, status # Dispatch to `_get_attribute`, which must be implemented by subclasses try: return self._get_attribute(attribute) except UnknownAttribute as e: logger.exception(str(e)) return 0, StatusCode.error_nonsupported_attribute def set_attribute(self, attribute, attribute_state): """Set the attribute_state value for a given VISA attribute for this session. Does a few checks before and calls before dispatching to `_gst_attribute`. :param attribute: Resource attribute for which the state query is made. :param attribute_state: value. :return: The return value of the library call. :rtype: VISAStatus """ # Check if the attribute value is defined. try: attr = attributes.AttributesByID[attribute] except KeyError: return StatusCode.error_nonsupported_attribute # Check if the attribute is defined for this session type. if not attr.in_resource(self.session_type): return StatusCode.error_nonsupported_attribute # Check if writing the attribute is allowed. if not attr.write: return StatusCode.error_attribute_read_only # First try to answer those attributes that are registered in # self.attrs, see Session.after_parsing if attribute in self.attrs: value = self.attrs[attribute] status = StatusCode.success if isinstance(value, tuple): setter = value[1] status = (setter(attribute, attribute_state) if setter else StatusCode.error_nonsupported_attribute) else: self.attrs[attribute] = attribute_state return status # Dispatch to `_set_attribute`, which must be implemented by subclasses try: return self._set_attribute(attribute, attribute_state) except ValueError: return StatusCode.error_nonsupported_attribute_state except NotImplementedError: e = UnknownAttribute(attribute) logger.exception(str(e)) return StatusCode.error_nonsupported_attribute except UnknownAttribute as e: logger.exception(str(e)) return StatusCode.error_nonsupported_attribute def _read(self, reader, count, end_indicator_checker, suppress_end_en, termination_char, termination_char_en, timeout_exception): """Reads data from device or interface synchronously. Corresponds to viRead function of the VISA library. :param reader: Function to read one or more bytes. :type reader: () -> bytes :param count: Number of bytes to be read. :type count: int :param end_indicator_checker: Function to check if the message is complete. :type end_indicator_checker: (bytes) -> boolean :param suppress_end_en: suppress end. :type suppress_end_en: bool :param termination_char: Stop reading if this character is received. :type suppress_end_en: int or str :param termination_char_en: termination char enabled. :type termination_char_en: boolean :param: timeout_exception: Exception to capture time out for the given interface. :type: Exception :return: data read, return value of the library call. :rtype: bytes, constants.StatusCode """ # NOTE: Some interfaces return not only a single byte but a complete # block for each read therefore we must handle the case that the # termination character is in the middle of the block or that the # maximum number of bytes is exceeded # Make sure termination_char is a string try: termination_char = chr(termination_char) except TypeError: pass finish_time = (None if self.timeout is None else (time.time() + self.timeout)) out = bytearray() while True: try: current = reader() except timeout_exception: return out, StatusCode.error_timeout if current: out.extend(current) end_indicator_received = end_indicator_checker(current) if end_indicator_received: if not suppress_end_en: # RULE 6.1.1 return bytes(out), StatusCode.success else: if termination_char_en and termination_char in current: # RULE 6.1.2 # Return everything upto and including the termination # character return (bytes(out[:out.index(termination_char)+1]), StatusCode.success_termination_character_read) elif len(out) >= count: # RULE 6.1.3 # Return at most the number of bytes requested return (bytes(out[:count]), StatusCode.success_max_count_read) if finish_time and time.time() > finish_time: return bytes(out), StatusCode.error_timeout def _get_timeout(self, attribute): """ Returns timeout calculated value from python way to VI_ way In VISA, the timeout is expressed in milliseconds or using the constants VI_TMO_INFINITE or VI_TMO_IMMEDIATE. In Python we store it as either None (VI_TMO_INFINITE), 0 (VI_TMO_IMMEDIATE) or as a floating point number in seconds. """ if self.timeout is None: ret_value = constants.VI_TMO_INFINITE elif self.timeout == 0: ret_value = constants.VI_TMO_IMMEDIATE else: ret_value = int(self.timeout * 1000.0) return ret_value, StatusCode.success def _set_timeout(self, attribute, value): """ Sets timeout calculated value from python way to VI_ way In VISA, the timeout is expressed in milliseconds or using the constants VI_TMO_INFINITE or VI_TMO_IMMEDIATE. In Python we store it as either None (VI_TMO_INFINITE), 0 (VI_TMO_IMMEDIATE) or as a floating point number in seconds. """ if value == constants.VI_TMO_INFINITE: self.timeout = None elif value == constants.VI_TMO_IMMEDIATE: self.timeout = 0 else: self.timeout = value / 1000.0 return StatusCode.success pyvisa-py-0.3.1/pyvisa-py/tcpip.py000066400000000000000000000535321334632567300171320ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ pyvisa-py.tcpip ~~~~~~~~~~~~~~~ TCPIP Session implementation using Python Standard library. :copyright: 2014 by PyVISA-py Authors, see AUTHORS for more details. :license: MIT, see LICENSE for more details. """ import random import socket import select import time from pyvisa import constants, attributes, errors from .sessions import Session, UnknownAttribute from .protocols import vxi11, rpc from . import common StatusCode = constants.StatusCode # Conversion between VXI11 error codes and VISA status # TODO this is so far a best guess, in particular 6 and 29 are likely wrong VXI11_ERRORS_TO_VISA =\ {0: StatusCode.success, # no_error 1: StatusCode.error_invalid_format, # syntax_error 3: StatusCode.error_connection_lost, # device_no_accessible 4: StatusCode.error_invalid_access_key, # invalid_link_identifier 5: StatusCode.error_invalid_parameter, # parameter_error 6: StatusCode.error_handler_not_installed, # channel_not_established 8: StatusCode.error_nonsupported_operation, # operation_not_supported 9: StatusCode.error_allocation, # out_of_resources 11: StatusCode.error_resource_locked, # device_locked_by_another_link 12: StatusCode.error_session_not_locked, # no_lock_held_by_this_link 15: StatusCode.error_timeout, # io_timeout 17: StatusCode.error_io, # io_error 23: StatusCode.error_abort, # abort 29: StatusCode.error_window_already_mapped, # channel_already_established } @Session.register(constants.InterfaceType.tcpip, 'INSTR') class TCPIPInstrSession(Session): """A TCPIP Session that uses the network standard library to do the low level communication using VXI-11 """ @staticmethod def list_resources(): # TODO: is there a way to get this? return [] def after_parsing(self): # TODO: board_number not handled # TODO: lan_device_name not handled # vx11 expect all timeouts to be expressed in ms and should be integers self.interface = vxi11.CoreClient(self.parsed.host_address, self.open_timeout) self.max_recv_size = 1024 self.lock_timeout = 10000 self.client_id = random.getrandbits(31) error, link, abort_port, max_recv_size =\ self.interface.create_link(self.client_id, 0, self.lock_timeout, self.parsed.lan_device_name) if error: raise Exception("error creating link: %d" % error) self.link = link self.max_recv_size = min(max_recv_size, 2 ** 30) # 1GB for name in ('SEND_END_EN', 'TERMCHAR', 'TERMCHAR_EN'): attribute = getattr(constants, 'VI_ATTR_' + name) self.attrs[attribute] =\ attributes.AttributesByID[attribute].default def close(self): try: self.interface.destroy_link(self.link) except (errors.VisaIOError, socket.error, rpc.RPCError) as e: print("Error closing VISA link: {}".format(e)) self.interface.close() self.link = None self.interface = None def read(self, count): """Reads data from device or interface synchronously. Corresponds to viRead function of the VISA library. :param count: Number of bytes to be read. :return: data read, return value of the library call. :rtype: bytes, VISAStatus """ if count < self.max_recv_size: chunk_length = count else: chunk_length = self.max_recv_size if self.get_attribute(constants.VI_ATTR_TERMCHAR_EN)[0]: term_char, _ = self.get_attribute(constants.VI_ATTR_TERMCHAR) flags = vxi11.OP_FLAG_TERMCHAR_SET else: term_char = flags = 0 read_data = bytearray() reason = 0 # Stop on end of message or when a termination character has been # encountered. end_reason = vxi11.RX_END | vxi11.RX_CHR read_fun = self.interface.device_read status = StatusCode.success timeout = self._io_timeout start_time = time.time() while reason & end_reason == 0: # Decrease timeout so that the total timeout does not get larger # than the specified timeout. timeout = max(0, timeout - int((time.time() - start_time)*1000)) error, reason, data = read_fun(self.link, chunk_length, timeout, self.lock_timeout, flags, term_char) if error == vxi11.ErrorCodes.io_timeout: return bytes(read_data), StatusCode.error_timeout elif error: return bytes(read_data), StatusCode.error_io read_data.extend(data) count -= len(data) if count <= 0: status = StatusCode.success_max_count_read break chunk_length = min(count, chunk_length) return bytes(read_data), status def write(self, data): """Writes data to device or interface synchronously. Corresponds to viWrite function of the VISA library. :param data: data to be written. :type data: str :return: Number of bytes actually transferred, return value of the library call. :rtype: int, VISAStatus """ send_end, _ = self.get_attribute(constants.VI_ATTR_SEND_END_EN) chunk_size = 1024 try: if send_end: flags = vxi11.OP_FLAG_TERMCHAR_SET else: flags = 0 num = len(data) offset = 0 while num > 0: if num <= chunk_size: flags |= vxi11.OP_FLAG_END block = data[offset:offset + self.max_recv_size] error, size = self.interface.device_write( self.link, self._io_timeout, self.lock_timeout, flags, block) if error == vxi11.ErrorCodes.io_timeout: return offset, StatusCode.error_timeout elif error or size < len(block): return offset, StatusCode.error_io offset += size num -= size return offset, StatusCode.success except vxi11.Vxi11Error: return 0, StatusCode.error_timeout def _get_attribute(self, attribute): """Get the value for a given VISA attribute for this session. Use to implement custom logic for attributes. :param attribute: Resource attribute for which the state query is made :return: The state of the queried attribute for a specified resource, return value of the library call. :rtype: (unicode | str | list | int, VISAStatus) """ if attribute == constants.VI_ATTR_TCPIP_ADDR: return self.host_address, StatusCode.success elif attribute == constants.VI_ATTR_TCPIP_DEVICE_NAME: raise NotImplementedError elif attribute == constants.VI_ATTR_TCPIP_HOSTNAME: raise NotImplementedError elif attribute == constants.VI_ATTR_TCPIP_KEEPALIVE: raise NotImplementedError elif attribute == constants.VI_ATTR_TCPIP_NODELAY: raise NotImplementedError elif attribute == constants.VI_ATTR_TCPIP_PORT: raise NotImplementedError elif attribute == constants.VI_ATTR_SUPPRESS_END_EN: raise NotImplementedError raise UnknownAttribute(attribute) def _set_attribute(self, attribute, attribute_state): """Sets the state of an attribute. Corresponds to viSetAttribute function of the VISA library. :param attribute: Attribute for which the state is to be modified. (Attributes.*) :param attribute_state: The state of the attribute to be set for the specified object. :return: return value of the library call. :rtype: VISAStatus """ raise UnknownAttribute(attribute) def assert_trigger(self, protocol): """Asserts software or hardware trigger. Corresponds to viAssertTrigger function of the VISA library. :param protocol: Trigger protocol to use during assertion. (Constants.PROT*) :return: return value of the library call. :rtype: VISAStatus """ error = self.interface.device_trigger(self.link, 0, self.lock_timeout, self._io_timeout) return VXI11_ERRORS_TO_VISA[error] def clear(self): """Clears a device. Corresponds to viClear function of the VISA library. :return: return value of the library call. :rtype: VISAStatus """ error = self.interface.device_clear(self.link, 0, self.lock_timeout, self._io_timeout) return VXI11_ERRORS_TO_VISA[error] def read_stb(self): """Reads a status byte of the service request. Corresponds to viReadSTB function of the VISA library. :return: Service request status byte, return value of the library call. :rtype: int, :class:`pyvisa.constants.StatusCode` """ error, stb = self.interface.device_read_stb(self.link, 0, self.lock_timeout, self._io_timeout) return stb, VXI11_ERRORS_TO_VISA[error] def lock(self, lock_type, timeout, requested_key=None): """Establishes an access mode to the specified resources. Corresponds to viLock function of the VISA library. :param lock_type: Specifies the type of lock requested, either Constants.EXCLUSIVE_LOCK or Constants.SHARED_LOCK. :param timeout: Absolute time period (in milliseconds) that a resource waits to get unlocked by the locking session before returning an error. :param requested_key: This parameter is not used and should be set to VI_NULL when lockType is VI_EXCLUSIVE_LOCK. :return: access_key that can then be passed to other sessions to share the lock, return value of the library call. :rtype: str, VISAStatus """ # TODO: lock type not implemented flags = 0 error = self.interface.device_lock(self.link, flags, self.lock_timeout) return VXI11_ERRORS_TO_VISA[error] def unlock(self): """Relinquishes a lock for the specified resource. Corresponds to viUnlock function of the VISA library. :return: return value of the library call. :rtype: VISAStatus """ error = self.interface.device_unlock(self.link) return VXI11_ERRORS_TO_VISA[error] def _set_timeout(self, attribute, value): """ Sets timeout calculated value from python way to VI_ way """ if value == constants.VI_TMO_INFINITE: self.timeout = None self._io_timeout = 2**32-1 elif value == constants.VI_TMO_IMMEDIATE: self.timeout = 0 self._io_timeout = 0 else: self.timeout = value / 1000.0 self._io_timeout = int(self.timeout*1000) return StatusCode.success @Session.register(constants.InterfaceType.tcpip, 'SOCKET') class TCPIPSocketSession(Session): """A TCPIP Session that uses the network standard library to do the low level communication. """ # Details about implementation: # On Windows, select is not interrupted by KeyboardInterrupt, to avoid # blocking for very long time, we use a decreasing timeout in select. # A minimum select timeout which prevents using too short select interval # is also calculated and select timeout is not lower that that minimum # timeout. The absolute minimum is 1 ms as a consequence. # This is valid for connect and read operations @staticmethod def list_resources(): # TODO: is there a way to get this? return [] def after_parsing(self): # TODO: board_number not handled ret_status = self._connect() if ret_status != StatusCode.success: self.close() raise Exception("could not connect: {0}".format(str(ret_status))) self.max_recv_size = 4096 # This buffer is used to store the bytes that appeared after # termination char self._pending_buffer = bytearray() self.attrs[constants.VI_ATTR_TCPIP_ADDR] = self.parsed.host_address self.attrs[constants.VI_ATTR_TCPIP_PORT] = self.parsed.port self.attrs[constants.VI_ATTR_INTF_NUM] = self.parsed.board self.attrs[constants.VI_ATTR_TCPIP_NODELAY] = (self._get_tcpip_nodelay, self._set_attribute) self.attrs[constants.VI_ATTR_TCPIP_HOSTNAME] = '' self.attrs[constants.VI_ATTR_TCPIP_KEEPALIVE] = \ (self._get_tcpip_keepalive, self._set_tcpip_keepalive) # to use default as ni visa driver (NI-VISA 15.0) self.attrs[constants.VI_ATTR_SUPPRESS_END_EN] = True for name in ('TERMCHAR', 'TERMCHAR_EN'): attribute = getattr(constants, 'VI_ATTR_' + name) self.attrs[attribute] =\ attributes.AttributesByID[attribute].default def _connect(self): timeout = self.open_timeout / 1000.0 if self.open_timeout else 10.0 try: self.interface = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.interface.setblocking(0) self.interface.connect_ex((self.parsed.host_address, int(self.parsed.port))) except Exception as e: raise Exception("could not connect: {0}".format(str(e))) finally: self.interface.setblocking(1) # minimum is in interval 100 - 500ms based on timeout min_select_timeout = max(min(timeout/10.0, 0.5), 0.1) # initial 'select_timout' is half of timeout or max 2 secs # (max blocking time). min is from 'min_select_timeout' select_timout = max(min(timeout/2.0, 2.0), min_select_timeout) # time, when loop shall finish finish_time = time.time() + timeout while True: # use select to wait for socket ready, max `select_timout` seconds r, w, x = select.select([self.interface], [self.interface], [], select_timout) if self.interface in r or self.interface in w: return StatusCode.success if time.time() >= finish_time: # reached timeout return StatusCode.error_timeout # `select_timout` decreased to 50% of previous or # min_select_timeout select_timout = max(select_timout / 2.0, min_select_timeout) def close(self): self.interface.close() self.interface = None def read(self, count): """Reads data from device or interface synchronously. Corresponds to viRead function of the VISA library. :param count: Number of bytes to be read. :return: data read, return value of the library call. :rtype: bytes, VISAStatus """ if count < self.max_recv_size: chunk_length = count else: chunk_length = self.max_recv_size term_char, _ = self.get_attribute(constants.VI_ATTR_TERMCHAR) term_byte = common.int_to_byte(term_char) if term_char else b'' term_char_en, _ = self.get_attribute(constants.VI_ATTR_TERMCHAR_EN) suppress_end_en, _ =\ self.get_attribute(constants.VI_ATTR_SUPPRESS_END_EN) read_fun = self.interface.recv # minimum is in interval 1 - 100ms based on timeout, 1sec if no timeout # defined min_select_timeout = (1 if self.timeout is None else max(min(self.timeout / 100.0, 0.1), 0.001)) # initial 'select_timout' is half of timeout or max 2 secs # (max blocking time). min is from 'min_select_timeout' select_timout = (2.0 if self.timeout is None else max(min(self.timeout / 2.0, 2.0), min_select_timeout)) # time, when loop shall finish, None means never ending story if no # data arrives finish_time = (None if self.timeout is None else (time.time() + self.timeout)) while True: # check, if we have any data received (from pending buffer or # further reading) if term_char_en and term_byte in self._pending_buffer: term_byte_index = self._pending_buffer.index(term_byte) + 1 if term_byte_index > count: term_byte_index = count status = StatusCode.success_max_count_read else: status = StatusCode.success_termination_character_read out = bytes(self._pending_buffer[:term_byte_index]) self._pending_buffer = self._pending_buffer[term_byte_index:] return out, status if len(self._pending_buffer) >= count: out = bytes(self._pending_buffer[:count]) self._pending_buffer = self._pending_buffer[count:] return out, StatusCode.success_max_count_read # use select to wait for read ready, max `select_timout` seconds r, w, x = select.select([self.interface], [], [], select_timout) read_data = b'' if self.interface in r: read_data = read_fun(chunk_length) self._pending_buffer.extend(read_data) if not read_data: # can't read chunk or timeout if self._pending_buffer and not suppress_end_en: # we have some data without termchar but no further data # expected out = bytes(self._pending_buffer[:count]) self._pending_buffer = self._pending_buffer[count:] return out, StatusCode.succes if finish_time and time.time() >= finish_time: # reached timeout out = bytes(self._pending_buffer[:count]) self._pending_buffer = self._pending_buffer[count:] return out, StatusCode.error_timeout # `select_timout` decreased to 50% of previous or # min_select_timeout select_timout = max(select_timout / 2.0, min_select_timeout) def write(self, data): """Writes data to device or interface synchronously. Corresponds to viWrite function of the VISA library. :param data: data to be written. :type data: str :return: Number of bytes actually transferred, return value of the library call. :rtype: int, VISAStatus """ chunk_size = 4096 num = sz = len(data) offset = 0 while num > 0: block = data[offset:min(offset + chunk_size, sz)] try: # use select to wait for write ready select.select([], [self.interface], []) size = self.interface.send(block) except socket.timeout as e: return offset, StatusCode.error_io if size < len(block): return offset, StatusCode.error_io offset += size num -= size return offset, StatusCode.success def _get_tcpip_nodelay(self, attribute): if self.interface: value = self.interface.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY) return (constants.VI_TRUE if value == 1 else constants.VI_FALSE, StatusCode.succes) return 0, StatusCode.error_nonsupported_attribute def _set_tcpip_nodelay(self, attribute, attribute_state): if self.interface: self.interface.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1 if attribute_state else 0) return StatusCode.succes return 0, StatusCode.error_nonsupported_attribute def _get_tcpip_keepalive(self, attribute): if self.interface: value = self.interface.getsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE) return (constants.VI_TRUE if value == 1 else constants.VI_FALSE, StatusCode.succes) return 0, StatusCode.error_nonsupported_attribute def _set_tcpip_keepalive(self, attribute, attribute_state): if self.interface: self.interface.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1 if attribute_state else 0) return StatusCode.succes return 0, StatusCode.error_nonsupported_attribute def _get_attribute(self, attribute): """Get the value for a given VISA attribute for this session. Use to implement custom logic for attributes. :param attribute: Resource attribute for which the state query is made :return: The state of the queried attribute for a specified resource, return value of the library call. :rtype: (unicode | str | list | int, VISAStatus) """ raise UnknownAttribute(attribute) def _set_attribute(self, attribute, attribute_state): """Sets the state of an attribute. Corresponds to viSetAttribute function of the VISA library. :param attribute: Attribute for which the state is to be modified. (Attributes.*) :param attribute_state: The state of the attribute to be set for the specified object. :return: return value of the library call. :rtype: VISAStatus """ raise UnknownAttribute(attribute) pyvisa-py-0.3.1/pyvisa-py/testsuite/000077500000000000000000000000001334632567300174625ustar00rootroot00000000000000pyvisa-py-0.3.1/pyvisa-py/testsuite/__init__.py000066400000000000000000000012171334632567300215740ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import (division, unicode_literals, print_function, absolute_import) import os import unittest def testsuite(): """A testsuite that has all the pyvisa tests. """ return unittest.TestLoader().discover(os.path.dirname(__file__)) def main(): """Runs the testsuite as command line application. """ try: unittest.main() except Exception as e: print('Error: %s' % e) def run(): """Run all tests. :return: a :class:`unittest.TestResult` object """ test_runner = unittest.TextTestRunner() return test_runner.run(testsuite()) pyvisa-py-0.3.1/pyvisa-py/usb.py000066400000000000000000000221771334632567300166050ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ pyvisa-py.usb ~~~~~~~~~~~~~ Serial Session implementation using PyUSB. :copyright: 2014 by PyVISA-py Authors, see AUTHORS for more details. :license: MIT, see LICENSE for more details. """ from __future__ import division, unicode_literals, print_function, absolute_import import logging from pyvisa import constants, attributes from .sessions import Session, UnknownAttribute try: import usb from .protocols import usbtmc, usbutil, usbraw except ImportError as e: msg = 'Please install PyUSB to use this resource type.\n%s' Session.register_unavailable(constants.InterfaceType.usb, 'INSTR', msg % e) Session.register_unavailable(constants.InterfaceType.usb, 'RAW', msg % e) raise try: _ = usb.core.find() except Exception as e: msg = 'PyUSB does not seem to be properly installed.\n' \ 'Please refer to PyUSB documentation and \n' \ 'install a suitable backend like \n' \ 'libusb 0.1, libusb 1.0, libusbx, \n' \ 'libusb-win32 or OpenUSB.\n%s' % e Session.register_unavailable(constants.InterfaceType.usb, 'INSTR', msg) Session.register_unavailable(constants.InterfaceType.usb, 'RAW', msg) raise StatusCode = constants.StatusCode class USBSession(Session): """Base class for drivers that communicate with usb devices via usb port using pyUSB """ @staticmethod def list_resources(): """Return list of resources for this type of USB device""" raise NotImplementedError @classmethod def get_low_level_info(cls): try: ver = usb.__version__ except AttributeError: ver = 'N/A' try: # noinspection PyProtectedMember backend = usb.core.find()._ctx.backend.__class__.__module__.split('.')[-1] except Exception: backend = 'N/A' return 'via PyUSB (%s). Backend: %s' % (ver, backend) def _get_timeout(self, attribute): if self.interface: if self.interface.timeout == 2**32-1: self.timeout = None else: self.timeout = self.interface.timeout / 1000 return super(USBSession, self)._get_timeout(attribute) def _set_timeout(self, attribute, value): status = super(USBSession, self)._set_timeout(attribute, value) timeout = int(self.timeout*1000) if self.timeout else 2**32-1 if self.interface: self.interface.timeout = timeout return status def read(self, count): """Reads data from device or interface synchronously. Corresponds to viRead function of the VISA library. :param count: Number of bytes to be read. :return: data read, return value of the library call. :rtype: (bytes, VISAStatus) """ supress_end_en, _ = self.get_attribute(constants.VI_ATTR_SUPPRESS_END_EN) if supress_end_en: raise ValueError('VI_ATTR_SUPPRESS_END_EN == True is currently unsupported by pyvisa-py') term_char, _ = self.get_attribute(constants.VI_ATTR_TERMCHAR) term_char_en, _ = self.get_attribute(constants.VI_ATTR_TERMCHAR_EN) return self._read(lambda: self.interface.read(count), count, lambda current: True, # USB always returns a complete message supress_end_en, term_char, term_char_en, usb.USBError) def write(self, data): """Writes data to device or interface synchronously. Corresponds to viWrite function of the VISA library. :param data: data to be written. :type data: bytes :return: Number of bytes actually transferred, return value of the library call. :rtype: (int, VISAStatus) """ send_end, _ = self.get_attribute(constants.VI_ATTR_SEND_END_EN) count = self.interface.write(data) return count, StatusCode.success def close(self): self.interface.close() def _get_attribute(self, attribute): """Get the value for a given VISA attribute for this session. Use to implement custom logic for attributes. :param attribute: Resource attribute for which the state query is made :return: The state of the queried attribute for a specified resource, return value of the library call. :rtype: (unicode | str | list | int, VISAStatus) """ raise UnknownAttribute(attribute) def _set_attribute(self, attribute, attribute_state): """Sets the state of an attribute. Corresponds to viSetAttribute function of the VISA library. :param attribute: Attribute for which the state is to be modified. (Attributes.*) :param attribute_state: The state of the attribute to be set for the specified object. :return: return value of the library call. :rtype: VISAStatus """ raise UnknownAttribute(attribute) @Session.register(constants.InterfaceType.usb, 'INSTR') class USBInstrSession(USBSession): """Base class for drivers that communicate with instruments via usb port using pyUSB """ @staticmethod def list_resources(): out = [] fmt = 'USB%(board)s::%(manufacturer_id)s::%(model_code)s::' \ '%(serial_number)s::%(usb_interface_number)s::INSTR' for dev in usbtmc.find_tmc_devices(): intfc = usbutil.find_interfaces(dev, bInterfaceClass=0xfe, bInterfaceSubClass=3) try: intfc = intfc[0].index except (IndexError, AttributeError): intfc = 0 try: serial = dev.serial_number except (NotImplementedError, ValueError): logger = logging.getLogger(__name__) msg = ('Found a device whose serial number cannot be read.' ' The partial VISA resource name is: ' + fmt) logger.warning(msg, dict(board=0, manufacturer_id=dev.idVendor, model_code=dev.idProduct, serial_number='???', usb_interface_number=intfc)) continue out.append(fmt % dict(board=0, manufacturer_id=dev.idVendor, model_code=dev.idProduct, serial_number=serial, usb_interface_number=intfc)) return out def after_parsing(self): self.interface = usbtmc.USBTMC(int(self.parsed.manufacturer_id, 0), int(self.parsed.model_code, 0), self.parsed.serial_number) for name in ('SEND_END_EN', 'TERMCHAR', 'TERMCHAR_EN'): attribute = getattr(constants, 'VI_ATTR_' + name) self.attrs[attribute] = attributes.AttributesByID[attribute].default @Session.register(constants.InterfaceType.usb, 'RAW') class USBRawSession(USBSession): """Base class for drivers that communicate with usb raw devices via usb port using pyUSB """ @staticmethod def list_resources(): out = [] fmt = 'USB%(board)s::%(manufacturer_id)s::%(model_code)s::' \ '%(serial_number)s::%(usb_interface_number)s::RAW' for dev in usbraw.find_raw_devices(): intfc = usbutil.find_interfaces(dev, bInterfaceClass=0xFF) try: intfc = intfc[0].index except (IndexError, AttributeError): intfc = 0 try: serial = dev.serial_number except (NotImplementedError, ValueError): logger = logging.getLogger(__name__) msg = ('Found a device whose serial number cannot be read.' ' The partial VISA resource name is: ' + fmt) logger.warning(msg, dict(board=0, manufacturer_id=dev.idVendor, model_code=dev.idProduct, serial_number='???', usb_interface_number=intfc)) continue out.append(fmt % dict(board=0, manufacturer_id=dev.idVendor, model_code=dev.idProduct, serial_number=serial, usb_interface_number=intfc)) return out def after_parsing(self): self.interface = usbraw.USBRawDevice(int(self.parsed.manufacturer_id, 0), int(self.parsed.model_code, 0), self.parsed.serial_number) for name in ('SEND_END_EN', 'TERMCHAR', 'TERMCHAR_EN'): attribute = getattr(constants, 'VI_ATTR_' + name) self.attrs[attribute] = attributes.AttributesByID[attribute].default pyvisa-py-0.3.1/setup.cfg000066400000000000000000000000661334632567300153130ustar00rootroot00000000000000[check-manifest] ignore = .travis.yml tox.ini pyvisa-py-0.3.1/setup.py000066400000000000000000000040351334632567300152040ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import sys try: from setuptools import setup except ImportError: print('Please install or upgrade setuptools or pip to continue') sys.exit(1) def read(filename): with open(filename, 'rb') as f: return f.read().decode('utf8') long_description = '\n\n'.join([read('README'), read('AUTHORS'), read('CHANGES')]) __doc__ = long_description requirements = ['pyvisa>=1.8'] setup(name='PyVISA-py', description='Python VISA bindings for GPIB, RS232, and USB instruments', version='0.3.1', long_description=long_description, author='Hernan E. Grecco', author_email='hernan.grecco@gmail.com', maintainer='Hernan E. Grecco', maintainer_email='hernan.grecco@gmail.com', url='https://github.com/pyvisa/pyvisa-py', test_suite='pyvisa-py.testsuite.testsuite', keywords='Remote VISA GPIB USB serial RS232 measurement acquisition', license='MIT License', install_requires=requirements, classifiers=[ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: MIT License', 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX :: Linux', 'Operating System :: MacOS :: MacOS X', 'Programming Language :: Python', 'Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator', 'Topic :: Software Development :: Libraries :: Python Modules', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', ], packages=['pyvisa-py', 'pyvisa-py.protocols', 'pyvisa-py.testsuite'], platforms="Linux, Windows, Mac", use_2to3=False, zip_safe=False)