Python Instrument with latest opentap 9.29

I am attempting to update from OpenTap 9.23.1 to 9.29.1.

The main motivation is to be able to use the new cross platform Editor for Linux.

I installed opentap 9.29.1 on Ubuntu 20.04.

If I install my existing plugins I previously built using net6.0 / opentap 9.23, everything works fine.

If I rebuild my plugins using net9.0 and opentap 9.29 sdk, everything works fine except the one python instrument plugin.

Below is the interface for the instrument in my ‘M9000’ plugin

namespace Jtag
{
    // Interface to JtagInstrument implemented in python.  Python is used for the 
    // instrument because the JTAG library urjtag has an existing python binding
    public interface IJtagInstrument : IInstrument
    {
        void detect(bool force=true);
        void reset();
        void part(int part);
        void svf(string path, int stop, long freq);
        void flashmem(int addr, string path);
        void instruction(string instr);
        void shift_dr();
        string get_dr_in();
        void set_dr_in(string bits);
        void set_signal(int part, string name, int dir, int value);
        int  get_signal(int part, string name);
        int len();
    }
}

And the implementation of the python Instrument

import opentap
from opentap import *
from System import String, Int32, Enum, Boolean
import OpenTap
from OpenTap import Log, DisplayAttribute, Display, FilePathAttribute, FilePath

import urjtag
import clr
clr.AddReference("M9000")
from Jtag import IJtagInstrument # JtagInstrument c# interface we implement


@attribute(OpenTap.Display("JTAG Interface", "JTAG Interface adapter instrument.", "M9000 FCT"))
class JtagInstrument(Instrument, IJtagInstrument):
    Cable = property(String, "m9000-fct")\
        .add_attribute(OpenTap.Display("Cable", "Name of the cable driver"))

    def __init__(self):
        super(JtagInstrument, self).__init__()
        self.Name = "JtagInstrument"
        self.jtag = None
        self._inited=False
         
    def Open(self):
        self.detected = False
        self.jtag = urjtag.chain()
        self.jtag.cable(self.Cable)
        self.reset()

    def Close(self):
        self.jtag.disconnect()
    
    def detect(self, force=True):
        # detect can't be called as part of the instrument open sequence since
        # the DUT is not available at that time.  We track if detection has 
        # happened and allow it to be cached if force is overridden
        if (force or not self.detected):
            self.jtag.tap_detect()
            self.detected = True
    
    def reset(self):
        self.jtag.reset()

    def part(self, part):
        self.jtag.part(part)

    def svf(self, svf, stop, freq):
        self.jtag.run_svf(svf, stop, freq);
    
    def flashmem(self, addr, image):
        self.jtag.detectflash(0)
        self.jtag.flashmem(str(addr), image, 1)

    def instruction(self, inst):
        self.jtag.set_instruction(inst)
        self.jtag.shift_ir()
        self._instruction = inst
    
    def shift_dr(self):
        self.jtag.shift_dr()
    
    def get_dr_in(self):
        return self.jtag.get_dr_in_string();

    def set_dr_in(self, bits):
        self.jtag.set_dr_in(bits);
    
    def set_signal(self, part, sig, out, val):
        self.jtag.set_signal(part, sig, out, val)
    
    def get_signal(self, part, sig):
        return self.jtag.get_signal(part, sig)
    
    def len(self):
        return self.jtag.len()

Again, this works if I build my M9000 plugin using net6.0 and opentap 9.23 sdk, but if I build with net9.0 and opentap 9.29 sdk, I have a python error when the JtagInstrument is installed.

Caught exception loading M9000.JtagInstrument: No module named 'Jtag'

The Python plugin version is 3.1.

The version of python on Ubuntu 20.04 is Python 3.8.10

I’m not very familiar with python dotnet and what things would cause the assembly to load but still fail to find the module.

Both python and opentap are 64bit.

Since the clr.AddReference succeeds, I am assuming this isn’t any kind of python path problem?

Are there requirements on the version of Python / Python plugin that go along with updating to net9.0?

Thanks,

Wittrock

Hi @wittrock,

Thanks for raising the issue.

Since you were already on .net6, its a bit surprising if moving to .net9 would give any issues.

Did you try having a separate OpenTAP installation in another folder and just move your plugin over?

For example, what happens if you copy the opentap 9.23 based build. And then in that folder do tap package install OpenTAP --version 9.29?

  • If that has the same issue. What about updating to 9.28?

Thanks @rolf_madsen ,

Yes, as mentioned, if I just use my existing plugin built against opentap 9.23 sdk / .net6.0, then everything works with opentap 9.29 including the python based instrument.

Likewise, If I just update to 9.29 in place on my existing 9.23 installation folder (and install .net9.0), everything works.

I am only running into a problem if I re-build my plugin using opentap 9.29 sdk / .net9.0. If I do this, everything works except the python instrument. In this case, when the instrument is loaded, it can’t see the ‘Jtag’ ( or other) namespace in my M9000 plugin. From what I can tell, the assembly is found and loaded. For some reason, it just can’t see the instrument interface.

I could just continue to use 9.23/net6 to build my plugins, but I am trying to use a common environment for development and production so trying to find the root problem.

Thanks,

Wittrock

Has anyone else run into problems with using opentap 9.29 / net9 and python?

I still have the same issues. Everything works fine if I build the plugins with 9.23 / net6 then use those plugins with 9.29. I just can’t seem to use the plugins build against 9.29 / net9

Hi @wittrock, which version are you using?

I’d suggest you to try the newest Python plugin RC, there will be a 3.2 release in the not too distant future.

Finally getting back to this.

I have updated to Python plugin 3.2 and opentap 9.30.0 using net9.

Unfortunately, I still see the same problem.

The odd thing is, If I copy my plugin DLL from the build directory to the plugin installation directory, then it works.

In other words, relative to the root of my plugin project directory, if I copy /bin/Debug/M9000.dll to the installation directory (/opt/opentap/Packages/M9000/M9000.dll, then it works.

Likewise, If I copy from /bin/Debug/Packages/M9000/M9000.dll to the installation directory, then it works.

It is the M9000.dll that ends up in the bin/Debug/M9000.x.x.x.TapPackage that has the problem.

I have removed the bin directory and performed a clean build a number of times and the packaged dll is always smaller, so I assume this is some artifact of the packaging.

I would need to look into the packaging process as I am not familiar with it, but how is the assembly modified when it is placed into the .TapPackage?

I should also note that currently, I am building the package by setting the following in the .csproj

<PropertyGroup>
	<OpenTapPackageDefinitionPath>package.xml</OpenTapPackageDefinitionPath>
	<CreateOpenTapPackage>true</CreateOpenTapPackage>
	<OutputType>Library</OutputType>
</PropertyGroup>

But I have also manually built the package using ‘tap package create package.xml’ as well with the same results.

Also, I see the same for a release build.

If I simply unzip the .TapPackage, replace the M9000.dll with the one built, then re-compress, it installs fine and everything works.

Thanks,

wittrock

I guess the question I should ask is :

Should the package .dll be modified in any way by the create package process?

I’m trying to figure out what it might do that would affect the ability of Python to import the assembly.

As a test i did the following:

  1. Build the plugin using opentap 9.30 / net9.0 as I have been
  2. Manually create the package using ‘tap package create’ but use tap 9.23 (my previously used version) to do the packaging.
  3. Installed using opentap 9.30.
  4. Everything works OK

So it certainly does look like something the packaging process is doing with the later opentap version.

Thanks,

wittrock

Something does happen during packaging, but it should not affect this.

Does your package XML file use the <SetAssemblyInfo Attributes="Version"/> element?

Hello @rolf_madsen ,

Yes, below is the package.xml I am using:

<Package Name="M9000" xmlns="http://opentap.io/schemas/package" InfoLink="" Version="2.2.11" OS="Linux" Architecture="AnyCPU">
  <Description>M9000 Test Plugins
    <Prerequisites> Python (>3.7) </Prerequisites>
  </Description>
  <Dependencies>
    <PackageDependency Package="OpenTAP" Version="^9.29" />
    <PackageDependency Package="Python" Version="^3.2" />
  </Dependencies>
	<Files>
    <File Path="Packages/M9000/M9000.dll" SourcePath="M9000.dll">
        <SetAssemblyInfo Attributes="Version"/>
    </File>
    <File Path="Packages/M9000/*.py">
        <ProjectFile/> 
    </File>
  </Files>
</Package>

I removed the <SetAssemblyInfo Attributes="Version"/> line from the project.xml and rebuild the package.

After doing this, my package installs and works without error.

I know that doesn’t solve what is causing the issue but does help me work around what is going on for the time being. I’m just wondering what I could be doing to hit the issue. I’ll try to make a minimum python instrument plugin to see if it is something unique to just my project.

I very much appreciate your help.

Thanks,

wittrock

Ok, that is a strong indication that something goes wrong when setting the assembly version in this specific instance.

If you need to set this, you could also fall back to using csproj for setting the version.

for example:

    <PropertyGroup Condition="'$(GitVersion)' != ''">
        <GenerateAssemblyInfo>true</GenerateAssemblyInfo>
        <Version>$(ShortVersion)</Version>
        <AssemblyVersion>$(ShortVersion)</AssemblyVersion>
        <InformationalVersion>$(GitVersion)</InformationalVersion>
        <FileVersion>$(ShortVersion).0</FileVersion> 
    </PropertyGroup>

In this case, those are environment variables set by the build pipeline via tap sdk gitversion.