Problem with N18 Display with SDK 2015 R1

I upgraded to SDK 2015 R1 i.e. 4.3 from 4.1 and now I am having problems with the N18 Display connected to my Hydra main board. I have attached two photos, one of the N18 display and the other of the TE35 display. There are two lines on the N18 that appear to have reverse italics. On this screen example it is lines 9 and 10. On another screen it is lines 4, 8 and 9. The TE35 displays clean text. I have carefully run debug and can’t find any differences with displaying good line and the distorted reverse italic lines. I have tried 3 Hydra boards and 3 N18 displays and all exhibit the same issue. The same code is running both displays at the same time with the only coding difference as follows:

public void RenderLine(string message, int lineloc, Font LineFont, Color LineColor, DisplayN18 displayN18, DisplayTE35 displayTE35)
        {
            if ((message != null) && (message != ""))
            {
                int width;
                int height;
                LineFont.ComputeExtent(message, out width, out height);
                Bitmap bmp = new Bitmap(width, height);
                bmp.DrawText(message, LineFont, LineColor, 0, 0);
                // Render the bitmap to the screen
                displayN18.Draw(bmp, 0, lineloc);
                displayTE35.SimpleGraphics.DisplayImage(bmp, 0, lineloc);
            }
        }

Any idea what is happening and is there a work around?

I think you’re off display limits by one pixel somewhere here:

                Bitmap bmp = new Bitmap(width, height);
                bmp.DrawText(message, LineFont, LineColor, 0, 0);

Check you width and height…

I had already checked that. The N18 is 160 h x 128 w , the displayed lines are widths are:
Line 0: 114
Line 1: 2
Line 2: 114
Line 3: 106
Line 4: 96
Line 5: 124
Line 6 2
Line 7: 126
Line 8: 119
Line 9: 115 Problem Line
Line 10: 90 Problem Line
Line 11: 120

I even tried to see what would happen, I changes the length of line 7 to 119 and line 9 & 10 still had issues. Like I said the funny thing is this code all worked with 4.1. I am going to try varying other parameters like x and y and see what happens. Something has changed. (Edited: I just tried displaying the first 9 lines and providing more than adequate spacing for x and still having issues with line 9. I tried changing the content and it fixed the issue, so there must be a problem with the bitmap created for those lines. I will try more testing) I am not blaming 2015 R1, but there is a difference is how N18 functions.

This is really strange. I tried various line content:

works "123"
does not work "to change line. Indicators"
works "to change line Indicators"
does not work "to change line"
works "line"
works "line. Indicators"
does not work “to line. Indicators”

Of course all the content displays properly on the TE35

The problem occurs when I just have the N18 hooked up, removing all associated TE35 code. Thus the TE35 is not creating the issue.

@ CDR114 - Can you post a complete example that shows the issue?

John, I can’t post the whole code as it is part of a sports timing system that has hundreds of lines of code. However, tonight I will try to pull out the video portions and see if that condensed program replicates the problem If it does, I will post that. If not, is there some other way I can send you the project? This system operated all last winter at sports events as a prototype, running 4.1. I have been doing further enhancements, when I decided to upgrade to 4.3, not expecting any serious issues.

@ CDR114 - We need a minimal code example showing the problem please.

Can GHI post the N18 module firmware code, and let us find the bug? :smiley:

All gadgeteer module drivers are on bitbucket with a link on the support page.

1 Like

I have extracted the video code from my project and it behaves in the same fashion as the original code. However in testing I have discovered that the N18 behaves differently depending on the source of the tinyfnt. I have tried two tinyfnt files, one from TinyFontToolGUI.exe and one from TFConvert.exe. Both files have different lines distorted. The font is calibri light 12 point. I have tried different fonts and they all have different lines distorted. However the TE35 displays both tinyfnt files correctly. Here is the sample code:

using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Presentation.Shapes;
using Microsoft.SPOT.Touch;

using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;

namespace TidisVideoTest
{
    public partial class Program
    {
        delegate void SetTextCallback(string text);
        
        //********************************************************************************
        // ProgramStarted Declarations
        //********************************************************************************


        public static Joystick.Position JSPosition = new Joystick.Position();

        public static string[] TidisMenu1 = new string[12];
        public static string[] TidisMenu2 = new string[12];
        public static string[] TidisMenu3 = new string[12];
        public string[] CurrentMenu = new string[12];
        public string[] TimerMenu = new string[2] { "Timer#1 >  ", "< Timer#2" };  
        public string[] TimerTypeMenu = new string[5] {"None >                             ", "< TAG CP520 >                      ", 
                                                       "< TAG HL440 >                      ", "< ALGE/CP705 Display >",
                                                       "< Pass Through                     " };
        public string[] BaudMenu = new string[5] { "2400 >    ", "< 9600 >   ", "< 19200 > ", "< 57600 > ", "< 115200 " };
        public string[] DisplayTypeMenu = new string[6] {"One Line - Red >         ", "< One Line- Green > ", "< One Line - R/G >       ", 
                                                         "< Two Line - Red >       ", "< Two Line - Green >", "< Two Line R/G >         "};
        public string[] DisplayMethodMenu = new string[3] { "Single Result >   ", "< Rotate Two >   ", 
                                                            "< Info straight" };
        public int[] MenuLineLoc1 = new int[12] { 0, 13, 21, 34, 47, 60, 73, 81, 94, 107, 120, 133 };
        public int[] MenuLineLoc2 = new int[12] { 0, 13, 26, 39, 52, 65, 78, 91, 104, 117, 130, 143 };
        public int[] MenuLineLoc3 = new int[12] { 0, 13, 33, 53, 73, 93, 113, 133, 133, 133, 133, 133 };
        public int[] CurrentLineLoc = new int[12];
        public Color LineColor1 = Colors.Green;
        public Color LineColor2 = Colors.Yellow;
        public Color CurrentColor = Colors.White;
        public Font LineFont1 = Resources.GetFont(Resources.FontResources.calibril12);

        public string[] StoredParameters = new string[7] { "1", "1", "0", "4", "0", "0", "1" };
        public static int[] CurrentParameters = new int[7];
        public bool SetParameters = false;

        public int menuline = 0;
        public int menupage = 1;
        public int submenu1index = 0;
        public int submenu2index = 1;
        public int submenu3index = 0;
        public int submenu4index = 4;
        public int submenu5index = 0;
        public int submenu6index = 1;


        //********************************************************************************
        //********************************************************************************
        // ProgramStarted Portion of Class
        //********************************************************************************
        //********************************************************************************

        // This method is run when the mainboard is powered up or reset.   

        void ProgramStarted()
        {
            SetTidisMenu(TidisMenu1, TidisMenu2, TidisMenu3,
                            TimerMenu, TimerTypeMenu, BaudMenu,
                            DisplayTypeMenu, DisplayMethodMenu, CurrentParameters);
            MenuPageControl();
        }

        public void MenuPageControl()
        {
            if (menupage == 1)
            {
                TidisMenu1.CopyTo(CurrentMenu, 0);
                MenuLineLoc1.CopyTo(CurrentLineLoc, 0);
            }

            if (menupage == 2)
            {
                TidisMenu2[3] = TimerTypeMenu[CurrentParameters[0]];
                TidisMenu2[4] = BaudMenu[CurrentParameters[1]];
                TidisMenu2[7] = DisplayTypeMenu[CurrentParameters[2]];
                TidisMenu2[8] = BaudMenu[CurrentParameters[3]];
                TidisMenu2[11] = DisplayMethodMenu[CurrentParameters[4]];
                TidisMenu2.CopyTo(CurrentMenu, 0);
                MenuLineLoc2.CopyTo(CurrentLineLoc, 0);
            }
            if (menupage == 3)
            {
                TidisMenu3.CopyTo(CurrentMenu, 0);
                MenuLineLoc3.CopyTo(CurrentLineLoc, 0);
            }
            MenuPageDisplay();
            if (menupage == 3) { TidisP10(); }
        }

        public void MenuPageDisplay()
        {
            displayN18.Clear();

            int Menuindex = 0;
            int lineloc;
            string linemessage;
            while (Menuindex < 12)
            {
                lineloc = CurrentLineLoc[Menuindex];
                linemessage = CurrentMenu[Menuindex];
                if (menuline == Menuindex) { CurrentColor = LineColor2; } else { CurrentColor = LineColor1; }
                RenderLine(linemessage, lineloc, LineFont1, CurrentColor, displayN18);
                Menuindex++;
            }
        }

        public void DisplayActiveLine()
        {
            CurrentColor = LineColor2;
            RenderLine(CurrentMenu[menuline], CurrentLineLoc[menuline], LineFont1, CurrentColor, displayN18);
        }

        public void DisplayInactiveLine()
        {
            CurrentColor = LineColor1;
            RenderLine(CurrentMenu[menuline], CurrentLineLoc[menuline], LineFont1, CurrentColor, displayN18);
        }

        public void DisplayTimerInfo()
        {
            // display timer#1 info
            if (submenu1index == 0)
            {
                menuline = 3;
                CurrentMenu[3] = TimerTypeMenu[CurrentParameters[0]];
                DisplayInactiveLine();
                CurrentMenu[4] = BaudMenu[CurrentParameters[1]];
                menuline = 4;
                DisplayInactiveLine();
                menuline = 2;
            }

            // display timer#2 info
            if (submenu1index == 1)
            {
                menuline = 3;
                CurrentMenu[3] = TimerTypeMenu[CurrentParameters[5]];
                DisplayInactiveLine();
                CurrentMenu[4] = BaudMenu[CurrentParameters[6]];
                menuline = 4;
                DisplayInactiveLine();
                menuline = 2;
            }
        }

        public void TidisP10()
        {
        }

        public void SetTidisMenu(string[] TidisMenu1, string[] TidisMenu2, string[] TidisMenu3,
                         string[] TimerMenu, string[] TimerTypeMenu, string[] BaudMenu,
                         string[] DisplayTypeMenu, string[] DisplayMethodMenu, int[] CurrentParameters)
        {
            // Set Main Tidis Menu

            TidisMenu1[0] = "Timer Display System >";
            TidisMenu1[1] = " ";
            TidisMenu1[2] = "Instructions:  On top line";
            TidisMenu1[3] = "move joystick right or";
            TidisMenu1[4] = "left to change page.";
            TidisMenu1[5] = "Pages: Instruct, Set, Time";
            TidisMenu1[6] = " ";
            TidisMenu1[7] = "Move joystick up or down";
            TidisMenu1[8] = "to change line. Indicators";
            TidisMenu1[9] = "'>' & '<' mean move joy-";
            TidisMenu1[10] = "stick right or left to";
            TidisMenu1[11] = "change setting or timer#.";

            TidisMenu2[0] = "< Tidis Settings >";
            TidisMenu2[1] = "   -----";
            TidisMenu2[2] = TimerMenu[0];
            TidisMenu2[3] = TimerTypeMenu[CurrentParameters[0]];
            TidisMenu2[4] = BaudMenu[CurrentParameters[1]];
            TidisMenu2[5] = "   -----";
            TidisMenu2[6] = "Display";
            TidisMenu2[7] = DisplayTypeMenu[CurrentParameters[2]];
            TidisMenu2[8] = BaudMenu[CurrentParameters[3]];
            TidisMenu2[9] = "   -----";
            TidisMenu2[10] = "Display Method";
            TidisMenu2[11] = DisplayMethodMenu[CurrentParameters[4]];

            TidisMenu3[0] = "Tidis Timing Page";
            TidisMenu3[1] = " ";
            TidisMenu3[2] = " ";
            TidisMenu3[3] = " ";
            TidisMenu3[4] = " ";
            TidisMenu3[5] = " ";
            TidisMenu3[6] = " ";
            TidisMenu3[7] = " ";
            TidisMenu3[8] = " ";
            TidisMenu3[9] = " ";
            TidisMenu3[10] = " ";
            TidisMenu3[11] = " ";
        }


        public void RenderLine(string message, int lineloc, Font LineFont, Color LineColor, DisplayN18 displayN18)
        {
            if ((message != null) && (message != ""))
            {
                int width;
                int height;
                LineFont.ComputeExtent(message, out width, out height);
                Bitmap bmp = new Bitmap(width, height);
                bmp.DrawText(message, LineFont, LineColor, 0, 0);
                // Render the bitmap to the screen
                displayN18.Draw(bmp, 0, lineloc);
            }
        }

    }
}

Since there is no joystick code, only menu1 is displayed

Please try your fonts with the emulator, without any hardware.

I never noticed this!

@ Gus - Could not run emulator - GHI.Hardware.pdb not loaded

Sorry I am not an IT expert (actually a CPA) thus I don’t know how to resolve this. I noticed that the directory has GHI.Hardware.pdbx file. I don’t know what the difference is?

You should not use any of the GHI libraries. Just take a look at the netmf book on the support page please.

@ Gus - Found solution, now using

displayN18.SimpleGraphics.DisplayImage(bmp, 0, lineloc);
            

instead of

displayN18.Draw(bmp, 0, lineloc);

Everything works.

@ CDR114 - The issue appears to be somewhere in NETMF’s font rendering on bitmaps that are sized to fit the message exactly when using custom fonts and certain combinations of characters. The built in NinaB and small fonts do not appear to have this issue.

When calling Bitmap.DrawText("1 ", font, Color.White, 0, 0); where font is Calibri Light 12 pt and Bitmap is exactly big enough to hold "1 ", the data that gets drawn is corrupt. So the image you see when you call displayN18.Draw is correct, it’s just the bitmap given to it is wrong. You can see the corruption by passing your bitmap to the function below. It renders it as a string you can view in the debugger.

Interestingly, when you call SimpleGraphics.Paint, there is another bitmap internally for the entire screen and eventually internalBitmap.DrawImage(0, 0, bitmapToDraw, 0, 0, bitmapToDraw.Width, bitmapToDraw.Height) gets called. That call undoes the any corruption that is present.

There are two ways to work around this. Instead of working with bitmaps directly, you can use the SimpleGraphics interface that Gadgeteer provides for you. It provides most of the same functionality in with a slightly easier to use API. You could also create a bitmap that represents the entire screen and draw your lines to that instead of using precisely sized bitmaps for each line. The last snippet below shows two alternatives.


public string Render(Bitmap bmp) {
    var builder = new StringBuilder();
    var buffer = new ushort[bmp.Width * bmp.Height];

    GHI.Utilities.Bitmaps.GetBuffer(bmp, buffer);

    for (var y = 0; y < bmp.Height; y++) {
        for (var x = 0; x < bmp.Width; x++)
            builder.Append(buffer[y * bmp.Width + x] != 0 ? 'X' : ' ');

        builder.Append("\r\n");
    }

    return builder.ToString();
}


private Bitmap scn = new Bitmap(128, 160);

public void RenderLine(string message, int lineloc, Font LineFont, Color LineColor, DisplayN18 displayN18) {
    if ((message != null) && (message != "")) {
        scn.DrawText(message, LineFont, LineColor, 0, lineloc);
        displayN18.Draw(scn, 0, 0);
    }
}

public void RenderLine(string message, int lineloc, Font LineFont, Color LineColor, DisplayN18 displayN18) {
    if ((message != null) && (message != "")) {
        displayN18.SimpleGraphics.DisplayText(message, LineFont, LineColor, 0, lineloc);
    }
}

1 Like