Drivers coding and programming practices

Polymorphism would only be between similar classed devices…

You can’t call a LCD a stepper motor in real live, so you shouldn’t be able to in code - this is what Bec is saying.

Not a single mail for the shared dropbox, not a single post about this… :think:
Then it’s clear : no interest :snooty:

There won’t be further developments from me about this. I have to admit that I was wrong with this idea. It’s occuring more than I would want :-[

don’t be disheartened. i suspect there’s too much diversity in knowledge here, and no direct “project” that we’re all involved in to drive the need for this.

Don’t be so disheartened Bec, my girlfriend is sick at the moment and i’ve been pretty busy at work so i haven’t had a chance to do anything myself on it. I am still interested though.

I also would be interested. If we had standard interfaces for different types of sensors.
I guess until we have a standard I will write nasty code just to experiment with a sensor.

But when I start on a project I endeavor to use good coding practices.

I’m not disheartened at all :hand: I thought it was a good idea, but too few people seems to think the same thing. So this idea is not a really good idea. That’s all.
Or maybe it came too soon ? In this case, let’s wait a better time for it.

It is a good idea, to me anyway!

A hierarchy of interfaces could be used to as multiple interface inheritance is supported by C#.

I cannot see many good reasons against this approach myself and would be interested in getting involved.

Cheers

Andy

@ bec - It’s a good idea, but only if it makes sense to the person and their projects/

For a person who has just one servo in their single project, it’s not that big of deal.

But if you’re a tinkerer and have different types of servos and controllers just sitting on your workbench waiting to be used, then yeah they would likely appreciate having abstracted interfaces.

For me at work, it’s a “depends” if I create interfaces. My simple projects I don’t take the time, but when there will be clear overlap or a need to modularize my apps, then I do so.

Same with this - my initial bot will only have 1 servo. So for me, I wouldn’t take time to do so. But I will eventually have 2 different type of sensors - so for that, I may take the extra time.

For this to be of real use to everyone, imo, then GHI would have to roll them into their assemblies and have their drivers be based on them. This way, everyone is already using them, and then can simply switch out the implementation when needed. Also, then there would be an “official” standard to work from.

I’m not sure GHI should go this way : they sell nearly only one kind of each component so they don’t need to be more “open” in their drivers, to me.

But… users like us, that may buy many different parts everywhere could benefit of this kind of programming, I think.

Or, GHI could decide what set of properties/method should be implemented and we all follow these rules. It wouldn’t bother me that much :hand:

I think this is good practice, but it can also have some drawbacks if it’s not thought well at the beginning : if you put too much properties/methods then it could be hard to implement or even useless for many components; if you put too few properties, then you take the risk that a (forgotten) property is implemented with different names and different parameters, even though the result is the same.
Here I think for example at methods like LCD.Write() vs LCD.Print() or LCD.Display(). Everyone can see or imagine that each of these methods will display a char (a string) on a LCD screen but “you” will call it LCD.Display() in “your” driver while “I” will call it LCD.Write() in “mine” :wink:

But one of the major advantages I see with this is that you can simply provide an assembly (with source if you want) that has to be referenced in your project and here you go : everyone can use your driver without even knowing how it is done. This abstraction could be very useful for beginners so that they can have a fast and good result quickly while it will also be useful to other programmers that only need to test their program against different kinds of components. Here I think at the GPS driver, for example : there could be as many (small) drivers as needed that all implement a minimal set of properties/methods. More advanced GPS can still expose other things, of course, for example with the use of an “escape command” method.

I know you know and understand that, anyway. :wink:

Btw, I don’t understand what happened to my shared folder but all the .cs files have gone :o

Preface: I see the value.

But I think a beginner would just copy and paste from the eBook, rather than download an additional assembly/framework and then an implementation as well - even if it’s make easily available on a code sharing site.

I would be willing to assist in this effort, however my experience in FEZ type hardware is very limited.

Code should be made so it is portable and expandable. There is a catch, this is an embedded system! When you are on a small system with limited resources, you can’t the luxury of creating display drivers that have all kind of features, fonts and shapes. On a PC you can add it all and there is room for more. On an embedded system you will probably only add what you need. Not only that, the display refresh routine will run blazing fast on a PC but on an embedded system you would want to optimize it as much as I can. Maybe by updating part of the screen or by coding everything in-place, no function calls unless necessary.

So, what GHI does is provide you with the absolutely necessary functions to access hardware in the GHI assemblies. These are optimized and studied to the limits. Then we give you hardware components with their sample driver. But why would GHI provide super-optimized drivers for internal hardware but samples driver for components? This will guarantee that the hardware will work perfectly and as expected but then the drivers for the components are open for you to use and optimize to fit your needs. You may not be using our 16-relay I2C board but you maybe using something similar. The driver we give you will give you a good starting point. Our GPS driver is not optimized and doesn’t give you everything you need but surely will get you started on the right track. I saw some work being done to create a super GPS driver, which is great but it will be VERY difficult to create a driver that fits everyones needs and at the same time it is small and efficient for an embedded system.

PC = Portable = large and bulky = easy to use
embedded = somewhat portable = lean and fast = somewhat easy

This is just my personal opinion :slight_smile:

You’re absolutely right, Gus, and I completely agree with you. But I think that there’s some misunderstanding here and there :wink:

The main goal of such interface is to propose the strict minimal number of functions a device should implement, nothing more. Those functions should be/are common to all similar devices.

It’s not meant to implement all the possible capabilities of all devices :hand: But you can’t imagine either an LCD without some sort of Write() method, a Servo without a Position() method or a motor without a Move() method. This is the goal.

On the programmers’ side, we can then consider two categories of people : driver programmers and driver users.

The driver programmer has to code all the methods/properties contained in the interface (compiler will stop if he doesn’t :wink: ). No matter how he does it and no matter the device’s internals. Once done, he just puts his assembly online, ready for use.

The driver user will then include the interface assembly and the driver of his choice. Say he has bought one of the LCD you sell here : in his program, he will reference the assembly (driver) GHI_LCDDriver.
Now, if the LCD fries and he buys another one at SFE, not same brand. If this LCD has a driver that conforms to the interface, then he only has to remove the reference to GHI_LCDDriver and reference SFE_LCDDriver instead.

The benefit is obvious, to me. No hassle with looking at and/or modifying an entire program just because a device has changed.

Also, the interfaces can hold some informations like driver’s version, author’s name, and so on…

Here’s an example of how this interface work in practice. I was working on some code to be an asynchronous sensor manager - multiple sensors would fire at the same time, but have a blocking call that would wait until all results came in.

My simplified Interface:


interface ISensor
    {
        // void InitializeSensor(InputPort Port)
        object GetReading();
        string SensorName { get; set; }
    }

Here’s a simple InfraRed (without the initialization of the base driver)

class InfraRedSensor : ISensor
    {
        #region ISensor Members  
        // the init would go in here and it would keep the DistanceDetector object
        
        public object GetReading()
        {
            // return DistanceDetector.GetDistance_cm();
           // for testing sakes:
            Random r = new Random(DateTime.Now.Millisecond);
            return r.Next(0, 80);
        }

        string _sensorName;
        public string SensorName
        {
            get
            {
                return _sensorName;
            }
            set
            {
                _sensorName = value;
            }
        }

        #endregion
    }

In my manager function I’d have this:

public void AddSensor(ISensor Sensor)
        {
            int i = -1;
            while (++i < _sensors.Count() && _sensors[i] != null) { }
            _sensors[i] = Sensor;
        }

Then the thread function that does the work and returns the value to the buffer array (needs to be cleaned up):

void readSensor(object data)
        {
            var settings = (SensorStart)data;
            var sensor = (ISensor)settings.sensor;
            Thread.Sleep(r.Next(10, 2500));            
            setSensorData(settings.index, sensor.GetReading());

            Console.WriteLine("Thread {0} finished at {1}.{2}", sensor.SensorName, DateTime.Now.ToString(), DateTime.Now.Millisecond);

            if (getSensorData(0) != null && getSensorData(1) != null && getSensorData(2) != null)
                _signal.Set();
        }

And my struct for the ParameterizedThreadStart:

struct SensorStart
    {
        public object sensor;
        public int index;
    }

And in the calling code -I can pass in any type of ISensor

            Synchronizer ss = new Synchronizer();
            ss.AddSensor(new InfraRedSensor() { SensorName = "IR1" } );
            ss.AddSensor(new UltraSonicSensor() { SensorName = "US1" } );
            ss.AddSensor(new InfraRedSensor() { SensorName = "IR2" } );

            ss.GetReadings();

Now I come to the scene with my own sensor and its associated driver :

class BaFSensor : ISensor
    {
        public object GetReading()
        {
            int i = 10;
            for (int j=0; j<10; j++) { i += j; }
            Random r = new Random(DateTime.Now.Millisecond);
            return r.Next(0, 80);
        }
 
        string _sensorName;
        public string SensorName
        {
            get
            {
                return _sensorName;
            }
            set
            {
                _sensorName = value;
            }
        }
    }

… and following the program of mhectorgato, I add my own sensor in his list :wink:

Synchronizer ss = new Synchronizer();
            ss.AddSensor(new InfraRedSensor() { SensorName = "IR1" } );
            ss.AddSensor(new UltraSonicSensor() { SensorName = "US1" } );
            ss.AddSensor(new InfraRedSensor() { SensorName = "IR2" } );
            ss.AddSensor(new BaFSensor() { SensorName = "Becafuel sensor" } );
 
            ss.GetReadings();

Here, it’s another way of using interfaces, but the main principle is absolutely the same : since my BaFSensor does conform to his interface, mhectorgato can use it the same way he’s using the other sensors, without knowing that my sensor is far better that his ones, with a precision of a micrometer, 50GHz sampling rate and 32 bits ADC :smiley: