From 5e49ddeb1479b44151641e4274a7b2b0de9f1f8b Mon Sep 17 00:00:00 2001 From: Jonas Arnold Date: Thu, 11 May 2023 16:14:39 +0200 Subject: [PATCH] Initial commit --- udp_led_test_app/Dockerfile | 25 ++++ udp_led_test_app/build.sh | 1 + udp_led_test_app/run.sh | 1 + udp_led_test_app/src/BAT_UdpLedTestApp.csproj | 12 ++ udp_led_test_app/src/Joystick.cs | 55 ++++++++ udp_led_test_app/src/JoystickButtons.cs | 17 +++ udp_led_test_app/src/LedColor.cs | 14 +++ udp_led_test_app/src/Leds.cs | 94 ++++++++++++++ udp_led_test_app/src/Program.cs | 118 ++++++++++++++++++ 9 files changed, 337 insertions(+) create mode 100644 udp_led_test_app/Dockerfile create mode 100644 udp_led_test_app/build.sh create mode 100644 udp_led_test_app/run.sh create mode 100644 udp_led_test_app/src/BAT_UdpLedTestApp.csproj create mode 100644 udp_led_test_app/src/Joystick.cs create mode 100644 udp_led_test_app/src/JoystickButtons.cs create mode 100644 udp_led_test_app/src/LedColor.cs create mode 100644 udp_led_test_app/src/Leds.cs create mode 100644 udp_led_test_app/src/Program.cs diff --git a/udp_led_test_app/Dockerfile b/udp_led_test_app/Dockerfile new file mode 100644 index 0000000..f2cf7d9 --- /dev/null +++ b/udp_led_test_app/Dockerfile @@ -0,0 +1,25 @@ +#FROM debian + +# file: Dockerfile +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS builder + +WORKDIR /app + +# Copy everything from src-directory on host to workdir in image +COPY src . + +# Build and publish a release to directory "out" (build implicitly restores NuGet packages) +RUN dotnet publish -c Release -o out + +# Build runtime image +FROM mcr.microsoft.com/dotnet/runtime:7.0 + +# install GPIO library (don't clean, need cache :-) +RUN apt-get -y update && apt-get -y install gpiod libgpiod2 libgpiod-dev + +# set build- and run-time working directory +WORKDIR /app + +COPY --from=builder /app/out /app + +CMD ["dotnet", "/app/BAT_UdpLedTestApp.dll"] diff --git a/udp_led_test_app/build.sh b/udp_led_test_app/build.sh new file mode 100644 index 0000000..12b94de --- /dev/null +++ b/udp_led_test_app/build.sh @@ -0,0 +1 @@ +docker build . -t udp_led_test_app diff --git a/udp_led_test_app/run.sh b/udp_led_test_app/run.sh new file mode 100644 index 0000000..92557c0 --- /dev/null +++ b/udp_led_test_app/run.sh @@ -0,0 +1 @@ +docker run --rm -it --device /dev/gpiochip0 -p 10001:10001/udp udp_led_test_app diff --git a/udp_led_test_app/src/BAT_UdpLedTestApp.csproj b/udp_led_test_app/src/BAT_UdpLedTestApp.csproj new file mode 100644 index 0000000..7685257 --- /dev/null +++ b/udp_led_test_app/src/BAT_UdpLedTestApp.csproj @@ -0,0 +1,12 @@ + + + + Exe + net7.0 + + + + + + + diff --git a/udp_led_test_app/src/Joystick.cs b/udp_led_test_app/src/Joystick.cs new file mode 100644 index 0000000..a4dd9ff --- /dev/null +++ b/udp_led_test_app/src/Joystick.cs @@ -0,0 +1,55 @@ +using System; +using System.Device.Gpio; +using System.Device.Gpio.Drivers; + + +namespace BAT_UdpLedTestApp { + internal class Joystick { + // public event EventHandler JoystickChanged; + + protected int buttonLeft = 6; + protected int buttonRight = 5; + protected int buttonUp = 19; + protected int buttonDown = 13; + protected int buttonCenter = 26; + + private static GpioController Ctrl { get { return Program.Ctrl; } } + private static Joystick joystick = null; + + public static Joystick GetInstance() { + if( joystick == null ) { + joystick = new Joystick(); + } + return joystick; + } + + private Joystick() { + + if( Ctrl == null ) + throw new Exception( "Constructor Joystick needs access to GpioController object." ); + + Console.WriteLine( "in Joystick() - Initializing Pins" ); + Ctrl.OpenPin( buttonLeft, PinMode.Input ); + Ctrl.OpenPin( buttonRight, PinMode.Input ); + Ctrl.OpenPin( buttonUp, PinMode.Input ); + Ctrl.OpenPin( buttonDown, PinMode.Input ); + Ctrl.OpenPin( buttonCenter, PinMode.Input ); + + } // end constructor + + public JoystickButtons State { + get { + JoystickButtons state = JoystickButtons.None; + + // PinValue v = ctrl.Read( buttonLeft ); + if( Ctrl.Read( buttonLeft ) == false ) state |= JoystickButtons.Left; + if( Ctrl.Read( buttonRight ) == false ) state |= JoystickButtons.Right; + if( Ctrl.Read( buttonUp ) == false ) state |= JoystickButtons.Up; + if( Ctrl.Read( buttonDown ) == false ) state |= JoystickButtons.Down; + if( Ctrl.Read( buttonCenter ) == false ) state |= JoystickButtons.Center; + return state; + } + } // property State + + } // end class Joystick +} diff --git a/udp_led_test_app/src/JoystickButtons.cs b/udp_led_test_app/src/JoystickButtons.cs new file mode 100644 index 0000000..3b48bf2 --- /dev/null +++ b/udp_led_test_app/src/JoystickButtons.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BAT_UdpLedTestApp { + [Flags] + public enum JoystickButtons { + None = 0, + Left = 1, + Right = 2, + Up = 4, + Down = 8, + Center = 16 + } +} diff --git a/udp_led_test_app/src/LedColor.cs b/udp_led_test_app/src/LedColor.cs new file mode 100644 index 0000000..773e700 --- /dev/null +++ b/udp_led_test_app/src/LedColor.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BAT_UdpLedTestApp { + public enum LedColor { + Green, + Yellow, + Red, + Blue + } +} diff --git a/udp_led_test_app/src/Leds.cs b/udp_led_test_app/src/Leds.cs new file mode 100644 index 0000000..f521e21 --- /dev/null +++ b/udp_led_test_app/src/Leds.cs @@ -0,0 +1,94 @@ +using System; +using System.Device.Gpio; +using System.Threading; + +namespace BAT_UdpLedTestApp { + public class Leds { + + // APROG HAT rev6 // rev7 + int pinLedRed = 21; // 16 + int pinLedYellow = 20; // 20 + int pinLedGreen = 16; // 21 + int pinLedBlue = 12; // n/A - set to one of the others! + + bool stateLedRed = false; // PinValue.Low + bool stateLedYellow = false; + bool stateLedGreen = false; + bool stateLedBlue = false; + + private static GpioController Ctrl { get { return Program.Ctrl; } } + private static Leds leds = null; + public static Leds GetInstance() { + if( leds == null ) { + leds = new Leds(); + } + return leds; + } + + private Leds() { + + if( Ctrl == null ) + throw new Exception( "Constructor Leds needs access to GpioController object." ); + + // set GPIO to output mode + Ctrl.OpenPin( pinLedRed, PinMode.Output ); + Ctrl.OpenPin( pinLedYellow, PinMode.Output ); + Ctrl.OpenPin( pinLedGreen, PinMode.Output ); + Ctrl.OpenPin( pinLedBlue, PinMode.Output ); + + // breifly flash Leds: switch all Leds on + Ctrl.Write( pinLedRed, PinValue.High ); + Ctrl.Write( pinLedYellow, PinValue.High ); + Ctrl.Write( pinLedGreen, PinValue.High ); + Ctrl.Write( pinLedBlue, PinValue.High ); + Thread.Sleep( 50 ); + // switch all Leds off + Ctrl.Write( pinLedRed, PinValue.Low ); + Ctrl.Write( pinLedYellow, PinValue.Low ); + Ctrl.Write( pinLedGreen, PinValue.Low ); + Ctrl.Write( pinLedBlue, PinValue.Low ); + + } // end constructor + + public bool Get( LedColor color ) { + // horrible spaghetti code!help me fix it!;) + switch( color ) { + case LedColor.Red: + return stateLedRed; + case LedColor.Yellow: + return stateLedYellow; + case LedColor.Green: + return stateLedGreen; + case LedColor.Blue: + return stateLedBlue; + default: + throw new NotImplementedException( "Unknown LedColor " + color ); + } + } + public void Set( LedColor color, bool state ) { + // horrible spaghetti code! help me fix it! ;) + switch( color ) { + case LedColor.Red: + stateLedRed = state; + Ctrl.Write( pinLedRed, (PinValue)stateLedRed ); + break; + case LedColor.Yellow: + stateLedYellow = state; + Ctrl.Write( pinLedYellow, (PinValue)stateLedYellow ); + break; + case LedColor.Green: + stateLedGreen = state; + Ctrl.Write( pinLedGreen, (PinValue)stateLedGreen ); + break; + case LedColor.Blue: + stateLedBlue = state; + Ctrl.Write( pinLedBlue, (PinValue)stateLedBlue ); + break; + default: + throw new NotImplementedException( "Unknown LedColor " + color ); + } + } // end Set() + + + } // end class Leds +} // end namespace diff --git a/udp_led_test_app/src/Program.cs b/udp_led_test_app/src/Program.cs new file mode 100644 index 0000000..38b8dc6 --- /dev/null +++ b/udp_led_test_app/src/Program.cs @@ -0,0 +1,118 @@ +using System; +using System.Threading; +using System.Device.Gpio; +using System.Device.Gpio.Drivers; +using System.Net; +using System.Net.Sockets; +using System.Text; + +namespace BAT_UdpLedTestApp { + + internal class Program { + public static GpioController Ctrl { get; set; } + + static void Main( string[] args ) { + Console.WriteLine( "Application started!" ); + + // Set up GPIO + + int gpioBank = 0; + Console.WriteLine( "in Joystick() - create LibGpiodDriver" ); + LibGpiodDriver libGpiodDriver = new LibGpiodDriver( gpioBank ); + + Console.WriteLine( "in Joystick() - create GpioController" ); + GpioController ctrl = new GpioController( PinNumberingScheme.Logical, libGpiodDriver ); + Ctrl = ctrl; // set in public property so joystick and leds can access it + + Thread t = new Thread( Run ); + // Background thread, ends when Main() ends + t.IsBackground = false; + t.Start(); + // Program ends, but Run-Thread keeps working + } + protected static void Run() { + Joystick joystick = Joystick.GetInstance(); + Leds leds = Leds.GetInstance(); + JoystickButtons oldState = JoystickButtons.None; + JoystickButtons newState; + + IPEndPoint ipEndpoint = new IPEndPoint(IPAddress.Any, 10001); + UdpClient udpClient = new UdpClient(ipEndpoint); + udpClient.Client.ReceiveTimeout = 100; // set timeout to 100ms + byte[] data = new byte[1024]; + IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0); + + Console.WriteLine("Waiting for clients..."); + while( true ) { + // reset array + data = Array.Empty(); + // try receive data + try + { + data = udpClient.Receive(ref sender); + } + catch (SocketException sockEx) + { + // timeout = normal use case + if (sockEx.SocketErrorCode != SocketError.TimedOut) + { + throw; + } + } + + // decode message, if any received => Handle it + string receivedMessage = Encoding.ASCII.GetString(data, 0, data.Length); + if(receivedMessage.Length > 0) + { + Console.WriteLine("Message received from {0}:", sender.ToString()); + Console.WriteLine(receivedMessage); + + if(receivedMessage.StartsWith("led on")) + { + leds.Set( LedColor.Green, true ); + ReplyMessage(udpClient, sender, "Led turned on"); + } + else if(receivedMessage.StartsWith("led off")) + { + leds.Set( LedColor.Green, false ); + ReplyMessage(udpClient, sender, "Led turned on"); + } + else if(receivedMessage.StartsWith("joystick state")) + { + JoystickButtons state = joystick.State; + ReplyMessage(udpClient, sender, $"Current Joystick state: {state}"); + } + else + { + ReplyMessage(udpClient, sender, "Unknown command"); + } + } + + // check if the joystick state changed, send to last sender + newState = joystick.State; + if( oldState != newState ) { + Console.WriteLine($"New Joystick state detected: {newState}"); + ReplyMessage(udpClient, sender, $"New Joystick state: {newState}"); + oldState = newState; + } + Thread.Sleep( 50 ); + } + } + + public static void ReplyMessage(UdpClient client, IPEndPoint sender, string replyMessage) + { + // would lead to exception + if(sender.Address == IPAddress.Any) { return; } + + // terminate message with LF + string terminatedMessage = $"{replyMessage}\n"; + + // send data + byte[] data = new byte[1024]; + data = Encoding.ASCII.GetBytes(terminatedMessage); + client.Send(data, data.Length, sender); + Console.WriteLine($"Sent message: {replyMessage}"); + } + } // end class Program + +} // end namespace