Created
December 6, 2015 09:28
-
-
Save yaakov-h/0caad10add0b2935a85d to your computer and use it in GitHub Desktop.
Win10 IoT code for Pi Menorah
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.Net.Http; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using Windows.ApplicationModel.Background; | |
using Windows.Devices.Gpio; | |
using Windows.System.Threading; | |
namespace PiMenorah | |
{ | |
public sealed class StartupTask : IBackgroundTask | |
{ | |
// Board GPIO pin numbers that are connected to the LEDs. | |
static int[] ChannukiaPinNumbers => new[] { | |
21, // GPIO pin that controls the shamash AND the 1st light. | |
20, // GPIO pin that controls the 2nd light. | |
16, // GPIO pin that controls the 3rd light. | |
12, // GPIO pin that controls the 4th light. | |
25, // GPIO pin that controls the 5th light. | |
24, // GPIO pin that controls the 6th light. | |
18, // GPIO pin that controls the 7th light. | |
23 // GPIO pin that controls the 8th light. | |
}; | |
static TimeSpan HttpCheckTimeInterval => TimeSpan.FromMinutes(1); | |
// URL to check. Should return a plain text string indicating what number of LEDs to light | |
// (plus the shamash) | |
const string NightCountUri = "https://some.url.here"; | |
BackgroundTaskDeferral deferral; | |
GpioPin[] pins; | |
ThreadPoolTimer timer; | |
CancellationTokenSource cancellationTokenSource; | |
public async void Run(IBackgroundTaskInstance taskInstance) | |
{ | |
// I have no idea if this is a valid pattern for a background task, but YOLO. | |
cancellationTokenSource = new CancellationTokenSource(); | |
taskInstance.Canceled += (sender, reason) => | |
{ | |
cancellationTokenSource.Cancel(); | |
cancellationTokenSource.Dispose(); | |
cancellationTokenSource = null; | |
}; | |
// Let us keep running in the background indefinitely, or until our task is canceled. | |
deferral = taskInstance.GetDeferral(); | |
cancellationTokenSource.Token.Register(deferral.Complete); | |
var gpio = await GpioController.GetDefaultAsync(); | |
Debug.Assert(gpio != null); | |
pins = OpenPins(gpio, ChannukiaPinNumbers); | |
cancellationTokenSource.Token.Register(DisposePins); | |
await RunTestPatternAsync(); | |
SetNights(pins, 8); | |
// Note that this timer first runs after {HttpTimeCheckInterval}, so the startup procedure is: | |
// 1. Test pattern, 5 times. | |
// 2. 8 LEDs | |
// 3. {HttpCheckTimeInterval} later, the amount of LEDs as determined by our command and control server. | |
// 4. Every {HttpCheckTimeInterval} after that, the amount of LEDs as determined by our command and control server. | |
// (pretty much just control, no commanding going on). | |
timer = ThreadPoolTimer.CreatePeriodicTimer(GetCurrentNightCount, HttpCheckTimeInterval); | |
cancellationTokenSource.Token.Register(timer.Cancel); | |
} | |
async void GetCurrentNightCount(ThreadPoolTimer timer) | |
{ | |
using (var http = new HttpClient()) | |
{ | |
try | |
{ | |
var response = await http.GetStringAsync(NightCountUri); | |
var value = int.Parse(response?.Trim()); | |
SetNights(pins, value); | |
} | |
catch(Exception ex) | |
{ | |
Debug.WriteLine(FormattableString.Invariant($"{ex.GetType().FullName}: {ex.Message}")); | |
SetNights(pins, 8); | |
} | |
} | |
} | |
static void SetNights(GpioPin[] pins, int nights) | |
{ | |
Debug.Assert(pins != null); | |
nights = Math.Min(nights, pins.Length); | |
// Turns LEDs 0 - {nights} on. | |
var i = 0; | |
for (; i < nights; i++) | |
{ | |
pins[i].Write(GpioPinValue.Low); | |
} | |
// Turn LEDs {nights} - {max} off; | |
// i = nights at this point. | |
for(; i < pins.Length; i++) | |
{ | |
pins[i].Write(GpioPinValue.High); | |
} | |
} | |
static GpioPin[] OpenPins(GpioController controller, int[] pinNumbers) | |
{ | |
var pins = new GpioPin[pinNumbers.Length]; | |
for (int i = 0; i < pinNumbers.Length; i++) | |
{ | |
var pinNumber = pinNumbers[i]; | |
var pin = controller.OpenPin(pinNumber, GpioSharingMode.Exclusive); | |
Debug.Assert(pin != null); | |
pin.SetDriveMode(GpioPinDriveMode.Output); | |
pins[i] = pin; | |
} | |
return pins; | |
} | |
async Task RunTestPatternAsync() | |
{ | |
for (int i = 0; i < 5; i++) | |
{ | |
for (int j = 0; j < pins.Length; j++) | |
{ | |
pins[j].Write(GpioPinValue.Low); | |
await Task.Delay(100); | |
} | |
for (int j = 0; j < pins.Length; j++) | |
{ | |
pins[j].Write(GpioPinValue.High); | |
await Task.Delay(100); | |
} | |
} | |
} | |
void DisposePins() | |
{ | |
if (pins != null) | |
{ | |
for (int i = 0; i < pins.Length; i++) | |
{ | |
pins[i]?.Dispose(); | |
} | |
} | |
pins = null; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment