Archive for the ‘Linux’ Category

Linux NAT via iptables

Thursday, September 15th, 2011 by lane

If eth0 has an external network connection and you want to NAT your eth1 connection, you can use the following commands (as root):

echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -A FORWARD -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT

Chronovu USB LA-8 Logic Analyzer

Friday, August 13th, 2010 by lane

I am a fan of reducing cost and complexity of test equipment by pushing the UI to the PC to make the test equipment headless. In this vein, however, I was previously disappointed in the purchase an ELAN USB oscilloscope. It claimed Linux support, but after much hoop jumping, I never got their java app working on linux. I ended up running it in a virtual machine running windows, and even then the experience was not great. That is story for another post, though. For this post I am going to provide my initial feedback on the ChronoVu USB Logic Analyzer LA-8 that I purchased on Ebay for $189.00.

The primary reasons I picked the ChronoVu amongst the other several options (see Comments at this link from SparkFun.com for additional competitive products) was that it sampled at 100MHz and the app ran on Linux without java. I downloaded the app prior to purchasing to give it a test run and noticed that it used QT for widgets, so I was happy that the performance had a chance at being adequate on Linux.

Amazingly, the setup on Linux (or at least Fedora 13) was quite seemless. I am used to futzing with everything from udev rules to 64b/32b issues to compiling kernel modules to etc. when using these sort of fringe products that claim Linux support, but everything worked out of the box on my Fedora 13 Linux install. The lsusb output is shown at the end of this post for those interested. It basically enumerates as a serial device and on my Fedora 13 machine, it appears on device node ‘/dev/ttyUSBX’ with correct permissions so that I can use it without root access (in other words, udev rules exist and work without issue). The application seems to detect and find the correct ttyUSB devnode to use, so I am not sure how it would behave with multiple units plugged in, but I do have other usb-serial devs on ttyUSB nodes and it has never been confused or had issues with that. That was a refreshing experience that shows they are serious about linux and not just releasing crippled linux support for marketing reasons.

My initial experience was to debug an I2C problem I was having. I flipped into a precanned I2C setup on the application, hooked up my probes, and pressed play. It asked for a file to save the data to (which I now find a bit annoying). It then downloaded and processed the data. That takes more time than I would like, but the precanned I2C bus analysis worked well and performed a deserialization of the data correctly. All that worked without any issue. Kudos to ChronoVu. It was a better experience than I was expecting based on my previous experience with a piece of USB test equipment.

While the initial experience was positive, after using it, there are several user interface issues that still keep this device in a class below dedicated logic analyzers. The sad thing is that these are primarily software issues. I hope ChronoVu takes notice because if these are addressed, then it will be a happy day for me when I can replace a many tens of thousand dollar machine that is the size of a desktop PC and requires its own cart with a sub $200 pocket sized piece of equipment. They have already taken a major step to that end, but it is not quite there (yet).

User Interface Issues

  • You cannot setup triggering options beyond the simple state==0 or state==1. This makes it hard to sync to events of interest. This is my biggest complaint. Makes it hard to do more than just simple debugging.
  • The zoom level resets after every acquisition. Quite a pain given that events of interest can take a while to find again. This issue is also related to the lack of complex triggering options given that even if the view didn’t reset, I will still have to scroll around to find my event.
  • The UI is sluggish to zoom and pan. This is annoying and further exacerbates the view reseting issue previously mentioned. This is my second biggest complaint.
  • You cannot zoom in indefinitely, and even worse, you cannot zoom in adequately to see even 25ns clocks. This is quite annoying. I sampled a 25MHz clock at 100MHz and would like to see the clock up close. I realize that there will be some frequency beating between the 25MHz clock and 100MHz sampling rate, and I can live with that, but I still want to be able to zoom in and put some cursors down at the clock transition edges and make sure my clock is running as I expect. Instead I can only zoom in close enough to see a very high frequency signal, but nothing sufficient for what I want.
  • It asks to save a file everytime you press play to capture some data. 90% of the time I am taking setup data and I want it as quickly as possible. For the 10% of the time I take data I care about (after I have it setup and framed the way I want), then it would be nice to click a “Save As” button and save the raw data somewhere. Otherwise, I would prefer it save to a temp file that I don’t have to manage or know about. I would rather click to save the data permanently after I know the data is what I want. Don’t bother me a priori with a popup box.
  • Download and process time take too long. I count around 12 Mississippi’s (seconds). This is not a show a stopper, but annoying. They must not be using USB 2.0 high speed. I am not familiar with the Future Technologies USB-Serial chip they are using, but they would be well served by going with a chipset that supported high speed option as this would make it around 10 times faster and much more bearable.
  • This one is a nit-pick, but the application installer creates a new root menu in the GNOME “Applications” menu list. Perhaps it should install in the FEL “Electronics” menu or “Other”.
  • I don’t need a CD or a carrying case and would prefer not to pay for them.

Hardware Issues

  • There is crosstalk issue. I plugged in a low frequency signals into channel 0 (FV) and channel 1 (LV) and a 50MHz clock into channel 2 (CLK). The clock beats as expected against the 100MHz sampling rate, but it corrupts channel 0 and channel 1 as you can see in this screen shot.

    Disconnecting channel 2 probe from the clock and connecting it to ground solves the problem. The following is screen shot shows what channel 0 and channel 1 should look like in the previous capture.
  • If I had to guess, there is a significant inductance on the ground connection between the units and the ground bounce induced by the high frequency clock is causing this problem. It is hard to blame this one on them without some more futzing, so for now, I will only hook up to the clock when I slow everything down to debug.

    lsusb -v -s 001:080 output

    Bus 001 Device 080: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
    Device Descriptor:
      bLength                18
      bDescriptorType         1
      bcdUSB               2.00
      bDeviceClass            0 (Defined at Interface level)
      bDeviceSubClass         0
      bDeviceProtocol         0
      bMaxPacketSize0         8
      idVendor           0x0403 Future Technology Devices International, Ltd
      idProduct          0x6001 FT232 USB-Serial (UART) IC
      bcdDevice            6.00
      iManufacturer           1 ChronoVu
      iProduct                2 ChronoVu LA8
      iSerial                 3 CV100528120813
      bNumConfigurations      1
      Configuration Descriptor:
        bLength                 9
        bDescriptorType         2
        wTotalLength           32
        bNumInterfaces          1
        bConfigurationValue     1
        iConfiguration          0
        bmAttributes         0x80
          (Bus Powered)
        MaxPower              200mA
        Interface Descriptor:
          bLength                 9
          bDescriptorType         4
          bInterfaceNumber        0
          bAlternateSetting       0
          bNumEndpoints           2
          bInterfaceClass       255 Vendor Specific Class
          bInterfaceSubClass    255 Vendor Specific Subclass
          bInterfaceProtocol    255 Vendor Specific Protocol
          iInterface              2 ChronoVu LA8
          Endpoint Descriptor:
            bLength                 7
            bDescriptorType         5
            bEndpointAddress     0x81  EP 1 IN
            bmAttributes            2
              Transfer Type            Bulk
              Synch Type               None
              Usage Type               Data
            wMaxPacketSize     0x0040  1x 64 bytes
            bInterval               0
          Endpoint Descriptor:
            bLength                 7
            bDescriptorType         5
            bEndpointAddress     0x02  EP 2 OUT
            bmAttributes            2
              Transfer Type            Bulk
              Synch Type               None
              Usage Type               Data
            wMaxPacketSize     0x0040  1x 64 bytes
            bInterval               0
    Device Status:     0x0000
      (Bus Powered)
    

    Making Exim Case-Insensitive

    Saturday, October 18th, 2008 by lane

    I discovered that exim is sensitive such that Lane@example.com is a different user than lane@example.com. In my past experience sendmail was tolerant of such differences. I am not sure if that is because the sendmail configuration files distributed by Fedora/Redhat had that already setup or if it is built into sendmail. Regardless, I had some users expressing problems with email and we finally figured out it was because people were trying to send them email to usernames with capital letters in them. I added the following to my exim.conf file right before the localuser: router. Order is important, so make sure you put it in the right place.

    lowercase_local:
         driver = redirect
         redirect_router = localuser
         domains = +local_domains
         data = ${lc:$local_part}@$domain
    

    Certicates on Fedora/Redhat Linux Distributions

    Saturday, October 18th, 2008 by lane

    With Firefox 3 requiring you to jump through so many hoops to accept an personally signed certificate, I have decided to actually purchase a signed certificate to prevent my users from jumping through the hoops.  I was surprised at how easy it has become to get a signed certificate.  I used godaddy to sign my certificates since I already have an account with them.  They require a Certificate Signing Request (CSR).  The following instructions detail how to generate the requested CSR.

    1. As root, go into the /etc/pki/tls/certs. Check that you have a key already in the /etc/pki/tls/private directory called localhost.key. Then run the following command to generate the CSR:

      /usr/bin/openssl req -new -key ../private/localhost.key -out localhost.csr

      Answer all the questions. The most important question is the Common Name question. Make sure to put the host you want signed here, e.g. www.example.com. Then send this CSR to your signing agency.

    2. After you signing agency sends you back your certificate and their certificate, put them in the /etc/pki/tls/certs directory. Let’s suppose you call them mycert.crt and theircert.crt. Then update your apache configuration file to reflect these files. Here is what my squirrel mail virtual host section looks like in file /etc/httpd/conf.d/squirrelmail.conf:
      
      DocumentRoot "/usr/share/squirrelmail"
      ServerName webmail.example.com:443
      
      ErrorLog logs/webmail_error_log
      TransferLog logs/webmail_access_log
      LogLevel warn
      SSLEngine on
      SSLProtocol all -SSLv2
      SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW
      SSLCertificateFile /etc/pki/tls/certs/mycert.crt
      SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
      SSLCertificateChainFile /etc/pki/tls/certs/theircert.crt
      
          SSLOptions +StdEnvVars
      
      
      SetEnvIf User-Agent ".*MSIE.*" \
               nokeepalive ssl-unclean-shutdown \
               downgrade-1.0 force-response-1.0
      
      CustomLog logs/webmail_request_log \
                "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
      
      
      
    3. Restart httpd and test it out. No more nasty messages about unsigned certificates!

    Kerberos

    Friday, August 22nd, 2008 by lane

    I started using openldap for user information and automouting and I like it a lot despite the fact that it is more feature rich than I understand right now. I wanted to test afs and coda to see if they would meet our file system sharing needs, but both require Kerberos for authentication. I tried setting up Kerberos some 10 years ago and was not successful with and determined it was overkill for my small networking needs, so I was hesitant to try it again. Despite my reservations, however, tried it on both on a CentOS 5.2 and Fedora 8 server and was pleasantly surprised at how easy it was to setup. The RedHat Deployment Manual has very good instructions that I followed and had a working Kerberos setup in a very short time.

    I still use LDAP for user information but am now using kerberos for authentication. To enable kerberos on the client machines, just copy the /etc/krb5.conf and run

    authconfig --enablekrb5 --update

    OpenVPN setup on Centos 5.2

    Sunday, August 10th, 2008 by lane

    OpenVPN is a very capable SSL-based VPN client/server software package. It has great documentation at
    OpenVPN Howto Documents.

    • To install on CentOS, I grab the rpms from the EPEL repo. EPEL stands for Extra Packages for Enterprise Linux. They are Fedora packages repackaged for Redhat Enterprise. The project homepage and documentation is at http://fedoraproject.org/wiki/EPEL. There is also a package list at that site.
      To install the EPEL yum repo, run the following command:

      sudo rpm -ihv http://download.fedora.redhat.com/pub/epel/5/x86_64/epel-release-5-2.noarch.rpm 

      Change the architecture and version appropriately for your machine.

    • Install OpenVPN with the following command:
      yum install openvpn
    • For now I will setup OpenVPN to route rather than bridge. Later I will likely bridge two remote networks.
    • Generate the Master Certificate Authority. Copy the templates files into place:
      sudo cp -r /usr/share/openvpn/easy-rsa/2.0 /etc/openvpn/certs

      Now cd into /etc/openvpn/certs and edit the var file. The only thing I changed was the last five lines containing the location information. Now run the following commands

      sudo su
      . ./vars
      ./clean-all
      ./build-ca
      

      Note that you want to be root when running these commands because the vars script alters your environment, and they will get lost if you are using sudo on each command individually.

    • Generate certificate & key for server.
      ./build-key-server server_name

      I left challenge password empty and answered yes to signing and committing the certificate.

    • Generate client certificates
      ./build-key client1
    • Build Diffie Hellman data
      ./build-dh
    • You can now drop root permissions and setup the server configuration file
      sudo cp /usr/share/doc/openvpn-2.1/sample-config-files/server.conf /etc/openvpn

      Edit it to your liking. I did not change much except to add paths appropriately to the certificate and dh files.

    • Install OpenVPN on the client.
      yum install openvon

      . In my case this a Fedora 9 machine.

    • sudo cp /usr/share/doc/openvpn-2.1/sample-config-files/client.conf /etc/openvpn/

      and edit it to your liking.

    • Copy the keys from the server to the client and start it up
    • For routing so that I run the following
      echo 1 > /proc/sys/net/ipv4/ip_forward

      on the server so that machines on the same subnet as the server can talk to the clients. Likewise, I add the following static route to the default gateway (which is my wireless router):

      Destination LAN IP:  	  10.8.0.0
      		Subnet Mask: 	255.255.255.0
      		Gateway: 	192.168.35.2
      

      where gateway is the IP of the vpn server.

    LVM Example

    Monday, July 28th, 2008 by lane

    I always look at the MythTV documentation for a short, quick LVM reference

    I have a large 2TB RAID 5 device that I want to split into two partitions. LVM gives that ability. Here are the steps I followed:

    • Create the physical group
      sudo pvcreate /dev/md0
    • Create the volume to include the whole physical group.
      vgcreate bigdisk /dev/md0
    • Then use lvcreate as follows:
      sudo lvcreate --name mm --size 1TB bigdisk
      sudo lvcreate --name home -l 214789 bigdisk

    Example Software RAID 5 Setup in Linux

    Monday, July 28th, 2008 by lane

    I have three identical 1TB hard drives that I want to configure in a RAID 5 configuration to give me 2 TB. A good resource is RAID Quick HOWTO. Here are the steps I took:

    • Create partitions on the desired devices to have a type of 0xFD (linux raid autodetect). I created a single 1TB partition on each drive using fdisk.
    • Create the raid device using mdadm command
       sudo mdadm --create --verbose --level=5 --raid-devices=3 /dev/md0 /dev/sda1 /dev/sdc1 /dev/sdd1
    • The output for me looks like this:

      mdadm: layout defaults to left-symmetric
      mdadm: chunk size defaults to 64K
      mdadm: /dev/sdc1 appears to be part of a raid array:
          level=raid5 devices=2 ctime=Mon Jul 28 09:09:11 2008
      mdadm: /dev/sdd1 appears to be part of a raid array:
          level=raid5 devices=2 ctime=Mon Jul 28 09:09:11 2008
      mdadm: size set to 976759936K
      Continue creating array? y
      mdadm: array /dev/md0 started.
      
    • Take a look in the /proc/mdstat file to see how things went. For me, it looks like
      this

      $ cat /proc/mdstat
      Personalities : [raid6] [raid5] [raid4]
      md0 : active raid5 sdd1[3] sdc1[1] sda1[0]
            1953519872 blocks level 5, 64k chunk, algorithm 2 [3/2] [UU_]
            [>....................]  recovery =  0.0% (55552/976759936) finish=1171.1min speed=13888K/sec
      
      unused devices: 
      
    • Create the /etc/mdadm.conf file.
      mdadm --detail --scan --verbose > /etc/mdadm.conf
      
    • Setup mdadm to monitor the array and send an email if anything fails. I add the following line to my /etc/rc.local file:
      /sbin/mdadm --monitor -t -f -d 3600 -y --scan -m lane@brooks.nu
      

      The -t option causes a test message to be sent when the command is first run. This lets you verify the notification path. The -f puts the process in the background. -d 3600 puts the polling rate at once every hour. -y causes events to get logged to the syslog.

      You will get a DegradedArray array when you first setup the raid and it is doing the initial build of the array (which can take some time if you have big disks). This is to be expected as the array is not finished building.

    • Done. Now format the /dev/md0 and start using it. You can check /proc/mdstat at any time to see the state of your devices. It will tell if one has failed.

    Elan USBscope50 on Fedora 8

    Tuesday, June 3rd, 2008 by lane

    I have wanted a USB scope for quite some time now, and even considered designing my own. Well the other day I set out to find one with linux support and found one made by Elan Digital Systems. While $400 is way too expensive for such a device, it is much cheaper than a stand alone option, so I decided to try it out. It is a bit strange that it does not come with a probe, so I ordered a probe separately from Digikey. I need two channel support, but appearantly the Linux software does not yet support multiple channels, so I just bought one channel for now to evaluate it.

    The installation procedure that I used is below. Overall the installation process was fine. They do not provide udev rules and say to run the program as root. This is bad. Follow my rules to avoid this. The java application is listed as Beta, and it is missing quite a bit of functionality. So much so that I booted my laptop into windows to try their windows version. It is a lot more complete and usabe.

    Installation Instructions

    Fedora 8 kernel has the Elan device support, so it is not necessary to recompile the kernel. I plugged it in and the red LED came on without any changes.

    • First setup the udev rules so that you do not need to be root to access the Elan device. The following udev rules placed in a file called /etc/udev/rules.d/60-elan.rules directory worked for me
      # give all ttyUSB devices rw permission to all
      KERNEL=="ttyUSB*", MODE="0666"
      

      Run udevcontrol reload_rules as root after adding the rules.

    • Now plug the elan device in, run lsusb (part of the usbutils package) and see the addition of the Elan scope with this line:

      Bus 002 Device 002: ID 10c4:f001 Cygnal Integrated Products, Inc.
    • Look to ensure that /proc/bus/usb/devices contains the following listing:
      T:  Bus=02 Lev=01 Prnt=01 Port=07 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
      D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
      P:  Vendor=10c4 ProdID=f001 Rev= 1.06
      S:  Manufacturer=Silicon Labs
      S:  Product=USBscope50
      S:  SerialNumber=K58159-002
      C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=200mA
      I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=cp2101
      E:  Ad=81(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
      E:  Ad=01(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
      
    • And look at /var/log/messages for a similar message:

      May 29 10:42:18 XXXX kernel: usb 2-8: new full speed USB device using ohci_hcd and address 2
      May 29 10:42:18 XXXX kernel: usb 2-8: configuration #1 chosen from 1 choice
      May 29 10:42:18 XXXX kernel: cp2101 2-8:1.0: cp2101 converter detected
      May 29 10:42:18 XXXX kernel: usb 2-8: reset full speed USB device using ohci_hcd and address 2
      May 29 10:42:18 XXXX kernel: usb 2-8: cp2101 converter now attached to ttyUSB0
      
    • Check the permissions of the device using ls -al /dev/ttyUSB0. This will verify that your udev rules are working.
      crw-rw-rw- 1 root uucp 188, 0 2008-05-29 11:03 /dev/ttyUSB0
      
    • Now install the Elan software. I ran the following commands to download and install
      wget http://www.elandigitalsystems.co.uk/support/usbtmfaq/usbscope50/usbscope50_java_beta_linux_setup.zip
      mkdir usbscope50
      cd usbscope50
      unzip ../usbscope50_java_beta_linux_setup.zip
      sudo cp USBscope50Drvr.so /usr/lib
      
    • Try running the software (while in the same directory)
      java -jar USBscope50_Software.jar
      
    • On a 32 bit machine, I initially got this error:
      Exception in thread "main" java.lang.NoClassDefFoundError: de.javasoft.plaf.synthetica.SyntheticaLookAndFeel
         at java.lang.Class.initializeClass(libgcj.so.8rh)
         at java.lang.Class.initializeClass(libgcj.so.8rh)
         at usbscope50software.USBFamily_Main.main(USBFamily_Main.java:304)
      Caused by: java.lang.ClassNotFoundException: sun.swing.DefaultLookup not found in gnu.gcj.runtime.SystemClassLoader{urls=[file:USBscope50_Software.jar], parent=gnu.gcj.runtime.ExtensionClassLoader{urls=[], parent=null}}
         at java.net.URLClassLoader.findClass(libgcj.so.8rh)
         at gnu.gcj.runtime.SystemClassLoader.findClass(libgcj.so.8rh)
         at java.lang.ClassLoader.loadClass(libgcj.so.8rh)
         at java.lang.ClassLoader.loadClass(libgcj.so.8rh)
         at java.lang.Class.initializeClass(libgcj.so.8rh)
         ...2 more
      

      So I installed the icedtea version of java with the following command:

      yum install java-1.7.0-icedtea

      Then the application at least launched, but the signal was a constant flat line zero. So I installed Sun’s JRE, and then things started working.

    • On a 64 bit machine I got this error:
      Exception in thread "main" java.lang.UnsatisfiedLinkError: /usr/lib/USBscope50Drvr.so: /usr/lib/USBscope50Drvr.so: wrong ELF class: ELFCLASS32 (Possible cause: architecture word width mismatch)
              at java.lang.ClassLoader$NativeLibrary.load(Native Method)
              at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1769)
              at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1665)
              at java.lang.Runtime.load0(Runtime.java:788)
              at java.lang.System.load(System.java:1042)
              at usbscope50software.LoadDataArray.(LoadDataArray.java:600)
              at usbscope50software.USBscope50_Main.(USBscope50_Main.java:145)
              at usbscope50software.USBFamily_Main.(USBFamily_Main.java:108)
              at usbscope50software.USBFamily_Main.main(USBFamily_Main.java:310)
      

      It seems Elan needs a 64 bit release of their shared library.

    linux gpib on Fedora 5 with swig’d python bindings - National Instraments USB HS card

    Sunday, April 6th, 2008 by lane
    • Download linux-gpib version 3.2.10 from http://linux-gpib.sourceforge.net
    • Build the linux-gpib software
      ./configure --disable-guile-binding --disable-perl-binding --disable-php-binding  --disable-python-binding --disable-tcl-binding --prefix=/usr
      make
      sudo make install
    • Created a file /etc/udev/rules.d/60-gpib.rules with the following contents
      BUS=="usb", SYSFS{idVendor}=="3923", MODE="0666", RUN+="/usr/sbin/gpib_config"
      KERNEL="gpib[0-9]*", MODE="0666"

      I found that the kernel was oops’ing with these udev lines, so I commented out the first line that runs gpib_config and then manually run gpib_config. My guess is that the device needs some time to come on-line and that a delay is necessary. I am not sure how to force udev to wait though.

    • Reload the udev rules
      sudo udevcontrol reload_rules
    • Create /etc/gpib.conf as follows:
      interface {
      	minor = 0
      	board_type = "ni_usb_b"
      	name = "usb"
      	pad = 0
      	sad = 0
      	timeout = T3s
      	master = yes
      }
    • From the manual

      Unlike the USB-B, the USB-HS does not require a firmware upload to become functional after being
      plugged in. The linux-gpib tarball contains hotplug scripts which will automatically run gpib_config
      after the device is plugged in.

    • Unpack this tar file in the languages subdirectory swig’d linux gpib.
    • cd into the py_swig directory. run make and make install
    • Now you can import gpib in python
    • Here is some examples of how to use it
      import gpib
      
      class hp34401A:
          def __init__(self, addr, minor=0, timeout=11):
              self.ud = gpib.ibdev(minor, addr, 0, timeout, 1, 0)
              if(self.ud < 0):
                  raise RuntimeError("Error creating hp8656B")
      
          def meas(self):
              gpib.ibWrt(self.ud, "RST*");
              gpib.ibWrt(self.ud, "MEAS:VOLT:DC?");
              status, data = gpib.ibRd(self.ud);
              if(gpib.ThreadIberr()):
                  raise Exception("Read error: status = 0x%x" % status)
              else:
                  print data[:gpib.ThreadIbcnt()]
                  return float(data[:gpib.ThreadIbcnt()])
      
      class hp8656B:
          def __init__(self, addr, minor=0, timeout=11):
              self.ud = gpib.ibdev(minor, addr, 0, timeout, 1, 0)
              if(self.ud < 0):
                  raise RuntimeError("Error creating hp8656B")
      
          def setFreq(self, freq):
      
              # 9 digits max
              gpib.ibWrt(self.ud, "FR"+str(freq)+"MZ")
      
          def setAmpl(self, ampl):
              # 9 digits max
              gpib.ibWrt(self.ud, "AP"+str(ampl)+"VL")
      
      class hp8644B:
          def __init__(self, addr, minor=0, timeout=11):
              self.ud = gpib.ibdev(minor, addr, 0, timeout, 1, 0)
              if(self.ud < 0):
                  raise RuntimeError("Error creating hp8656B")
      
          def setFreq(self, freq):
      
              # 9 digits max
              gpib.ibWrt(self.ud, "FR"+str(freq)+"MZ")
      
          def setAmpl(self, ampl):
              # 9 digits max
              gpib.ibWrt(self.ud, "AP"+str(ampl)+"VL")
      
      if __name__ == "__main__":
      
          hp = hp34401A(12)