azonenberg changed the topic of #scopehal to: ngscopeclient, libscopehal, and libscopeprotocols development and testing | https://github.com/ngscopeclient/scopehal-apps | Logs: https://libera.irclog.whitequark.org/scopehal
nelgau has quit [Read error: Connection reset by peer]
nelgau has joined #scopehal
Degi has quit [Ping timeout: 268 seconds]
Degi has joined #scopehal
<_whitenotifier> [scopehal] codepox commented on issue #838: Tektronix MSO64 Connect Error - https://github.com/ngscopeclient/scopehal/issues/838#issuecomment-1874968809
<_whitenotifier-3> [scopehal] codepox commented on issue #838: Tektronix MSO64 Connect Error - https://github.com/ngscopeclient/scopehal/issues/838#issuecomment-1874972814
bvernoux has joined #scopehal
<d1b2> <azonenberg> @vegard_e so there's two ways you can get a driver loaded by ngscopeclient
<d1b2> <azonenberg> the first is to build it into libscopehal itself, which is what we generally recommend people do if it's a driver for something commercially available or open source (i.e. lots of people will probably want to use it)
<d1b2> <azonenberg> If this is bespoke in house tooling that is not intended to be released or not useful outside your project, then you probably will want to make it a plugin
<d1b2> <azonenberg> (We've supported plugins for a long time but for the v0.x series there's no API/ABI stability so you need to recompile plugins if you update to a new libscopehal version)
<d1b2> <azonenberg> the driver code is the same either way
<d1b2> <azonenberg> just a question of how you package it up
<d1b2> <azonenberg> https://github.com/ngscopeclient/scopehal/blob/master/scopehal/scopehal.cpp#L197 here's an example of how you'd register a new driver class in libscopehal
<d1b2> <vegard_e> I and @mubes have talked about adding LA capability to orbtrace, and while what I'm thinking about now is for a different project, they'll probably share at least some of the code, and the former absolutely makes sense to upstream
<d1b2> <azonenberg> So in that case you probably will want to work on a fork of scopehal rather than a plugin. but there's no real difference and you can do either, or move back and forth
<d1b2> <azonenberg> i actually have a private plugin library that i use for development of things like drivers for unreleased hardware that we got early access to
<d1b2> <azonenberg> e.g. the scopehal driver for the new PicoVNA software was developed in secret as a plugin in a private repo for a good 6+ months before the public announcement of the software on Pico's side
<d1b2> <azonenberg> then upstreamed it once the software launched
<d1b2> <azonenberg> anyway, basically you'd just create a new class derived from SCPIOscilloscope, implement all of the pure virtuals and any other overrides that make sense, and add that one line to register the driver
<d1b2> <vegard_e> even if there's no SCPI involved?
<d1b2> <azonenberg> So there is a base Oscilloscope class and some parts of the API do allow you to work directly with it
<d1b2> <azonenberg> but the SCPITransport layer in the GUI is a lot happier if you derive from SCPIOscilloscope. There's one argument you have to pass to the constructor to make it not send a *IDN? during startup
<d1b2> <vegard_e> yeah, I see SCPIOscilloscope mostly just inherits Oscilloscope and SCPIInstrument
<d1b2> <azonenberg> From there on you can just have a raw socket pipe that you can run any protocol you want over
<d1b2> <vegard_e> right
<d1b2> <azonenberg> Cleaning up the code to make non-scpi instruments easier to do is on the distant wishlist but for now it's easier to just pretend they're scpi :p
<d1b2> <vegard_e> and the transport layer already supports both USB pipes and various sockets?
<d1b2> <azonenberg> The SCPITransport layer currently supports LXI VXI-11, LeCroy VICP, raw TCP sockets with no framing, dual sockets with one used for control plane (SendCommand() / ReadReply()) and the other used for binary waveform acquisition (ReadRawData() etc)
<d1b2> <azonenberg> RS232, GPIB (linux only i think), USBTMC (linux only)
<d1b2> <azonenberg> new transports can be freely defined and registered just like with drivers, even added as plugins
<d1b2> <vegard_e> hmm, I'm on macos, and I think I'd like to use either raw USB bulk or UDP
<d1b2> <azonenberg> it just needs to take a string describing the path to whatever you want to talk to
<d1b2> <azonenberg> you can format that string as you see fit
<d1b2> <azonenberg> as long as it has the same APIs to send/receive commands and raw data you can do whatever backend you want underneath
<d1b2> <azonenberg> Thats the whole point of the transport layer, abstracting away all the details
<d1b2> <vegard_e> maybe it'd make sense to make a separate bridge to handle it and run the dual socket transport against it? AIUI some of the drivers work that way
<d1b2> <azonenberg> That is another way to do it.
<d1b2> <azonenberg> To date we've mostly done bridges when working with binary blob SDKs especially for USB attached instruments
<d1b2> <azonenberg> it provides network transparency and a license boundary and allows the scopehal core to not depend on the blob
<d1b2> <azonenberg> while allowing you to install bridges as your situation dictates
<d1b2> <azonenberg> basically we don't want you to have to install digilent and pico and multilane and dreamsourcelab and... SDKs just to build scopehal
<d1b2> <azonenberg> or have a proliferation of 30 different incompatible scopehal versions in different distros each supporting a different subset of instruments
<d1b2> <azonenberg> This approach lets us have a single, permissively licensed, common core and then talk to blobs as needed
<d1b2> <azonenberg> Nothing stops you from making a bridge server for a non-blob instrument of course, but that's typically where we've used them to date
<d1b2> <vegard_e> the orbtrace stuff would probably use a raw TCP socket to the orbuculum demux, maybe it makes sense to just tie into that infrastructure for this project as well
<d1b2> <azonenberg> Yeah if it's a raw TCP socket just use SCPISocketTransport and then pass the flag to SCPIInstrument::SCPIInstrument() to say don't *IDN?
<d1b2> <azonenberg> Or SCPITwinLanTransport depending on if you want data and control plane on the same socket or not
<d1b2> <azonenberg> Separating can improve e.g. UI responsiveness by letting you send a query and get a reply even if you're in the middle of downloading a large waveform on the other socket
<d1b2> <azonenberg> And also allows a push based rather than polling based workflow
<d1b2> <azonenberg> the scope can send you a waveform when it triggered even if you haven't asked for it
<d1b2> <azonenberg> this greatly reduces round trips and improves performance enormously over high latency links like VPNs
<d1b2> <azonenberg> I did a demo a year or two back for LeCroy where I was at their corporate HQ in NY, VPN'd into my lab outside Seattle
<d1b2> <azonenberg> the LeCroy scope that happily did 60+ Hz update rates over LAN was getting single digit WFM/s
<d1b2> <azonenberg> while the picoscope sustained 60 WFM/s limited by refresh rate of my laptop :p
<d1b2> <azonenberg> Because the lecroy had to arm the trigger, ask if data was ready repeatedly until it said "yes", download the data, then re-arm the trigger
<d1b2> <azonenberg> with a 100+ ms turnaround time between each of those steps
<d1b2> <azonenberg> the picoscope could just firehose data as fast as the internet could keep up
<d1b2> <azonenberg> over LAN the benefits are less significant but remoting is a key use case for scopehal so we try to design around it
<d1b2> <vegard_e> speaking of speed, I've got a rigol mso5k and given how low the update rate is, I didn't find using ngscopeclient with it to be very pleasant from the little testing I've done so far; is there a way to let me operate the scope manually directly instead and only trigger a download once I've got an interesting waveform I'd like to analyse?
<d1b2> <azonenberg> So: not yet, but you're also not the first to ask
<d1b2> <azonenberg> I don't think it would be that hard to do
<d1b2> <vegard_e> adding a way to manually trigging a download is probably not hard, but I suspect it'd also need a way to disable it taking control of the scope and polling for a trigger while you're working it manually
<d1b2> <vegard_e> I guess you could disconnect from the scope, but that doesn't sound like a good workflow
<d1b2> <vegard_e> or I guess a solution could be for the download button to connect to the scope, trigger a download and then disconnect again
<d1b2> <azonenberg> So it only polls for a trigger while scopehal thinks the trigger is armed
<d1b2> <azonenberg> In the download mode scopehal would always see the trigger as stopped
<d1b2> <vegard_e> right
<d1b2> <azonenberg> It would send a stop command anyway (just in case the trigger was armed, so as to avoid race conditions where it got one channel from one trigger and another channel from a later trigger)
<d1b2> <azonenberg> then call AcquireData()
<d1b2> <azonenberg> There would be a bit of work needed to do it right around all of the thread synchronization and such but it's absolutely possible to do. Just a quesiton of too many github tickets and not enough hours in the day :p
<d1b2> <azonenberg> For the lead-up to v0.1 i'm really trying to get the existing feature set solidly documented, stable and reliable build directions and packaging for all supported OSse
<d1b2> <azonenberg> fix known crash or functionality bugs
<d1b2> <vegard_e> I don't even get how you find time for everything that you do do, so I'm certainly not going to complain about what you don't find time to do
<d1b2> <azonenberg> So new feature dev isnt my top priority
<d1b2> <azonenberg> Lol
miek has quit [Ping timeout: 255 seconds]
miek has joined #scopehal
bvernoux has quit [Quit: Leaving]