Const byte[] in C#

I’m working on creating a lightweight managed driver for monochrome LCD’s on a Panda II. I’d like to keep it 100% managed for now (don’t RLP flame me please :))

To put a font on the screen you basically need to bang out some bytes from a predefined “contant byte array” to the display.

On a traditional C platform such an array looks like this:


const Terminal6x8 as byte[672] = (
        $04, $00, $00, $00, $00, $00, $00,       ' Code for char  
        $05, $00, $00, $06, $5F, $06, $00,       ' Code for char !
        $06, $00, $07, $03, $00, $07, $03,       ' Code for char "
        $06, $00, $24, $7E, $24, $7E, $24,       ' Code for char #
        $05, $00, $24, $2B, $6A, $12, $00,       ' Code for char $
        $06, $00, $63, $13, $08, $64, $63,       ' Code for char %
        $06, $00, $36, $49, $56, $20, $50,       ' Code for char &
        $04, $00, $00, $07, $03, $00, $00,       ' Code for char '
        $04, $00, $00, $3E, $41, $00, $00,       ' Code for char (
        $04, $00, $00, $41, $3E, $00, $00,       ' Code for char )
        $06, $00, $08, $3E, $1C, $3E, $08,       ' Code for char *
        $06, $00, $08, $08, $3E, $08, $08,       ' Code for char +
        $04, $00, $00, $E0, $60, $00, $00,       ' Code for char ,
        $06, $00, $08, $08, $08, $08, $08,       ' Code for char -
        $04, $00, $00, $60, $60, $00, $00,       ' Code for char .
        $06, $00, $20, $10, $08, $04, $02,       ' Code for char /
        $06, $00, $3E, $51, $49, $45, $3E,       ' Code for char 0
        $05, $00, $00, $42, $7F, $40, $00,       ' Code for char 1
        $06, $00, $62, $51, $49, $49, $46,       ' Code for char 2
        $06, $00, $22, $49, $49, $49, $36,       ' Code for char 3
        $06, $00, $18, $14, $12, $7F, $10,       ' Code for char 4
        $06, $00, $2F, $49, $49, $49, $31,       ' Code for char 5
        $06, $00, $3C, $4A, $49, $49, $30,       ' Code for char 6
        $06, $00, $01, $71, $09, $05, $03,       ' Code for char 7
        $06, $00, $36, $49, $49, $49, $36,       ' Code for char 8
        $06, $00, $06, $49, $49, $29, $1E,       ' Code for char 9
        )

This is very handy because 1. it can move very fast from the array to the display and 2. the font definitions are stored in the program flash - and not precious RAM on the device.

Is there something similar I can do in C#? The example above is not supported in C#.

I am now considering storing the byte arrays as raw binary objects as a Resource.
Can I read individual bytes out of a resource file without first putting them into an array in memory? In other words, can I transfer straight from resource file to the display?

I see on the devices that support the Bitmap object, you can use Tiny Fonts. This is unfortunately not available on the Panda. Does anyone know if the binary format of these Tiny Fonts are available anywhere so I can implement a parser myself?

This is BASIC not C code :slight_smile:

I have requested this from Microsoft years ago and it finally made it to NETMF 4.2, available Q1/2012

Just copy what you need from our drivers http://code.tinyclr.com/project/277/fez-touch-lcd-component/

static byte[]  Terminal6x8 = new byte[672]{
        $04, $00, $00, $00, $00, $00, $00,       //Code for char  
        $05, $00, $00, $06, $5F, $06, $00,       //Code for char !
        $06, $00, $07, $03, $00, $07, $03,       //Code for char "
        $06, $00, $24, $7E, $24, $7E, $24,       //Code for char #
        $05, $00, $24, $2B, $6A, $12, $00,       //Code for char $
        $06, $00, $63, $13, $08, $64, $63,       //Code for char %
        $06, $00, $36, $49, $56, $20, $50,       //Code for char &
        $04, $00, $00, $07, $03, $00, $00,       //Code for char '
        $04, $00, $00, $3E, $41, $00, $00,       //Code for char (
        $04, $00, $00, $41, $3E, $00, $00,       //Code for char )
        $06, $00, $08, $3E, $1C, $3E, $08,       //Code for char *
        $06, $00, $08, $08, $3E, $08, $08,       //Code for char +
        $04, $00, $00, $E0, $60, $00, $00,       //Code for char ,
        $06, $00, $08, $08, $08, $08, $08,       //Code for char -
        $04, $00, $00, $60, $60, $00, $00,       //Code for char .
        $06, $00, $20, $10, $08, $04, $02,       //Code for char /
        $06, $00, $3E, $51, $49, $45, $3E,       //Code for char 0
        $05, $00, $00, $42, $7F, $40, $00,       //Code for char 1
        $06, $00, $62, $51, $49, $49, $46,       //Code for char 2
        $06, $00, $22, $49, $49, $49, $36,       //Code for char 3
        $06, $00, $18, $14, $12, $7F, $10,       //Code for char 4
        $06, $00, $2F, $49, $49, $49, $31,       //Code for char 5
        $06, $00, $3C, $4A, $49, $49, $30,       //Code for char 6
        $06, $00, $01, $71, $09, $05, $03,       //Code for char 7
        $06, $00, $36, $49, $49, $49, $36,       //Code for char 8
        $06, $00, $06, $49, $49, $29, $1E,       //Code for char 9
        };

Well spotted Gus! Yes, I copied the Basic version by mistake. The tool generates stubs for Basic, Pascal and C… pretty cool:

Anyway, I used the examples from Fez Touch and other drivers on the Code site. All of them use an array in memory, like this:


static private byte[] font = new byte[]{                      /*--  show:     --*/            0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,             /*--  show:  !  --*/            0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00,             /*--  show:  "  --*/            0x00,0x28,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,             /*--  show:  #  --*/            0x00,0x00,0x28,0x28,0xFC,0x28,0x50,0xFC,0x50,0x50,0x00,0x00
}

This can run into several K for larger fonts - and at this stage every K counts for the rest of the app.

I was just wondering if there was a more efficient way.

But the difference in memory foot print between

static int[] 

and

const int 

should be marginal for bigger arrays. It is only for the compiler that a constant can not be changed, whereas a static can be modified: only it should use the same memory again.

You can not use const with something that uses an initializer.

Have a look the two projects I published on TinyCLR Code at:

[url]http://code.tinyclr.com/project/364/fez-touch-font-generator/[/url]
[url]http://code.tinyclr.com/project/363/fez-touch-driver-ver-23/[/url]

My generated font class is shown below. Notice that I used a const string, which is allowed, and will be placed into code space. I convert this string to a char[] array at runtime and manipulate the bytes in order to get the actual bitmap for each character. One of the problems I ran into is that NETMF does not allow a NULL (zero value) character to be embedded in the string. If you place one in the string it will be terminated, so I had to hardcode a 1 into the most significant bit.


public class FontCourierNew10 : FEZ_Components.FEZTouch.Font
{
	// CONSTRUCTOR
	public FontCourierNew10()
	{
		// set properties
		this.avgWidth = 8;
		this.maxWidth = 8;
		this.height = 16;
		this.startChar = ' ';
		this.endChar = '~';

		// attach string pointers to const strings
		this.charDescriptors = constCourierNew10Descriptors;
		this.charBitmaps = constCourierNew10Bitmaps;
	}

	// character descriptor array
	public const string constCourierNew10Descriptors =
		//  [width][height][offset][length]   [character]
		"\u8008\u8010\u8000\u8001" +    // [ ]
		"\u8008\u8010\u8001\u8007" +    // [!]
		"\u8008\u8010\u8008\u8005" +    // ["]
		"\u8008\u8010\u800D\u8007" +    // [#]
		"\u8008\u8010\u8014\u8007" +    // [$]

		// and continues defining descriptors for all characters...

	// character bitmap array
	public const string constCourierNew10Bitmaps =
		"\u8000" +
		"\u8000\u8000\uC040\u8080\u8101\u8000\u8004" +
		"\u8000\u8000\uB1B0\uA123\u8002" +
		"\u8000\u9000\u9121\uA3F1\uE242\uC48F\u8484" +
		"\u8000\uA000\u90E0\uC021\uC201\u8384\u8404" +
		"\u8000\u8000\uA810\u8020\u80E3\u8502\u8004" +
		"\u8000\u8000\uC000\uC043\uC180\u848A\u801E" +

That is a neat trick with the string! I’ll definately use it in future projects - especially because one can do this sort of thing with such a string constant:


      byte octet = (byte)stringconstant[i]

and


        foreach(char ch in stringconstant)
        {
            byte octet = (byte)ch;
        }

That is a lot like a “const byte[]” and will be very useful for things like packet headers in comms packets or larg(ish) byte arrays that should rather live in flash than RAM.

I digress…

I’ve tried the following two techniques and both also work:

This one stores the bitmaps in program space and takes a slight performance hit for filling the byte array. The GC can collect these easily so RAM footprint is low.


        private byte[] GetCharBitmap(char ch)
        {
            switch (ch)
            {
                case '0': return new byte[5] { 0x3e, 0x51, 0x49, 0x45, 0x3e };
                case '1': return new byte[5] { 0x00, 0x42, 0x7f, 0x40, 0x00 };
                case '2': return new byte[5] { 0x42, 0x61, 0x51, 0x49, 0x46 };
                case '3': return new byte[5] { 0x21, 0x41, 0x45, 0x4b, 0x31 };
                case '4': return new byte[5] { 0x18, 0x14, 0x12, 0x7f, 0x10 };
                case '5': return new byte[5] { 0x27, 0x45, 0x45, 0x45, 0x39 };
                case '6': return new byte[5] { 0x3c, 0x4a, 0x49, 0x49, 0x30 };
                case '7': return new byte[5] { 0x01, 0x71, 0x09, 0x05, 0x03 };
                case '8': return new byte[5] { 0x36, 0x49, 0x49, 0x49, 0x36 };
                case '9': return new byte[5] { 0x06, 0x49, 0x49, 0x29, 0x1e };
                default: return new byte[5] {0xff,0xff,0xff,0xff,0xff};
            }
        }

This one is more efficient, but is limited to 8 bytes to describe the font. It is very easy to generate the code with a font generator.


        private UInt64 GetCharBitmap(char ch)
        {
            switch (ch)
            {
                case '0': return 0x3e5149453e;
                case '1': return 0x00427f4000;
                case '2': return 0x4261514946;
                case '3': return 0x2141454b31;
                case '4': return 0x1814127f10;
                case '5': return 0x2745454539;
                case '6': return 0x3c4a494930;
                case '7': return 0x0171090503;
                case '8': return 0x3649494936;
                case '9': return 0x064949291e;
                default: return 0xFFFFFFFFFF;
            }
        }

I then just shift the bytes out to the display.

My next task is to test the total memory footprint and performance of each and see which one wins!

Thanks for all the help so far.

I like your two solutions also. I will definitely put those to use in some future project.
Please let us know the results of your tests.
Thanks.