DancingQuanta / pyusbiss

Python API for USB-ISS Multifunction USB Communications Module
MIT License
2 stars 3 forks source link

Feasibility of a class for each USBISS mode #3

Closed DancingQuanta closed 6 years ago

DancingQuanta commented 6 years ago

I wanted to start a discussion on how the code for USBISS should be structured. The motivation for this discussion is because some people are starting to develop on top of my library and I wanted to make that easier.

My proposal is to restructure the code so that there will be a base class containing functions that mediates connections to USBISS from the host. Then separate classes for each USBISS mode in its own file which inherits the base class.

I love to know your thoughts on this.

CC: @dhhagan, @vignkri and @gwdehaan

gwdehaan commented 6 years ago

First let me thank you for the great job you did on the library in setup of the initialization and communication for the UBISS module and adding the spi functionality. For a Python beginner like me it has been a great start.

My primary goal is to add I2C functionality to the library, as a kind of POC I started out with the IO possibilities of the module. At this point in time I'm testing the IO capabilities of the module and after that will cleanup the code before I start with I2C. As I mentioned I'm new to Python and as I don't fully understand the setup that you are using to make the library ready for Pypi my code may seem a bit dodgy to you in the current state. I'm still learning :-)

As to your proposal : I imagine the baseclass would contain the intialization and communication methods and the I2C, SPI, IO classes the specifics for these modes.

I think the readability of the code with different classes would increase as there is no more need for an if ... then ... else tree for every mode, but on the user side it would not make a lot of difference when you make an instance of the class, you can only relinquish on specifying the mode.

If I understand your proposal correctly : # Current t=USBISS('COM3', 'spi',spi_mode = 1, freq = 25000)

# Proposal DancingQuanta t=USBISSSPI(('COM3', spi_mode = 1, freq = 25000)

DancingQuanta commented 6 years ago

Welcome!

@gwdehaan, it was great to have you on board! I hope you will find this project simulating and helps you to learn the Python language. i am happy that you are developing on IO and I2C capacity of USBISS which will improve uility of this library and make the case for PYPI publication.

Mission of the project

My idea for this project overall is to have a backend that manages the serial connection to USBISS and the frontend that manages a connection between USBISS and a device. The backend needs to be initialized and set the protocol mode for the frontend before being passed to an application, much like opening a port and passing an instance over to the application. The frontend must be compatible with most popular python library for the protocol in question. For example the SPI mode in the library looks like spidev to an application so that the application do not needs to be modified to accept the port instance. This is done by naming the transceive method xfer for SPI so that the application continues to use the method. This is called duck typing. Also I made sure that a property mode is set so that if an application tries to inspect the instance it will expect the property mode to exist otherwise things get confusing! So in summary, the instance of usbiss must behave like the protocol library it claims to be.

Proposed structure

I am basing my proposal on a code structure used by @dhhagan's py-opc library which I have used in combination with SPI functionality of USBISS in the past. This library uses a base class and two subclasses. The subclasses are public so users can use them.

usbiss base class will have the initialization and communication methods, like you said. Separate class for each of the I2C, SPI, IO modes in their own file. I have created a new branch classes so I can focus on developing the base class and SPI protocal mode. If you like the direction this is going, then I suggest that you focus on developing methods and properties for IO and I2C and make a pull request for each protocol mode against 'classes' branch. The pull repuests will be a great playground where we try to make things work!

User prespective

Current

t = usbiss.USBISS(port, 'spi', spi_mode=1, freq=500000)
print(t.get_iss_info())

Proposal

t = usbiss.SPI(port, mode=1, freq=500000)
print(t.get_iss_info())

Proposed Code base

init.py

class USBISS(object):
# Properties for USBISS's information such as firmware

  def __init__(self, port, **kwargs):
    # Open serial port and get USBISS's firmware version eg

# Other methods for managing serial port (open, close), 
# methods that get firmware
# misc?

spi.py

from . import USBISS

class SPI(USBISS):
# Properties for SPI port and device information
  self.mode = None
  def __init__(self, port, mode=None, freq=None):
    # Execute baseclass __init__
    super(SPI, self).__init__(port)

    # Set SPI mode
    self.iss_mode('spi')
  def xfer(self, word):
  ...

About myself

I do not have any use for this library anymore as I used this a summer project two years ago. But as a hobbyist I see this as something to practise my skills on and so I kept this around in hopes that someone want to help with developing the library.

What are your objectives for using this library?

DancingQuanta commented 6 years ago

I have pushed two commits to classes branch. @dhhagan would you mind testing this out please?

dhhagan commented 6 years ago

@DancingQuanta This all sounds/looks good. I will try and test when I get to the office tomorrow morning.

gwdehaan commented 6 years ago

Project Mission and - Structure

I understand and agree on your projectmission and - structure, and while I'm a little out of my depth as a hobbyist I like the challenge and am convinced that with a little help from you now and then we will get the project done. The only "problem" I see is planning. My daytime job consumes a lot of time and energy and every project should have some sort of planning. In my case however the journey to the endresult is more important then the result itself, hence there is no real planning, only my commitment to the project. If this is a problem to you it would be better to decide on next steps in this phase.

The Result

I'm learning MicroPython and have a few I2C devices lying around. To develop the libraries for them I would first like to create a working pythondriver as a POC using a full flexed development environment based on Win10/ usbiss.I2C() and then squeeze the driver into MicroPython.

Next Steps

(if you can agree on the "planning")

  1. Finish testing of my current IO version, thereby verifying that the current methods/properties that I added to the Original init.py work.
  2. Decide on a donor protocol library for the IO frontend
  3. Developing the IO Frontend based on current methods but with Ducktyped names and parameters from the donor protocol library. Property mode
  4. repeat steps 2 and 3 for the I2C frontend
  5. Decide if a frontend for Serial communications should be part of the project

    Help needed

    As I said earlier I'm a bit out of my depth but I'm sure I will get there as far as the mission goes. While I have covered the basics of GitHub for working on my own, I will need your help for working on the project together. Furthermore I think I will need your assistance on architectural decisions like choosing the right Protocol Libraries for every mode.

DancingQuanta commented 6 years ago

This project is just a hobby and so there is no time goal and therefore no rush! I got a full-time job too.

i am helping my dad with learning micropython for programming pycom boards such as fipy :). What I2C devices are you using? Also the driver for micropython, what device are you installing the driver into?

Comments on your Plan

  1. Great idea
  2. There are a number of implementions. I would go with Raspberry Pi GPIO library. I don't know how the GPIOs work, and may depend on unique hardware of the master. But IO of USBISS is parallel (contiguous pins) so you set a word (a number of bits on a bus which is half of a byte in this case) in a register (memory bits) which is then read out. I have not read your code but I imagine this: You could transmit a word or set a pin individually (through mutating the previously used word to keep other pin status). I used to develop a communication system between a FPGA and C# program during my placement and this use a 8-bit word and lots of timing and clocks, fun times!
  3. The beauty of class-based structure is that you can have a number of different donor class for every sitaution. So you can change something if you learnt a new concept in hardware design (IO is very basic and forms the base of I2C and SPI).
  4. Rinse and repeat for I2C.
  5. This library should have a class for serial.

You can ask for help anytime. I was hoping that I am not making things difficult but i liked my code be flexible! I think it is a good idea to open a separate issue for each protocol so we can work on each more easily.

gwdehaan commented 6 years ago

Thanks for that!

I bought 2 Pycom LORA on Kickstarter, but haven't come around to even install them. I mostly experimented with the pyboard because the timing aspects are superior as MicroPython runs on bare metal and not on top of a RTOS like on the ESP32, the basis for all Pycom devices. As a FPGA developer you will appreciate correct - and reliable timing for your signals :-)

SE95, MCP4725, MCP23008, BME280, INA219 and EAT123W-I2C are a few of the devices that are laying around and will eventually be hooked up to the usbiss.I2C driver.

I noticed the py-gpio driver from the same developer as the py-spidev. Do you know this library?

Off Topic, What kind of project has your dad in mind for his FiPy's ?

DancingQuanta commented 6 years ago

Cool, I did not know about the timing difference between pyboard's micropython and pycom's micropython. Where can I read more on that?

I did not know the library py-gpio and it have not been worked on for 6 years. There is also a different library adafruit/Adafruit_Python_GPIO.

My dad is interested in a networking protocol called NB-IoT which the fipy can use. However, the NB-IoT relies on cellular masts (piggy back on mobile service so you have a sim card and billing, pretty much like a mobile phone) so NB-IoT have not been activated in UK yet. NB-IoT is an interesting tech where you can transmit for a long distance.

How are you testing your IO capacity?

gwdehaan commented 6 years ago

Where can I read more on that? https://forum.pycom.io/topic/936/pin-interrupt-latency https://forum.micropython.org/viewtopic.php?f=15&t=4016 https://forum.micropython.org/viewtopic.php?f=18&t=4278

It is not to say that the ESP32 based solutions are inferior to the baremetal variants, it is just that it is a designconsediration when choosing the right tools for the project at hand.

The Adafruit version is for Circuitpython, their implementation of uPython.

How are you testing your IO capacity?

# Testing 1 - 
#
# All pins as OutputL
t=USBISS('COM3',  "io", pin1="outputL", pin2="outputL", pin3="outputL", pin4="outputL")
# pin switching as fast as possible
while True:
    t.SetPinOn(2)
    t.SetPinOff(2)

image

Results

As shown on the image : massive jitter, as to be expected with WIN10, Python garbage collection and the dependency on the serial communication.

# Testing 2 -
#
# Pin 1 as Input, Pin2 has a Led connected
t=USBISS('COM3',  "io", pin1="input", pin2="outputL", pin3="outputL", pin4="outputL")
while True:
    inp = t.GetPin(1)
    if inp:
        t.SetPinOn(2)
    else:
        t.SetPinOff(2)

Results

Test OK, Led on Pin2 is controlled by lnput on Pin 1

Next on GPIO

  1. Testing the ADC capability.
  2. Fork your new classes branch. I will need your help on that. I've tried but without success.
  3. Adapt my current GPIO code for use with your new class. Retest (test on GPIO and your classes branch)
  4. DuckTyping based on the rpi.GPIO

Offtopic

Germany is implementing NB-Iot, but in other countries LORA seems to be the first choice, including the UK and specific in London. https://www.theinquirer.net/inquirer/news/2471687/london-gets-dedicated-iot-network

DancingQuanta commented 6 years ago

Yes, each tool have its strengths and weaknesses and every situation require different tool.

Nice tests. The duty cycle didn't look symmetrical but yea we are dealing with python. Python is not meant for precision timing.

I realised that USBISS works as a I/O expander. There are numerous examples of I/O expanders in the wild. Some of them may have python libraries built for them like this; https://github.com/BLavery/virtual-GPIO, https://github.com/hardkernel/Odroid-USBIO and https://nathan.chantrell.net/20120524/python-tools-for-the-mcp23017-io-expander/. These IO expanders connect to master through I2C and you can imagine that with USBISS the I2C is replaced with USB.

Developing classes concept

I wish I knew how to make test suite scripts to make testing easier.

I also remembered I called my SPI functionality virtual SPI device. Donor is odd.

gwdehaan commented 6 years ago

I think we should stick to Virtual rpi libraries like GPIO, smbus etc. They are well known and many people learnt these techniques by using Python on the Raspberry Pi.

First tests on the ADC look promising, wil do some more tests to have a kind of a performance baseline for future variants.

Thanks for your help on the necessary git commands to have the classes branch available.

Now seems to be a good moment to start a new issue for the GPIO protocol like you suggested.

DancingQuanta commented 6 years ago

Yes, stick to virtual rpi libraries.

DancingQuanta commented 6 years ago

Continue discussion in other issues eg #4.