jefffhaynes / XBee

A .NET library for XBee wireless controllers
MIT License
41 stars 17 forks source link

Feature Request: Extend Input/Output Configuration and Change Detection for S2C #16

Closed PaulNoto closed 8 years ago

PaulNoto commented 8 years ago

Hi Jeff,

I extended the input/output Configuration and Change Detection so it would cover DIO0 thru DIO14 on the S2C Version of the XBees. I was hoping you would consider modifying the library. The following includes the files I modified and the changes I made. I tested everything through DIO14 and it works. My tests included setting the pins low, high, and as an input with change detection. I don't know if this is the right way to do this because I made it work for just my flavor of S2C Xbees. Also I noticed that several of the ResponseData Methods need to support all the versions of XBees. I modified just InputOutputChangeDetectionResponseData to support just my flavor of XBee.

Here is what I did:

CHANGE DETECTION

// ADDED TO: InputOutputChangeDetectionResponseData.cs
// Needed to support my S2C version
[FieldOrder( 1 )]
[SerializeWhen( "ControllerHardwareVersion", HardwareVersion.XBeePro900, RelativeSourceMode = RelativeSourceMode.SerializationContext )]
[SerializeWhen( "ControllerHardwareVersion", HardwareVersion.XBeePro900HP, RelativeSourceMode = RelativeSourceMode.SerializationContext )]
[SerializeWhen( "ControllerHardwareVersion", HardwareVersion.XBee24C, RelativeSourceMode = RelativeSourceMode.SerializationContext )]
public DigitalSampleChannels? ChannelsExt { get; set; }

// MODIFIED: InputOutputChangeDetectionCommand.cs
// Needs to set 16 bit value
public class InputOutputChangeDetectionCommand : AtCommand {

    [Ignore]
    public DigitalSampleChannels? Channels {
        get { return Parameter as DigitalSampleChannels?; }
        set { Parameter = Convert.ToUInt16( value ); }
        //set { Parameter = Convert.ToByte(value); }
    }

//-----------------------------------------

INPUT OUTPUT CONFIGURATION

// MODIFIED: InputOutputConfigurationCommand.cs
// Above D9 starts with P0.  Cool, I learned I could include a conditional in a call to the base constructor!
public class InputOutputConfigurationCommand : AtCommand {

    public InputOutputConfigurationCommand( InputOutputChannel channel ) :
         base( (int)channel > 9 ? $"P{(int)channel - 10}" : $"D{(int)channel}" ) {
    }

// ADDED TO: InputOutputChannel.cs
// It stopped at Channel 9
public enum InputOutputChannel {
    Channel0 = 0,
    Channel1 = 1,
    Channel2 = 2,
    Channel3 = 3,
    Channel4 = 4,
    Channel5 = 5,
    Channel6 = 6,
    Channel7 = 7,
    Channel8 = 8,
    Channel9 = 9,
    Channel10 = 10,
    Channel11 = 11,
    Channel12 = 12,
    Channel13 = 13,
    Channel14 = 14
}

// ADDED TO: DigitalSampleState.cs
public enum DigitalSampleState : ushort {
    None = 0x0,
    Input0 = 0x1,
    Input1 = 0x2,
    Input2 = 0x4,
    Input3 = 0x8,
    Input4 = 0x10,
    Input5 = 0x20,
    Input6 = 0x40,
    Input7 = 0x80,
    Input8 = 0x100,
    Input9 = 0x200,
    Input10 = 0x400,
    Input11 = 0x800,
    Input12 = 0x1000,
    Input13 = 0x2000,
    Input14 = 0x4000,

    All = Input0 | Input1 | Input2 | Input3 | Input4 | Input5
            | Input6 | Input7 | Input8 | Input9 | Input10 | Input11 | Input12 | Input13 | Input14
}

// ADDED TO: DigitalSampleChannels.cs
public enum DigitalSampleChannels : ushort {
    None = 0x0,
    Input0 = 0x1,
    Input1 = 0x2,
    Input2 = 0x4,
    Input3 = 0x8,
    Input4 = 0x10,
    Input5 = 0x20,
    Input6 = 0x40,
    Input7 = 0x80,
    Input8 = 0x100,
    Input9 = 0x200,
    Input10 = 0x400,
    Input11 = 0x800,
    Input12 = 0x1000,
    Input13 = 0x2000,
    Input14 = 0x4000
}

// ADDED TO: RxIndicatorSampleExtFrame.cs
[SerializeWhen( "DigitalChannels", DigitalSampleChannels.Input13,
     ConverterType = typeof( BitwiseAndConverter ), ConverterParameter = DigitalSampleChannels.Input13 )]
[SerializeWhen( "DigitalChannels", DigitalSampleChannels.Input14,
     ConverterType = typeof( BitwiseAndConverter ), ConverterParameter = DigitalSampleChannels.Input14 )]

Like I said, this works for me, but, I don't know the big picture of what you are doing.

PS. I was testing on a router. I never tested committing a change to DIO13 or DIO14 and putting it back in the programmer board. I assume it wouldn't work because DIO13 & 14 are also the serial data pins.

jefffhaynes commented 8 years ago

Still looking at this but in regards to the change in InputOutputChangeDetectionCommand from byte to ushort, that is already handled in InputOutputChangeDetectionCommandExt. Are you using the GetNodeAsync method and then setting IO change detection or something else?

PaulNoto commented 8 years ago

I was just testing how things work when I ran into an issue where I was getting an Overflow Exception on setting change detection on inputs 8 and above. I tracked it down to InputOutputChangeDetectionCommand using a byte. which made sense. 0 to 7 work, 8 and above throw an overflow exception. so I changed it to uint16 and everything worked without an overflow exception.

I'm using this: await sender.SetChangeDetectionChannelsAsync( DigitalSampleChannels.Input8 );

Which calls: public class InputOutputChangeDetectionCommand : AtCommand { public InputOutputChangeDetectionCommand() : base( "IC" ) { }

    public InputOutputChangeDetectionCommand( DigitalSampleChannels channels ) : this() {
        Channels = channels;
    }

    [Ignore]
    public DigitalSampleChannels? Channels {
        get { return Parameter as DigitalSampleChannels?; }
        set { Parameter = Convert.ToUInt16(value); }
        //set { Parameter = Convert.ToByte( value ); } 
    }
}

Which will throw an overflow exception on Convert.ToByte( value ); Which made sense because the mask is 16 bits wide. Anyway, that was why I changed it to Uint16.

jefffhaynes commented 8 years ago

Sure, but you're not using that class directly, right?  What are you actually calling that's causing that exception? Thanks

On Sun, May 8, 2016 at 12:51 PM -0700, "PaulNoto" notifications@github.com wrote:

I was just testing how things work when I ran into an issue where I was getting an Overflow Exception on setting change detection on inputs 8 and above. I tracked it down to InputOutputChangeDetectionCommand using a byte. which made sense. 0 to 7 work, 8 and above throw an overflow exception. so I changed it to uint16 and everything worked without an overflow exception.

I'm using this:

await sender.SetChangeDetectionChannelsAsync( DigitalSampleChannels.Input8 );

Which calls:

public class InputOutputChangeDetectionCommand : AtCommand {

    public InputOutputChangeDetectionCommand() : base( "IC" ) {

    }

public InputOutputChangeDetectionCommand( DigitalSampleChannels channels ) : this() {
    Channels = channels;
}

[Ignore]
public DigitalSampleChannels? Channels {
    get { return Parameter as DigitalSampleChannels?; }
    set { Parameter = Convert.ToUInt16(value); }
    //set { Parameter = Convert.ToByte( value ); } 
}

}

Which will throw an overflow exception on Convert.ToByte( value );

Which made sense because the mask is 16 bits wide.

Anyway, that was why I changed it to Uint16.

— You are receiving this because you commented. Reply to this email directly or view it on GitHub

PaulNoto commented 8 years ago

Well, I was just testing things out. So the pattern I was using was:

    XBeeSeries2 routerTest;
    private async Task DiscoverNodes() {

        controller.NodeDiscovered += async ( sender, args ) => {
            await Task.Delay( 1000 );
            if ( args.Node.Address.Equals( new NodeAddress( "0013A20040F7850E" ) ) ) {
                routerTest = args.Node as XBeeSeries2;
                routerTest.SampleReceived += RouterTest_SampleReceived;
            }
        };
        await controller.DiscoverNetworkAsync();
    }

    private async void RouterTest_SampleReceived( object sender, SampleReceivedEventArgs sample ) {
        // Check if XBee has been power cycled
        if ( !sample.DigitalChannels.HasFlag( DigitalSampleChannels.Input14 ) ) {
            // Yes it has, do any configuration that is necessary
            await Task.Run( () => SetRemoteControl_S2C( sender as XBeeSeries2 ) );
        } else {
            // No it hasn't, Process samples from it normally
            LightSensorSample( sample.A0 );
        }
    }

    private async void SetRemoteControl_S2C( XBeeSeries2 sender ) {
        // Set DIO14 so we don't come back here unless the XBee is power cycled
        await sender.SetInputOutputConfigurationAsync( InputOutputChannel.Channel14, InputOutputConfiguration.DigitalLow );
        // Test input 8 for overflow exception
        // Set Input 8 as an input
        await sender.SetInputOutputConfigurationAsync( InputOutputChannel.Channel8, InputOutputConfiguration.DigitalIn );
        // Set change detection and cause overflow exception
        await sender.SetChangeDetectionChannelsAsync( DigitalSampleChannels.Input8 );
    }

I am going to use DIO14 as a flag to check if I need to do any first time configuration on an XBee when it gets power cycled. I won't have fixed variables like routerTest in my actual code, and I won't use network discovery. My final code will respond to an un-configured XBee as soon as it sends it's first sample. But this does prove my concept for what I want to do.

jefffhaynes commented 8 years ago

Ok I'll take a look when I get a minute. 

On Sun, May 8, 2016 at 1:56 PM -0700, "PaulNoto" notifications@github.com wrote:

Well, I was just testing things out. So the pattern I was using was:

XBeeSeries2 routerTest;
private async Task DiscoverNodes() {

    controller.NodeDiscovered += async ( sender, args ) => {
        await Task.Delay( 1000 );
        if ( args.Node.Address.Equals( new NodeAddress( "0013A20040F7850E" ) ) ) {
            routerTest = args.Node as XBeeSeries2;
            routerTest.SampleReceived += RouterTest_SampleReceived;
        }
    };
    await controller.DiscoverNetworkAsync();
}

private async void RouterTest_SampleReceived( object sender, SampleReceivedEventArgs sample ) {
    // Check if XBee has been power cycled
    if ( !sample.DigitalChannels.HasFlag( DigitalSampleChannels.Input14 ) ) {
        // Yes it has, do any configuration that is necessary
        await Task.Run( () => SetRemoteControl_S2C( sender as XBeeSeries2 ) );
    } else {
        // No it hasn't, Process samples from it normally
        LightSensorSample( sample.A0 );
    }
}

private async void SetRemoteControl_S2C( XBeeSeries2 sender ) {
    // Set DIO14 so we don't come back here unless the XBee is power cycled
    await sender.SetInputOutputConfigurationAsync( InputOutputChannel.Channel14, InputOutputConfiguration.DigitalLow );
    // Test input 8 for overflow exception
    // Set Input 8 as an input
    await sender.SetInputOutputConfigurationAsync( InputOutputChannel.Channel8, InputOutputConfiguration.DigitalIn );
    // Set change detection and cause overflow exception
    await sender.SetChangeDetectionChannelsAsync( DigitalSampleChannels.Input8 );
}

I am going to use DIO14 as a flag to check if I need to do any first time configuration on an XBee when it gets power cycled. I won't have fixed variables like routerTest in my actual code, and I won't use network discovery. My final code will respond to an un-configured XBee as soon as it sends it's first sample. But this does prove my concept for what I want to do.

— You are receiving this because you commented. Reply to this email directly or view it on GitHub

jefffhaynes commented 8 years ago

Yeah, sorry this was just a bug. The XBeeSeries2 wasn't correctly overriding the iochangedetect stuff. Thanks!