Python Logic Analyzer Entry: Basic tools Date: Thu Feb 27 23:34:00 CET 2014 - pyside + opengl - inner loop in c++ - swig for python interface - cmake for windows/linux/OSX compilation Entry: Basic idea Date: Thu Feb 27 23:40:39 CET 2014 - fast video update "scope like" - point & shoot triggering - data logger window (serial, spi, i2c) Entry: GNU Radio Date: Fri Feb 28 11:54:51 CET 2014 If this is going to be DAG of byte stream processors, it might be good to not make it too incompatible to gnu radio processors. Entry: Saleae Logic callbacks Date: Fri Feb 28 13:40:08 CET 2014 SL API uses a callback. This is a little inconvenient as it requires calling python from C++, or needs multiple threads with a buffer to decouple the source and sink. Let's go for the buffered approach. This can then be memory backed or file backed. Entry: Calling python from C++ with swig Date: Fri Feb 28 16:47:22 CET 2014 Reason: cross-platform windows / pthread multi-threading without including boost on the C++ side. Saleae uses multithreaded callbacks. Pff... it's probably easier to use boost. http://stackoverflow.com/questions/12392703/what-is-the-cleanest-way-to-call-a-python-function-from-c-with-a-swig-wrapped Entry: Use Boost.Python instead of SWIG? Date: Fri Feb 28 16:55:28 CET 2014 https://dev.lsstcorp.org/trac/wiki/SwigVsBoostPython Entry: Push architecutre? Date: Fri Feb 28 18:19:39 CET 2014 It's going to feel much more natural from the device APIs to use a push architecture. Allow the data source to push data into a processor network, and use mutexed polling on the result. Or does it really not matter? From the language side (functions), pull is more natural. Let's continue with pull, and remove the read_sync() method. Convention is that each read will poll its chain. EDIT: Sort of works, but buffer management is going to be interesting... Entry: Memory management Date: Fri Feb 28 21:42:14 CET 2014 Some ideas: - combination of push/pull would be nice: - push allows the large data reduction to happen strictly, so buffers do not grow too large - pull is easier to code - a linear processing chain can be buffered at an arbitrary place in the chain. - a dag can be transformed into a a chain if ordering is allowed - "fanout" is useful (i.e. obsering a multiple uarts / spi on a single bus). what about "merge" after "fanout"? Entry: use the Forth Date: Fri Feb 28 22:44:26 CET 2014 (aka Packet Forth) To express DAGs and solve memory management, it seems simplest to convert everythin to RPN. This exposes refcounting (dup / drop / ...). This also allows driving the whole computation from the data gatherer. The results after one run can then simply be copied into high level data structures. Approach? - Rewrite all processors to use pointers or references. - Or have them operate on a stack directly - For refcounting: use boost::shared_ptr - Expose the stack as a stack of iterators? Inner loop should be fast. - Allow the same code to run on a uC with static memory Entry: Remodel the co-sink Date: Sat Mar 1 01:08:41 CET 2014 - Construct a sink object. - Plug it into the SL callback, which is an cosink (an object parameterized by a sink). An cosink is not a source, as it has the wrong caller/callee polarity. A sink has a read() method, while an cosink calls a write() method. Entry: Notes Date: Sat Mar 1 23:33:10 CET 2014 http://downloads.saleae.com/SDK/Saleae%20Device%20SDK.pdf http://downloads.saleae.com/SDK/SaleaeDeviceSdk-1.1.14.zip Entry: Mipmap Date: Sun Mar 2 19:38:59 CET 2014 For waveform display, we need a "mipmap". An interval mipmap would be best. Per channel, there are only 3 values: low/high/both However it seems best to just use 2 bits to encode this to keep things simple. EDIT: 4th case = empty, since we round up to next 2^n The mipmap is bounded, as size divides by two per level. Encoding. What about storing multiple channels in one machine word to make addressing simpler? Let's stick to 32 bit words, giving 16 channels of 2 bits. This is good as it makes computing the mipmap very simple: logic OR. Maybe this is fast enought to just rebuild everything on the fly? With a memory-mapped store it might be doable. This would keep the representation simple as well. Then, instead of using multiple channels, chop a channel up into multiple parts. There is also an interesting pattern in the address bits: 0..... 10.... 110... 1110.. 11110. If the storage mapping is fixed (fixed maximum size), incremental updates are simple: round range to fit in between max/min power of two and recompute. Is a fixed buffer size a problem? Memory mapping should make access quite fast. Entry: syncser Date: Mon Mar 3 10:52:23 CET 2014 Problem.. Make a test case using data captured from dsPIC. Entry: mipmapping Date: Mon Mar 3 20:07:48 CET 2014 What problem am I solving? Waveform display while capturing. So incremental update is important. Data representation is naturally incremental / idempotent. To use circular buffers, the idempotent part is no longer satisfied, so a chunk needs to be zeroed out. This is possible by not expanding all levels to the very end, i.e. keep say 1000 samples at the coarsest level = +- nb pixels in a window = maximal zoom out. Does it make sense to work with data sets the size of a harddrive, say terabytes? That's in the order of 1M seconds, which is in the order of two weeks. I guess. The mip-mapped data structure is a direct representation of what a user sees. Access should be instantaneous for all zoom levels, meaning per zoom level. Entry: Forth as a python DSL? Date: Thu Mar 6 00:14:14 CET 2014 Mayb it fits in the dot chaining notation? dup.process(uart, config).swap.process(syncser, config2) 1 -> 2 buffers Entry: new Date: Thu Mar 6 01:01:01 CET 2014 So the problem is that objects that are constructed from python tend to be destructed from python. Maybe best to manage construction as tied to the cosink? Basically I like the idea of memory management as it's done in lua: don't expose any pointers! So all evil is essentially created by: - storing a pointer in a cosink object - composing sinks What about adding static methods to the cosink object to connect stuff? The objects could be left accessible from python to keep things flexible, but in order to connect anything to the cosink, they need to be created locally. Is there a way to pass in a constructor? Entry: Compose kills it Date: Thu Mar 6 01:15:33 CET 2014 I still want managed pointers. The reason is that I'd like to keep object construction in Python. Otherwise it's going to be a mess.. So the only real option then is boost? Entry: kicking out the saleae lib? Date: Fri Mar 7 19:44:32 CET 2014 It should be straightforward to work with libusb directly. Entry: rpn dataflow Date: Sat Mar 8 15:59:17 CET 2014 Seems to work. Next: how to actually make this useful with 2 output streams on the console? Entry: multilog Date: Sat Mar 8 19:29:27 CET 2014 The gui should really just be a multilog. 1. Set up a notational shorthand for a polling multi-out rpn program. 2. Display results in pylag Entry: Sharing incoming buffer Date: Sun Mar 9 12:00:00 CET 2014 One last thing to do: don't copy the memory buffer coming in from the Saleae. How to make a vector wrapper that uses the underlying memory? Entry: Rust? Date: Thu Mar 20 13:17:46 CET 2014 Is it possible to express the state machine <-> task transformation as a function composition in Rust. In Haskell? Likely this transformation is a 1-way projection, not a projection followed by injection. Entry: Fast update gui Date: Sun Apr 20 11:58:24 EDT 2014 Roadmap: - Get a OpenGL view to work in pyside - Call C/C++ code to draw OpenGL primitives - Implement circular buffer recording + mipmap - Enable triggers on mipmap - Implement autoscaling Elements: - Circular buffer: memory, optionally backed with a file (mmap). Entry: Sigrok Date: Sun Apr 20 12:58:48 EDT 2014 How to share code? First, use it as a streaming backend + enable open FX2 firmware. Entry: Multiscale / multichannel roll mode Date: Mon Apr 28 22:03:54 EDT 2014 ! Entry: 24MHz Date: Fri May 2 21:13:25 EDT 2014 works on tx: [master] tom@tx:~/pyla$ lsusb -t 1-1.6:1.2: No such file or directory 1-1.6:1.3: No such file or directory 4-1.2:1.0: No such file or directory /: Bus 04.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/2p, 480M |__ Port 1: Dev 2, If 0, Class=hub, Driver=hub/6p, 480M |__ Port 2: Dev 7, If 0, Class=vend., Driver=, 480M /: Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/2p, 5000M /: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/2p, 480M /: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/2p, 480M |__ Port 1: Dev 2, If 0, Class=hub, Driver=hub/6p, 480M |__ Port 3: Dev 3, If 0, Class='bInterfaceClass 0x0e not yet handled', Driver=uvcvideo, 480M |__ Port 3: Dev 3, If 1, Class='bInterfaceClass 0x0e not yet handled', Driver=uvcvideo, 480M |__ Port 6: Dev 54, If 0, Class='bInterfaceClass 0xe0 not yet handled', Driver=btusb, 12M |__ Port 6: Dev 54, If 1, Class='bInterfaceClass 0xe0 not yet handled', Driver=btusb, 12M |__ Port 6: Dev 54, If 2, Class=vend., Driver=, 12M |__ Port 6: Dev 54, If 3, Class=app., Driver=, 12M Entry: sigrok Date: Sat Aug 9 13:07:35 EDT 2014 Unfortunately pyla was already +- done when I heard of sigrok[1]. I'd like to find a way to integrate. The simplest way would probably to integrate into libsigrokdecode[2] from two ways: export pyla C++ as a decoder and use the lsd decoders in pyla style python scripts. Former is probably most useful. Second part is to use the libsigrok drivers as frontend to the pyla C++ decoders. Problem is time. What I'm looking at is mostly direction: how to aim at integration instead of reinventing the wheel. Roadmap: - get sigrok to work with the custom FX2 firmware fx2lafw[3]. - connect libsigrok driver to pylacore ./sigrok-cli -d fx2lafw -c samplerate=1m -C 0,1,2,3,4,5,6,7 --time 100 Next: how to get at the datafeed? OK, got it. Trouble: sigrok git is incompatible with 0.3.0 I wonder if maybe it is simpler to forget about sigrok and just go for libusb directly? [1] http://sigrok.org [2] http://sigrok.org/wiki/Libsigrokdecode [3] http://sigrok.org/wiki/Fx2lafw Entry: Rust Date: Mon Sep 15 01:15:32 CEST 2014 Time to get some of the core written in Rust. Entry: C++ / boost / swig / cmake Date: Fri Jan 30 11:57:28 EST 2015 So this is written in C++ / swig / cmake as those were the tools I was using for work in early 2014. At that time it seemed like a good idea to regain some C++ knowledge and dig into boost and swig a bit more. I no longer think this is the best approach, however I'm glad to have refreshed C++ and thought about the design of an event-driven analyzer core. Currently I'm more interested in (re)writing (parts) in rust. Next thing I need is a graphics display with fast waveform update. The plan is to write it standalone in rust first. EDIT: moved rust code to git/rust. Starting over as a pure Rust library without core C++ / cmake / python dependencies. Entry: Produce GTKwave VCD files Date: Sun Feb 14 13:58:09 EST 2016 I'd like to tie this into MyHDL.