Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Enable code when a class is loaded


  • Please log in to reply
11 replies to this topic

#1 Stefan

Stefan

    Moderator

  • Members
  • PipPipPip
  • 1965 posts
  • LocationBreda, the Netherlands

Posted 30 March 2011 - 06:32 AM

Hi,

I have written a couple of classes of which are helper classes which can help with multiple other classes. Complex story, but here's the thing.

I want some of the code only available if another class is also added to the solution. I was looking into C# Preprocessor Directives
and tried to do the following:

Class1.cs:
#define Class1
Class2.cs:
#if Class1
// Some code
#endif
That didn't work. The conditional statement should be in the same file appairently.
How can I dis/enable code by checking if a specific class exists? Or is what I want kinda impossible?
"Fact that I'm a moderator doesn't make me an expert in things." Stefan, the eternal newb!
My .NETMF projects: .NETMF Toolbox / Gadgeteer Light / Some PCB designs

#2 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 30 March 2011 - 09:49 AM

Hi Stefan. From my viewpoint Visual Studio is somewhat leaky about this kind of stuffs. Preprocessing is available only in two flavors: scoped within a module in which is declared and project-wide, by declaring in the project-property wizard. I am not sure to understand what you want to do, but the "partial" keyword does fit your need? Cheers
Biggest fault of Netduino? It runs by electricity.

#3 Stefan

Stefan

    Moderator

  • Members
  • PipPipPip
  • 1965 posts
  • LocationBreda, the Netherlands

Posted 30 March 2011 - 10:01 AM

Well, actually this is the real case. I have two classes named like this:

Ic74HC595.cs:
Class Ic74HC595
{
	public enum Pins
	{
		GPO_PIN_D0 = 0,
		GPO_PIN_D1 = 1,
		GPO_PIN_D2 = 2,
		GPO_PIN_D3 = 3,
		GPO_PIN_D4 = 4,
		GPO_PIN_D5 = 5,
		GPO_PIN_D6 = 6,
		GPO_PIN_D7 = 7
	}
	
	// A bunch of code
}
IcTLC5940.cs:
Class IcTLC5940
{
	public enum Pins
	{
		LED_0 = 0,
		LED_1 = 1,
		LED_2 = 2,
		LED_3 = 3,
		LED_4 = 4,
		LED_5 = 5,
		LED_6 = 6,
		LED_7 = 7,
		LED_8 = 8,
		LED_9 = 9,
		LED_10 = 10,
		LED_11 = 11,
		LED_12 = 12,
		LED_13 = 13,
		LED_14 = 14,
		LED_15 = 15
	}
	
	// A bunch of code
}
OutputPortShift.cs:
Class OutputPortShift
{
	// A bunch of code
	public OutputPortShift(Ic74HC595 IcOut, Ic74HC595.Pins Pin, bool InitialState)
	{
		// Constructor when creating an outputport behind the Ic74HC595 IC
	}
	public OutputPortShift(IcTLC5940 IcOut, IcTLC5940.Pins Pin, bool InitialState)
	{
		// Constructor when creating an outputport behind the IcTLC5940 IC
	}
	// A bunch of code
}
Both IC's can be driven with the same outputport-class, but for example the enumeration of pins is different (the 595 is an 8 pins bitshifter, the 5940 is a 16 pins led driver), and a few other calls, so it has more constructors and a few switch statements later on.

But when only one of those IC's is required, it's a waste of memory if also the other IC's should be loaded because of dependency issues.

So if I could place a #define statement in Ic74HC595.cs and IcTLC5940.cs and a #if statement in OutputPortShift.cs the code would be compiled as clean as possible.
"Fact that I'm a moderator doesn't make me an expert in things." Stefan, the eternal newb!
My .NETMF projects: .NETMF Toolbox / Gadgeteer Light / Some PCB designs

#4 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 30 March 2011 - 10:26 AM

IMHO better would be to define an abstract interface that describes the common functionality (of a shift register) and use it in the OutputPortShifter class, and then derive specific classes for each shift register, something like:

public interface IShiftRegister
{
  // Just example
  void Reset();
  void Write(byte[] data);
  void Latch();
  int NumberOfOutputs { get; }
}

public class OutputPortShift
{
  public OutputPortShift(IShiftRegister shiftRegister, bool initialState)
  { ... }
}

public class Ic74HC595 : IShiftRegister
{
  public void Reset()
  {
    // Actual implementation here
  }
  public int NumberOfOutputs
  {
    get { return 8; }
  }
  // The rest of IShiftRegister methods
}

public class IcTLC5940 : IShiftRegister
{
  public void Reset() { ... }

  public int NumberOfOutputs
  {
    get { return 16; }
  }
  // The rest of IShiftRegister methods
}
You could also implement the common functionality in a base class, say ShiftRegister : IShiftRegister, and derive IcXXX from it, overriding just what is different. Regarding the pin enumeration, I would need to see the intended usage scenarios, but in all likelihood it would be better to use (e.g.) a collection (IEnumerable) or a hardware provider class/interface. I am afraid though, such redesign would mean to completely change the existing code (?).

#5 Stefan

Stefan

    Moderator

  • Members
  • PipPipPip
  • 1965 posts
  • LocationBreda, the Netherlands

Posted 30 March 2011 - 10:40 AM

Completely change the existing code wouldn't be my biggest issue ;)

The point is, the pins aren't hardware pins, they form a 8 or 16-bit byte together. When having more IC's in a chain (is also possible), they will even form bigger byte sequences.

I already thought of a few alternatives, going to work on it tonight. I got two evenings 100% free for this project :D

I was just hoping there would be a nice and easy solution to implement.

My current best solution is to add at the top of my OutputPortShift-class:
// Please define the used IC's here
#define Ic74HC595
#undef IcTLC5940

I already considered interfacing but that gives a problem with the enumeration of the pins, and one thing I really really like of Visual Studio is how it handles these things and automaticly does suggestions based on the constructor and Documentation Comments.

When I type, for example:
Ic74HC595 IcOut = new Ic74HC595(SPI_Devices.SPI1, Pins.GPIO_PIN_D10);
OutputPortShift pin1 = new OutputPortShift(IcOut,
it will automaticly suggest all available pins based on the correct constructor. I love it ;) Makes things very easy to code and prevents typos.
"Fact that I'm a moderator doesn't make me an expert in things." Stefan, the eternal newb!
My .NETMF projects: .NETMF Toolbox / Gadgeteer Light / Some PCB designs

#6 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 30 March 2011 - 10:43 AM

Hmmm...
As far I know there's no way to solve with preprocessing directives.

Also, the closest solution I may suggest you is the following:

class OutputPortShift
{
    public OutputPortShift(IcShifterBase IcOut, int Pin, bool InitialState)
    {
        // Constructor when creating an outputport behind the Ic74HC595 IC
    }
}


interface class IcShifterBase
{
  //common members
}



class Ic74HC595 : IcShifterBase
{
    public const int GPO_PIN_D0 = 0,
    public const int GPO_PIN_D1 = 1,
    public const int GPO_PIN_D2 = 2,
    public const int GPO_PIN_D3 = 3,
    public const int GPO_PIN_D4 = 4,
    public const int GPO_PIN_D5 = 5,
    public const int GPO_PIN_D6 = 6,
    public const int GPO_PIN_D7 = 7
        
    // A bunch of code
}


// ...rest is the same...


I do not like your method to manage the compilation based on the presence of a certain class.
I would prefer having some costless abstraction that won't collide, even with both the classes included in the project.
Using this way there's no collision at all and the cost of implementation is even lesser than using enums. As far I know the "const" is translated compile-time (so that will fall in the flash), the enum is a kind of array stored in ram.

The only difference I see is about the intellisense: using enums is automatic, while using const pushes you typing at least the type name.
Cheers
Biggest fault of Netduino? It runs by electricity.

#7 Stefan

Stefan

    Moderator

  • Members
  • PipPipPip
  • 1965 posts
  • LocationBreda, the Netherlands

Posted 30 March 2011 - 10:47 AM

The only difference I see is about the intellisense: using enums is automatic, while using const pushes you typing at least the type name.
Cheers

It also is a form of typehinting, if you fill in 8 for example, the parser won't give an error, but there is no pin 8 (0 to 7). With an enumeration this is forced to only the real possibilities.

Hmm I have some thinking to do and some choices to make... :)
"Fact that I'm a moderator doesn't make me an expert in things." Stefan, the eternal newb!
My .NETMF projects: .NETMF Toolbox / Gadgeteer Light / Some PCB designs

#8 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 30 March 2011 - 11:53 AM

With an enumeration this is forced to only the real possibilities.

False: the constraint is apparent.
You may OR any combination of enums' items and you may cast to any int also. If you want a strict checking on what the user may insert, you must parse every single possibility.
Biggest fault of Netduino? It runs by electricity.

#9 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 30 March 2011 - 01:09 PM

I think the "partial class" approach would work well here. Mario briefly mentioned "partial" but perhaps it helps to provide an example. I will modify the example you posted:

Ic74HC595.cs:
class Ic74HC595
{
	public enum Pins
	{
		GPO_PIN_D0 = 0,
		GPO_PIN_D1 = 1,
		GPO_PIN_D2 = 2,
		GPO_PIN_D3 = 3,
		GPO_PIN_D4 = 4,
		GPO_PIN_D5 = 5,
		GPO_PIN_D6 = 6,
		GPO_PIN_D7 = 7
	}
	
	// A bunch of code
}

partial class OutputPortShift
{
	// A bunch of code
	public OutputPortShift(Ic74HC595 IcOut, Ic74HC595.Pins Pin, bool InitialState)
	{
		// Constructor when creating an outputport behind the Ic74HC595 IC
	}
}


IcTLC5940.cs:
class IcTLC5940
{
	public enum Pins
	{
		LED_0 = 0,
		LED_1 = 1,
		LED_2 = 2,
		LED_3 = 3,
		LED_4 = 4,
		LED_5 = 5,
		LED_6 = 6,
		LED_7 = 7,
		LED_8 = 8,
		LED_9 = 9,
		LED_10 = 10,
		LED_11 = 11,
		LED_12 = 12,
		LED_13 = 13,
		LED_14 = 14,
		LED_15 = 15
	}
	
	// A bunch of code
}

partial class OutputPortShift
{
	public OutputPortShift(IcTLC5940 IcOut, IcTLC5940.Pins Pin, bool InitialState)
	{
		// Constructor when creating an outputport behind the IcTLC5940 IC
	}
}

OutputPortShift.cs:
partial class OutputPortShift
{
   //the remainder of the code for OutputPortShift
}

Do you see what's happening here? The existence of the file Ic74HC595.cs adds a new class called Ic74HC595 and also enhances the class OutputPortShift. A similar thing happens for IcTLC5940.cs.

#10 Stefan

Stefan

    Moderator

  • Members
  • PipPipPip
  • 1965 posts
  • LocationBreda, the Netherlands

Posted 30 March 2011 - 01:24 PM

I was thinking about a solution of that kind as well... Have a lot to do and decide tonight. :lol:
"Fact that I'm a moderator doesn't make me an expert in things." Stefan, the eternal newb!
My .NETMF projects: .NETMF Toolbox / Gadgeteer Light / Some PCB designs

#11 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 30 March 2011 - 01:47 PM

@Corey I was on the clouds! I didn't realize that placing constructors into guess classes is an overload and *NOT* a collision! My age rises and neurons falls... :( Cheers
Biggest fault of Netduino? It runs by electricity.

#12 Stefan

Stefan

    Moderator

  • Members
  • PipPipPip
  • 1965 posts
  • LocationBreda, the Netherlands

Posted 30 March 2011 - 01:50 PM

My age rises and neurons falls... :(

You are wrong. It should be: "never too old to learn" ;)
"Fact that I'm a moderator doesn't make me an expert in things." Stefan, the eternal newb!
My .NETMF projects: .NETMF Toolbox / Gadgeteer Light / Some PCB designs




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.