Microbit Dinosaur Detector

It’s been a while since I posted a microbit sample so here’s one that would work well on the set of Jurassic Park, a dinosaur detector.

As you will know from the film, the way you know the T-Rex is approaching is by standing a glass of water on the dashboard of your stranded Jeep. As the dinosaur approaches, the vibrations from it’s stamping cause ripples in the water so you know when to panic.

The accelerometer in the microbit works well as a crude vibration detector. We note the current x and y orientation of the microbit at start up and watch for a change.


from microbit import *

sleep_time = 200
warning_time = 5000

class Pinger:
    
  def __init__(self):
    self.direction = 1
    self.x = 2
    self.y = 2
     
  def update(self):
    display.set_pixel(self.x, self.y, 0)
    if self.x >= 4:
        self.x = 4
        self.direction = -self.direction
    elif self.x <= 0:
        self.x = 0
        self.direction = -self.direction
        
    self.x += self.direction
    display.set_pixel(self.x, self.y, 9) 
    
    
class DinosaurDetector:
   
  def __init__(self):
    self.horizontal_start = 0
    self.vertical_start = 0
    self.reset()
     
  def dinosaur_detected(self):
    horizontal_now = accelerometer.get_x()
    vertical_now = accelerometer.get_y()
  
    return self.horizontal_start != horizontal_now or self.vertical_start != vertical_now

  def reset(self):
    self.horizontal_start = accelerometer.get_x()
    self.vertical_start = accelerometer.get_y()


display.scroll('Dino Detector', delay=100)

detector = DinosaurDetector()
pinger = Pinger()

glass1 = Image("00000:00000:00900:00000:00000")
glass2 = Image("00000:00900:09090:00900:00000")
glass3 = Image("09990:90009:90009:90009:09990")
glass4 = Image("09090:90009:00000:90009:09090")
ripple_animation = [glass1, glass2, glass3, glass4, glass3, glass2, glass1]

while True:
  
  pinger.update()
  sleep(sleep_time)
    
  if detector.dinosaur_detected():
      detector.reset()
      display.show(ripple_animation, delay=100)
      display.show(Image.GIRAFFE)
      sleep(warning_time)
      display.clear()

The “pinger” is a battlestar galactica style roving pixel to show that the microbit is alive and monitoring it’s environment for dinosaurs. The water ripple animation is there in place of the dashboard water and the giraffe icon is the closest stock image I could get to a sauropod.

This is the first time I’m trying a version of one of these examples using classes instead of exclusively inline code. I think the behaviour of the detector and the scanning “pinger” warranted a little bit extra verbosity to make the main loop a bit more compact.

NUnit Test Actions for Great Good

Lots of c# unit tests I see build up a set of abstract base classes to allow for things like setting up common environments and handling common startup and teardown tasks. This is never a good approach, in my opinion, and can lead to some difficult workarounds due to the high level of coupling this implies. NUnit has a better approach by allowing a text fixture or method to be decorated with a custom attribute that allows code to be run before and/or after all the tests in that test fixture or just the one affected test method.


using NUnit.Framework;

[TestFixture]
[CommonTestHousekeeping]
public class ExampleTest
{
	[Test]
	public void Example_Must_Do_Housekeeping_First()
	{
		... 
	}
}



using NUnit.Framework;

... 

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)]
public class CommonTestHousekeepingAttribute : Attribute, ITestAction
{
	public ActionTargets Targets
	{
		get { return ActionTargets.Default; }
	}

	public void BeforeTest(TestDetails testDetails)
	{
        // do stuff here 
		// ...
		
		if (NotAbleToDoTheThingIWasSupposedToDo)
		{
			// report an error back to the NUnit framework
			throw new ApplicationException("Could not do the thing");
		}
	}

	public void AfterTest(TestDetails testDetails)
	{
        // do stuff here 
		// ...
	}
}



Now rather than having all that coupling to a base class, if you decide your test no longer needs the housekeeping, you remove the attribute and nothing else changes.

Generating Notepaper with PdfSharp

PdfSharp is a lovely library that lets you generate/draw pdf documents programmatically. I used it to generate some notepaper and found it easy to work with once the basics of the objects are understood. We need to create a document, give it some properties, then we can save it.


using PdfSharp.Drawing;
using PdfSharp.Pdf;

...

PdfDocument document = new PdfDocument
{
	PageLayout = PdfPageLayout.SinglePage,
	PageMode = PdfPageMode.UseNone
};

document.Save(filename);


The next obvious thing is to add some pages. Each page can have it’s own size and orientation.


PdfPage newPage = document.AddPage();
newPage.Size = PdfSharp.PageSize.A4;
newPage.Orientation = PdfSharp.PageOrientation.Landscape;


Now that we have a page or two, we want to put some content into them. PdfSharp has a number of objects that are analogs of the GDI drawing objects in Windows, things like Graphics, Pens, Brushes etc. and a set of similar methods to draw lines, rectangles, ellipses.

In order to be able to draw some notepaper, I wanted to be able to have a white border around each page and maybe print on all the page or print an A5 signature as two halves of a landscape A4 page. This meant I needed something to represent one or more printable areas for each page.


public class PrintableArea
{
	public int Left { get; set; }
	public int Right { get; set; }
	public int Top { get; set; }
	public int Bottom { get; set; }

	public static IEnumerable<PrintableArea> FromPage(PdfPage page, int border, bool split)
	{
		var areas = new List<PrintableArea>();

		if (split)
		{
			PrintableArea pane1 = new PrintableArea
			{
				Left = border,
				Right = ((int)page.Width / 2) - border,
				Top = border,
				Bottom = (int)page.Height - border
			};

			PrintableArea pane2 = new PrintableArea
			{
				Left = pane1.Right + (2 * border),
				Right = (int)page.Width - border,
				Top = border,
				Bottom = (int)page.Height - border
			};

			areas.Add(pane1);
			areas.Add(pane2);
		}
		else
		{
			PrintableArea single = new PrintableArea
			{
				Left = border,
				Right = (int)page.Width - border,
				Top = border,
				Bottom = (int)page.Height - border
			};

			areas.Add(single);
		}

		return areas;
	}
}


Each kind of paper - graph, dotted, music manuscript, lined - implies an interface. Let’s call it IPageRenderer.


public interface IPageRenderer
{
	int PageBorder { get; set; }

	void Render(PdfPage page, IEnumerable<PrintableArea> areas);
}


So now we can treat a list of renderings as a group using a page generator.


public class PageGenerator
{
	public bool SplitPages { get; set; }

	public PdfSharp.PageSize PageSize { get; set; }

	public PdfSharp.PageOrientation PageOrientation { get; set; }

	public int PageBorder { get; set; }

	public void GeneratePages(PdfDocument document, int pages, IEnumerable<IPageRenderer> renderers)
	{
		foreach(var renderer in renderers)
		{
			renderer.PageBorder = this.PageBorder;

			for (int page = 0; page < pages; ++page)
			{
				PdfPage newPage = document.AddPage();
				newPage.Size = this.PageSize;
				newPage.Orientation = this.PageOrientation;

				var areas = PrintableArea.FromPage(newPage, this.PageBorder, this.SplitPages);
				renderer.Render(newPage, areas);
			}
		}
	}
}

...


var renderers = new List<IPageRenderer>();
renderers.Add(new ManuscriptPaperRenderer(58, 6));
renderers.Add(new DottedPaperRenderer(15, 1));
renderers.Add(new LinedPaperRenderer(18));
renderers.Add(new GraphPaperRenderer(16));

PageGenerator pageGenerator = new PageGenerator
{
	PageBorder = pageBorder,
	PageOrientation = pageOrientation,
	PageSize = PdfSharp.PageSize.A4,
	SplitPages = splitPages
};

int pagesEach = 1;
pageGenerator.GeneratePages(document, pagesEach, renderers);

			
			




Finally, the implementation of each of the different types of renderer.

Music Manuscript


public class ManuscriptPaperRenderer : IPageRenderer
{
	private readonly int staveSpacing;

	private readonly int lineSpacing;

	public ManuscriptPaperRenderer(int staveSpacing, int lineSpacing)
	{
		this.staveSpacing = staveSpacing;
		this.lineSpacing = lineSpacing;
	}

	public int PageBorder { get; set; }

	public void Render(PdfPage page, IEnumerable<PrintableArea> areas)
	{
		using (XGraphics gfx = XGraphics.FromPdfPage(page))
		{
			XPen pen = new XPen(XColors.Black, 0.0);

			foreach (PrintableArea area in areas)
			{
				for (int horizontalLine = area.Top; horizontalLine < area.Bottom; horizontalLine += this.staveSpacing)
				{
					DrawStave(gfx, pen, horizontalLine, area.Left, area.Right, this.lineSpacing);
				}
			}
		}
	}

	private static void DrawStave(XGraphics graphics, XPen pen, int topLine, int start, int end, int lineSpacing)
	{
		int linesPerStave = 5;
		for (int horizontalLine = 0; horizontalLine < linesPerStave; horizontalLine++)
		{
			graphics.DrawLine(pen, start, topLine + (horizontalLine * lineSpacing), end, topLine + (horizontalLine * lineSpacing));
		}

		// draw end caps to lines
		graphics.DrawLine(pen, start, topLine, start, topLine + ((linesPerStave - 1) * lineSpacing));
		graphics.DrawLine(pen, end, topLine, end, topLine + ((linesPerStave - 1) * lineSpacing));
	}
}


Dotted


public class DottedPaperRenderer : IPageRenderer
{
	private readonly int gridSize;

	private readonly int dotSize;

	public DottedPaperRenderer(int gridSize, int dotSize)
	{
		this.gridSize = gridSize;
		this.dotSize = dotSize;
	}

	public int PageBorder { get; set; }

	public void Render(PdfPage page, IEnumerable<PrintableArea> areas)
	{
		using (XGraphics gfx = XGraphics.FromPdfPage(page))
		{
			XPen pen = new XPen(XColors.LightGray, 0.0);

			foreach (PrintableArea area in areas)
			{
				for (int x = area.Left; x < area.Right; x += this.gridSize)
				{
					for (int y = area.Top; y < area.Bottom; y += this.gridSize)
					{
						gfx.DrawEllipse(pen, x, y, this.dotSize, this.dotSize);
					}
				}
			}
		}
	}
}


Lined


public class LinedPaperRenderer : IPageRenderer
{
	private readonly int lineSpacing;

	public LinedPaperRenderer(int lineSpacing)
	{
		this.lineSpacing = lineSpacing;
	}

	public int PageBorder { get; set; }

	public void Render(PdfPage page, IEnumerable<PrintableArea> areas)
	{
		using (XGraphics gfx = XGraphics.FromPdfPage(page))
		{
			XPen pen = new XPen(XColors.LightGray, 0.0);

			foreach (PrintableArea area in areas)
			{
				for (int horizontalLine = area.Top; horizontalLine < area.Bottom; horizontalLine += this.lineSpacing)
				{
					gfx.DrawLine(pen, area.Left, horizontalLine, area.Right, horizontalLine);
				}
			}
		}
	}
}


Graph


public class GraphPaperRenderer : IPageRenderer
{
	private readonly int gridSize;

	public GraphPaperRenderer(int gridSize)
	{
		this.gridSize = gridSize;
	}

	public int PageBorder { get; set; }

	public void Render(PdfPage page, IEnumerable<PrintableArea> areas)
	{
		using (XGraphics gfx = XGraphics.FromPdfPage(page))
		{
			XPen pen = new XPen(XColors.LightGray, 0.0);

			foreach(PrintableArea area in areas)
			{
				for (int verticalLine = area.Left; verticalLine < area.Right; verticalLine += gridSize)
				{
					gfx.DrawLine(pen, verticalLine, area.Top, verticalLine, area.Bottom);
				}

				for (int horizontalLine = area.Top; horizontalLine < area.Bottom; horizontalLine += gridSize)
				{
					gfx.DrawLine(pen, area.Left, horizontalLine, area.Right, horizontalLine);
				}
			}
		}
	}
}


Examples of each type of paper are available for download.

Naive GUI Automation in PowerShell

For those times when you just need to automate a UI without worrying about too many edge cases. SendKeys works well for simple applications where there isn’t a lot of choice required for workflow or lots of possible dialogs opening.


Start-Process notepad.exe
Start-Sleep -Seconds  3

$Shell = New-Object -ComObject WScript.Shell
$Shell.AppActivate('Untitled - Notepad')
Start-Sleep -Seconds  3

$Shell.SendKeys('Hello World')

# Close Notepad 
$Shell.SendKeys( % )
Start-Sleep -Seconds 1
$Shell.SendKeys( F )
Start-Sleep -Seconds 1
$Shell.SendKeys( X )
Start-Sleep -Seconds 1

# Answer No - Don't save when prompted 
$Shell.SendKeys( n ) 
Start-Sleep -Seconds 1


Note the code above is slightly incorrect. SendKeys can take a string or a single letter surrounded by curly braces to represent that key press. Unfortunately, the site is generated by Jekyll which doesn’t seem to like that syntax in the markup used for this post so I have had to omit it.

Occasionally, the shell implementation can get confused, in which case the alternative is to use a direct invokation of SendWait.


Add-Type -AssemblyName System.Windows.Forms

[System.Windows.Forms.SendKeys]::SendWait('Hello from SendKeys SendWait');


Pre- and Post- Build Differences in MSBuild

Again with the large codebases. Along with many other problems, it can be difficult to see what physical binaries have been created or copied when a build takes place, particularly if pre- and post- build events are used as a sort of batch file within the .csproj. Migrating away from that undesirable kind of build process can be difficult if you can’t tell what is supposed to be happening.

If we use the BeforeTargets and AfterTargets hooks in the msbuild pipeline we can take a snapshot of the output folder immediately before the build and immediately after it and store both snapshots in correspondingly named files. Then we can use a diff tool to look at, well, the differences.


<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<Target Name="SnapshotBeforeBuild" BeforeTargets="BeforeBuild">

	<PropertyGroup>
		<PreBinariesDir>$(TargetDir)\</PreBinariesDir>
		<SnapshotOutput>$(SolutionDir)\$(ProjectName).Pre.Snapshot.txt</SnapshotOutput>
	</PropertyGroup>	

	<ItemGroup>
		<PreBinaries Include="$(PreBinariesDir)**\*.*" />
	</ItemGroup>
	
	<WriteLinesToFile 
		Lines="@(PreBinaries)" 
		File="$(SnapshotOutput)" 
		Encoding="Unicode" 
		Overwrite="true"
		/>
</Target>

<Target Name="SnapshotAfterBuild" AfterTargets="AfterBuild">

	<PropertyGroup>
		<PostBinariesDir>$(TargetDir)\</PostBinariesDir>
		<SnapshotOutput>$(SolutionDir)\$(ProjectName).Post.Snapshot.txt</SnapshotOutput>
	</PropertyGroup>	

	<ItemGroup>
		<PostBinaries Include="$(PostBinariesDir)**\*.*" />
	</ItemGroup>
	
	<WriteLinesToFile 
		Lines="@(PostBinaries)" 
		File="$(SnapshotOutput)" 
		Encoding="Unicode" 
		Overwrite="true"
		/>
</Target>

</Project>

Lightweight Build Order Logging in MSBuild

If you have a lot of .Net code, projects and solutions to build, it can sometimes be difficult to see the order that the projects are actually being built in without going for the nuclear option of detailed or diagnostics logs in msbuild.

If we use the trick of putting a script into the msbuild ImportAfter folder, we can hook into every build and append each project’s build output to a minimal log.


<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="CaptureBuildOutput" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

	<PropertyGroup>
		<BuildOutput>$(SolutionDir)\BuildOrder.txt</BuildOutput>
	</PropertyGroup>	
				 
	<Target Name="BuildOrder" BeforeTargets="BeforeBuild">
	
		<ItemGroup>
			<BuildLines Include="$(SolutionFileName): $(ProjectName)" />
		</ItemGroup>
	
		<WriteLinesToFile 
			Lines="@(BuildLines)" 
			File="$(BuildOutput)" 
			Encoding="Unicode" 
			Overwrite="false"
			/>
	</Target>

</Project>

Tiny Lisp Implementations

I wanted to mention a couple of awesome walkthroughs - one old, one newer - dealing with a subject I always find fascinating, writing interpreters for little languages. Back a couple of weeks ago I discovered a live programming language intended for children called Isla by Mary Rose Cook and after browsing her blog, found an article on implementing a Lisp interpreter in Javascript.

Mary explains the code in an article and a screencast.

On to the older version, right at the end of the article, Mary credits Peter Novig and his implementations of lisp in Python lis.py and an improved lis.py2.

Inspired by these articles, I might have to try an implementation in one of two ways. Either a (not so) tiny .Net version or as an interpreter to run on the microbit.

Project Euler

Project Euler Problem #1 is listing all natural numbers under 1000 and summing those divisible by 3 or 5. Kind of like a maths fizz buzz.


1..999 
|> Enum.filter(fn n -> rem(n, 3) == 0 or rem(n, 5) == 0 end) 
|> Enum.sum 
|> IO.puts