EV3 Firmware download via BricxCC

Discussion specific to NXT-G, NXC, NBC, RobotC, Lejos, and more.
joto1000
Posts: 4
Joined: 02 Oct 2013, 08:09

Re: EV3 Firmware download via BricxCC

Post by joto1000 »

Hello, I'm new with EV3.

What do I have to do to get a C Code running on EV3?
I followed the 9 steps mentioned above, but I don't get it running on my EV3.

What should I do with the files from the lms_api? Do I have to link or compile them? And how can I do this?

Can anybody help me ;) ?
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: EV3 Firmware download via BricxCC

Post by HaWe »

.@totokan:
so after 1-9
then one may drop 10-19
20 is missing...
and then continue from 21-34, right?

man, that's enough guide to sink a ship...

BTW:
maybe it's a good advice to copy and save the current BCC installation folder in the windows programs directory by a different name in order to be able to quickly reinstall anything safely if one or the other thing (or, more likely: one AND the other thing ;) ) once went wrong.
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: EV3 Firmware download via BricxCC

Post by HaWe »

I also followed all instructions but can't download and run, I get errors like
ev3_lcd.o:(.data+0x0): multiple definition of `PixelTab'
c:\Temp\cc6HjJOD.o:(.data+0x0): first defined here
ev3_lcd.o:(.data+0x8): multiple definition of `UnPixelTab'
c:\Temp\cc6HjJOD.o:(.data+0x8): first defined here
ev3_lcd.o: In function `WriteToLcdDevice':
ev3_lcd.c:(.text+0x0): multiple definition of `WriteToLcdDevice'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x0): first defined here
ev3_lcd.o:(.data+0x1608): multiple definition of `FontInfo'
c:\Temp\cc6HjJOD.o:(.data+0x1608): first defined here
ev3_lcd.o: In function `dLcdGetFontWidth':
ev3_lcd.c:(.text+0x80): multiple definition of `dLcdGetFontWidth'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x80): first defined here
ev3_lcd.o: In function `dLcdGetFontHeight':
ev3_lcd.c:(.text+0xd0): multiple definition of `dLcdGetFontHeight'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0xd0): first defined here
ev3_lcd.o:(.data+0x24e8): multiple definition of `IconInfo'
c:\Temp\cc6HjJOD.o:(.data+0x24e8): first defined here
ev3_lcd.o: In function `dLcdGetIconBits':
ev3_lcd.c:(.text+0x120): multiple definition of `dLcdGetIconBits'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x120): first defined here
ev3_lcd.o: In function `dLcdGetIconWidth':
ev3_lcd.c:(.text+0x168): multiple definition of `dLcdGetIconWidth'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x168): first defined here
ev3_lcd.o: In function `dLcdGetIconHeight':
ev3_lcd.c:(.text+0x1c0): multiple definition of `dLcdGetIconHeight'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x1c0): first defined here
ev3_lcd.o: In function `dLcdGetNumIcons':
ev3_lcd.c:(.text+0x210): multiple definition of `dLcdGetNumIcons'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x210): first defined here
ev3_lcd.o: In function `frameBufferToLcd':
ev3_lcd.c:(.text+0x2a0): multiple definition of `frameBufferToLcd'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x2a0): first defined here
ev3_lcd.o: In function `lcdToFrameBuffer':
ev3_lcd.c:(.text+0x5cc): multiple definition of `lcdToFrameBuffer'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x5cc): first defined here
ev3_lcd.o: In function `doUpdateScreen':
ev3_lcd.c:(.text+0x8fc): multiple definition of `doUpdateScreen'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x8fc): first defined here
ev3_lcd.o: In function `LcdUpdateHandler':
ev3_lcd.c:(.text+0x978): multiple definition of `LcdUpdateHandler'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x978): first defined here
ev3_lcd.o: In function `LcdCloseDevices':
ev3_lcd.c:(.text+0x9a8): multiple definition of `LcdCloseDevices'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x9a8): first defined here
ev3_lcd.o: In function `LcdInitialized':
ev3_lcd.c:(.text+0xc18): multiple definition of `LcdInitialized'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0xc18): first defined here
ev3_lcd.o: In function `LcdInit':
ev3_lcd.c:(.text+0xa2c): multiple definition of `LcdInit'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0xa2c): first defined here
ev3_lcd.o: In function `LcdOpen':
ev3_lcd.c:(.text+0xb78): multiple definition of `LcdOpen'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0xb78): first defined here
ev3_lcd.o: In function `LcdClose':
ev3_lcd.c:(.text+0xb94): multiple definition of `LcdClose'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0xb94): first defined here
ev3_lcd.o: In function `LcdExit':
ev3_lcd.c:(.text+0xbb0): multiple definition of `LcdExit'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0xbb0): first defined here
ev3_lcd.o: In function `dLcdDrawPixel':
ev3_lcd.c:(.text+0xc74): multiple definition of `dLcdDrawPixel'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0xc74): first defined here
ev3_lcd.o: In function `dLcdReadPixel':
ev3_lcd.c:(.text+0xe8c): multiple definition of `dLcdReadPixel'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0xe8c): first defined here
ev3_lcd.o: In function `dLcdDrawChar':
ev3_lcd.c:(.text+0xf80): multiple definition of `dLcdDrawChar'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0xf80): first defined here
ev3_lcd.o: In function `dLcdDrawText':
ev3_lcd.c:(.text+0x15d4): multiple definition of `dLcdDrawText'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x15d4): first defined here
ev3_lcd.o: In function `dLcdDrawPicture':
ev3_lcd.c:(.text+0x16c8): multiple definition of `dLcdDrawPicture'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x16c8): first defined here
ev3_lcd.o: In function `dLcdDrawIcon':
ev3_lcd.c:(.text+0x188c): multiple definition of `dLcdDrawIcon'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x188c): first defined here
ev3_lcd.o: In function `dLcdGetBitmapSize':
ev3_lcd.c:(.text+0x1994): multiple definition of `dLcdGetBitmapSize'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x1994): first defined here
ev3_lcd.o: In function `dLcdDrawBitmap':
ev3_lcd.c:(.text+0x1a08): multiple definition of `dLcdDrawBitmap'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x1a08): first defined here
ev3_lcd.o: In function `LcdRefresh':
ev3_lcd.c:(.text+0x1e28): multiple definition of `LcdRefresh'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x1e28): first defined here
ev3_lcd.o: In function `LcdSetAutoRefresh':
ev3_lcd.c:(.text+0x1e50): multiple definition of `LcdSetAutoRefresh'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x1e50): first defined here
ev3_lcd.o: In function `LcdUpdate':
ev3_lcd.c:(.text+0x1e80): multiple definition of `LcdUpdate'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x1e80): first defined here
ev3_lcd.o: In function `LcdClean':
ev3_lcd.c:(.text+0x1edc): multiple definition of `LcdClean'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x1edc): first defined here
ev3_lcd.o: In function `LcdClearDisplay':
ev3_lcd.c:(.text+0x1f58): multiple definition of `LcdClearDisplay'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x1f58): first defined here
ev3_lcd.o: In function `LcdScroll':
ev3_lcd.c:(.text+0x1f78): multiple definition of `LcdScroll'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x1f78): first defined here
ev3_lcd.o: In function `LcdSelectFont':
ev3_lcd.c:(.text+0x2128): multiple definition of `LcdSelectFont'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x2128): first defined here
ev3_lcd.o: In function `LcdGetDisplay':
ev3_lcd.c:(.text+0x21a4): multiple definition of `LcdGetDisplay'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x21a4): first defined here
ev3_lcd.o: In function `LcdGetFrameBuffer':
ev3_lcd.c:(.text+0x21f4): multiple definition of `LcdGetFrameBuffer'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x21f4): first defined here
ev3_lcd.o: In function `reverse_bits':
ev3_lcd.c:(.text+0x2274): multiple definition of `reverse_bits'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x2274): first defined here
ev3_lcd.o: In function `_lcdWriteBytesToFile':
ev3_lcd.c:(.text+0x22a8): multiple definition of `_lcdWriteBytesToFile'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x22a8): first defined here
ev3_lcd.o: In function `LcdWriteDisplayToFile':
ev3_lcd.c:(.text+0x2874): multiple definition of `LcdWriteDisplayToFile'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x2874): first defined here
ev3_lcd.o: In function `LcdWriteFrameBufferToFile':
ev3_lcd.c:(.text+0x28d0): multiple definition of `LcdWriteFrameBufferToFile'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x28d0): first defined here
ev3_lcd.o: In function `LcdText':
ev3_lcd.c:(.text+0x292c): multiple definition of `LcdText'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x292c): first defined here
ev3_lcd.o: In function `LcdIcon':
ev3_lcd.c:(.text+0x29d0): multiple definition of `LcdIcon'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x29d0): first defined here
ev3_lcd.o: In function `LcdBmpFile':
ev3_lcd.c:(.text+0x2a78): multiple definition of `LcdBmpFile'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x2a78): first defined here
ev3_lcd.o: In function `LcdPicture':
ev3_lcd.c:(.text+0x2b88): multiple definition of `LcdPicture'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x2b88): first defined here
ev3_lcd.o: In function `LcdFillWindow':
ev3_lcd.c:(.text+0x2c20): multiple definition of `LcdFillWindow'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x2c20): first defined here
ev3_lcd.o: In function `DisplayLineHeight':
ev3_lcd.c:(.text+0x2df0): multiple definition of `DisplayLineHeight'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x2df0): first defined here
ev3_lcd.o: In function `DisplayEraseLine':
ev3_lcd.c:(.text+0x2e28): multiple definition of `DisplayEraseLine'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x2e28): first defined here
ev3_lcd.o: In function `DisplayErase':
ev3_lcd.c:(.text+0x2e9c): multiple definition of `DisplayErase'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x2e9c): first defined here
ev3_lcd.o: In function `DisplaySetPixel':
ev3_lcd.c:(.text+0x2ed0): multiple definition of `DisplaySetPixel'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x2ed0): first defined here
ev3_lcd.o: In function `DisplayClrPixel':
ev3_lcd.c:(.text+0x2fbc): multiple definition of `DisplayClrPixel'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x2fbc): first defined here
ev3_lcd.o: In function `DisplayXorPixel':
ev3_lcd.c:(.text+0x30b0): multiple definition of `DisplayXorPixel'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x30b0): first defined here
ev3_lcd.o:(.data+0x2524): multiple definition of `Masks'
c:\Temp\cc6HjJOD.o:(.data+0x2524): first defined here
ev3_lcd.o: In function `DisplayFillScreen':
ev3_lcd.c:(.text+0x319c): multiple definition of `DisplayFillScreen'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x319c): first defined here
ev3_lcd.o: In function `DisplayLineX':
ev3_lcd.c:(.text+0x3470): multiple definition of `DisplayLineX'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x3470): first defined here
ev3_lcd.o: In function `DisplayLineY':
ev3_lcd.c:(.text+0x3680): multiple definition of `DisplayLineY'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x3680): first defined here
ev3_lcd.o: In function `DisplayFrame':
ev3_lcd.c:(.text+0x382c): multiple definition of `DisplayFrame'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x382c): first defined here
ev3_lcd.o: In function `DisplayDraw':
ev3_lcd.c:(.text+0x393c): multiple definition of `DisplayDraw'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x393c): first defined here
ev3_lcd.o: In function `CmdResolveDrawingMode':
ev3_lcd.c:(.text+0x3ae0): multiple definition of `CmdResolveDrawingMode'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x3ae0): first defined here
ev3_lcd.o: In function `CmdSetPixel':
ev3_lcd.c:(.text+0x3c08): multiple definition of `CmdSetPixel'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x3c08): first defined here
ev3_lcd.o: In function `CmdDrawLine':
ev3_lcd.c:(.text+0x3c98): multiple definition of `CmdDrawLine'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x3c98): first defined here
ev3_lcd.o: In function `CmdDrawRect':
ev3_lcd.c:(.text+0x4234): multiple definition of `CmdDrawRect'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x4234): first defined here
ev3_lcd.o: In function `CmdDrawEllipse':
ev3_lcd.c:(.text+0x44e4): multiple definition of `CmdDrawEllipse'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x44e4): first defined here
ev3_lcd.o: In function `CmdDrawCircle':
ev3_lcd.c:(.text+0x4d2c): multiple definition of `CmdDrawCircle'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x4d2c): first defined here
ev3_lcd.o: In function `CircleOutEx':
ev3_lcd.c:(.text+0x4dc4): multiple definition of `CircleOutEx'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x4dc4): first defined here
ev3_lcd.o: In function `LineOutEx':
ev3_lcd.c:(.text+0x4e74): multiple definition of `LineOutEx'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x4e74): first defined here
ev3_lcd.o: In function `PointOutEx':
ev3_lcd.c:(.text+0x4f18): multiple definition of `PointOutEx'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x4f18): first defined here
ev3_lcd.o: In function `RectOutEx':
ev3_lcd.c:(.text+0x4fb0): multiple definition of `RectOutEx'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x4fb0): first defined here
ev3_lcd.o: In function `TextOutEx':
ev3_lcd.c:(.text+0x505c): multiple definition of `TextOutEx'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x505c): first defined here
ev3_lcd.o: In function `NumOutEx':
ev3_lcd.c:(.text+0x50b4): multiple definition of `NumOutEx'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x50b4): first defined here
ev3_lcd.o: In function `EllipseOutEx':
ev3_lcd.c:(.text+0x510c): multiple definition of `EllipseOutEx'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x510c): first defined here
ev3_lcd.o: In function `PolyOutEx':
ev3_lcd.c:(.text+0x51fc): multiple definition of `PolyOutEx'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x51fc): first defined here
ev3_lcd.o: In function `GraphicOutEx':
ev3_lcd.c:(.text+0x5224): multiple definition of `GraphicOutEx'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x5224): first defined here
ev3_lcd.o: In function `GraphicArrayOutEx':
ev3_lcd.c:(.text+0x5254): multiple definition of `GraphicArrayOutEx'
c:\Temp\cc6HjJOD.o:ev3_lcd.c:(.text+0x5254): first defined here
c:/cslite/bin/../arm-none-linux-gnueabi/libc/usr/lib/crt1.o: In function `_start':
init.c:(.text+0x30): undefined reference to `main'
collect2: ld returned 1 exit status
make: *** [ev3_lcd] Error 1

Code: Select all

#include "ev3_lcd.h"
#include "ev3_timer.h"
I included the .h files also into the project manager
Note: the project manager should show also all .h files automatically!




Note:
a short description about what the example codes are supposed to do would be appreciated!

Code: Select all

/*
/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * The Initial Developer of this code is John Hansen.
 * Portions created by John Hansen are Copyright (C) 2009-2013 John Hansen.
 * All Rights Reserved.
 *
 */

#include "ev3_lcd.h"
#include "ev3_timer.h"

#define DRAW_PIXELS_SET    0x00 //Basic options for pixel, line and shape drawing.
#define DRAW_PIXELS_CLEAR  0x01
#define DRAW_PIXELS_INVERT 0x02

#define DRAW_SHAPE_HOLLOW 0x00 //Extra options for shape drawing.
#define DRAW_SHAPE_FILLED 0x01

#define DRAW_BITMAP_PLAIN  0x00
#define DRAW_BITMAP_INVERT 0x01

#define DRAW_LOGICAL_COPY 0x00
#define DRAW_LOGICAL_AND  0x01
#define DRAW_LOGICAL_OR   0x02
#define DRAW_LOGICAL_XOR  0x03

#define LCD_MEM_WIDTH 60 // width of HW Buffer in bytes
#define LCD_BUFFER_LENGTH (LCD_MEM_WIDTH*LCD_HEIGHT)

#define ABS(a)    (((a)<0) ? -(a) : (a))
#define SGN(a)    (((a)<0) ? -1 : 1)
#define MAX(a,b)    (((a>b) ? (a) : (b)))
#define MIN(a,b)    (((a<b) ? (a) : (b)))

byte hwBuffer[LCD_BUFFER_LENGTH];

byte PixelTab[] = {
    0x00, // 000 00000000
    0xE0, // 001 11100000
    0x1C, // 010 00011100
    0xFC, // 011 11111100
    0x03, // 100 00000011
    0xE3, // 101 11100011
    0x1F, // 110 00011111
    0xFF  // 111 11111111
  };

byte UnPixelTab[] = {
// 0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
   0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 6, // 1
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
   1, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 7  // F
  };
  
typedef struct {
  bool Dirty;
  int DispFile;
  byte *pFB0;
  byte displayBuf[LCD_BUFFER_SIZE];
  byte *font;
  byte *pLcd;
  byte currentFont;
  bool autoRefresh;
} LCDGlobals;

LCDGlobals LCDInstance;

int WriteToLcdDevice(char * bytes, int num_bytes)
{
  int result = -1;
  if (LCDInstance.DispFile >= 0)
  {
    // for some reason write is not returning num_bytes -
    // it usually returns zero
    result = write(LCDInstance.DispFile, bytes, num_bytes);
    if (result >= 0)
      return num_bytes;
  }
  return result;
}

typedef struct
{
  const char  *pFontBits;           // Pointer to start of font bitmap
  const short FontHeight;           // Character height (all inclusive)
  const short FontWidth;            // Character width (all inclusive)
  const short FontHorz;             // Number of horizontal character in font bitmap
  const char  FontFirst;            // First character supported
  const char  FontLast;             // Last character supported
} FONTINFO;

#include "normal_font.xbm"
#include "small_font.xbm"
#include "large_font.xbm"
#include "tiny_font.xbm"

FONTINFO FontInfo[] =
{
  [FONTTYPE_NORMAL] = {
                    .pFontBits    = (const char*)normal_font_bits,
                    .FontHeight   = 9,
                    .FontWidth    = 8,
                    .FontHorz     = 16,
                    .FontFirst    = 0x20,
                    .FontLast     = 0x7F
                  },
  [FONTTYPE_SMALL] =  {
                    .pFontBits    = (const char*)small_font_bits,
                    .FontHeight   = 8,
                    .FontWidth    = 8,
                    .FontHorz     = 16,
                    .FontFirst    = 0x20,
                    .FontLast     = 0x7F
                  },
  [FONTTYPE_LARGE] =  {
                    .pFontBits    = (const char*)large_font_bits,
                    .FontHeight   = 16,
                    .FontWidth    = 16,
                    .FontHorz     = 16,
                    .FontFirst    = 0x20,
                    .FontLast     = 0x7F
                  },
  [FONTTYPE_TINY] =   {
                    .pFontBits    = (const char*)tiny_font_bits,
                    .FontHeight   = 7,
                    .FontWidth    = 5,
                    .FontHorz     = 16,
                    .FontFirst    = 0x20,
                    .FontLast     = 0x7F
                  },

};

short dLcdGetFontWidth(byte Font)
{
  return (FontInfo[Font].FontWidth);
}

short dLcdGetFontHeight(byte Font)
{
  return (FontInfo[Font].FontHeight);
}

typedef   struct
{
  const char  *pIconBits;
  const short IconSize;
  const short IconHeight;
  const short IconWidth;
} ICONINFO;

#include "normal_icons.xbm"
#include "small_icons.xbm"
#include "large_icons.xbm"
#include "menu_icons.xbm"
#include "arrow_icons.xbm"

ICONINFO IconInfo[] =
{
  [ICONTYPE_NORMAL] = {
                    .pIconBits    = normal_icons_bits,
                    .IconSize     = normal_icons_height,
                    .IconHeight   = 12,
                    .IconWidth    = normal_icons_width
                  },
  [ICONTYPE_SMALL] =  {
                    .pIconBits    = small_icons_bits,
                    .IconSize     = small_icons_height,
                    .IconHeight   = 8,
                    .IconWidth    = small_icons_width
                  },
  [ICONTYPE_LARGE] =  {
                    .pIconBits    = large_icons_bits,
                    .IconSize     = large_icons_height,
                    .IconHeight   = 22,
                    .IconWidth    = large_icons_width
                  },
  [ICONTYPE_MENU] =   {
                    .pIconBits    = menu_icons_bits,
                    .IconSize     = menu_icons_height,
                    .IconHeight   = 12,
                    .IconWidth    = menu_icons_width
                  },
  [ICONTYPE_ARROW] =  {
                    .pIconBits    = arrow_icons_bits,
                    .IconSize     = arrow_icons_height,
                    .IconHeight   = 12,
                    .IconWidth    = arrow_icons_width
                  },
};

byte *dLcdGetIconBits(byte Icon)
{
  return (byte*)IconInfo[Icon].pIconBits;
}

short dLcdGetIconWidth(byte Icon)
{
  return (IconInfo[Icon].IconWidth);
}

short dLcdGetIconHeight(byte Icon)
{
  return (IconInfo[Icon].IconHeight);
}

short dLcdGetNumIcons(byte Icon)
{
  return (IconInfo[Icon].IconSize / IconInfo[Icon].IconHeight);
}

void frameBufferToLcd(byte* pSrc, byte* pDst)
{
  unsigned long Pixels;
  unsigned short X;
  unsigned short Y;

  for (Y = 0; Y < LCD_HEIGHT; Y++)
  {
    for (X = 0; X < 7; X++)
    {
      // read 8 bytes (3 bits per byte) into a 32-bit unsigned long from our source
      Pixels  = (unsigned long)UnPixelTab[*pSrc] << 0;  pSrc++;
      Pixels |= (unsigned long)UnPixelTab[*pSrc] << 3;  pSrc++;
      Pixels |= (unsigned long)UnPixelTab[*pSrc] << 6;  pSrc++;
      Pixels |= (unsigned long)UnPixelTab[*pSrc] << 9;  pSrc++;
      Pixels |= (unsigned long)UnPixelTab[*pSrc] << 12; pSrc++;
      Pixels |= (unsigned long)UnPixelTab[*pSrc] << 15; pSrc++;
      Pixels |= (unsigned long)UnPixelTab[*pSrc] << 18; pSrc++;
      Pixels |= (unsigned long)UnPixelTab[*pSrc] << 21; pSrc++;

      // now write the 24 bits to 3 8-bit bytes in our destination
      *pDst = (byte)(Pixels >> 0);  pDst++;
      *pDst = (byte)(Pixels >> 8);  pDst++;
      *pDst = (byte)(Pixels >> 16); pDst++;
    }
    Pixels  = (unsigned long)UnPixelTab[*pSrc] << 0;  pSrc++;
    Pixels |= (unsigned long)UnPixelTab[*pSrc] << 3;  pSrc++;
    Pixels |= (unsigned long)UnPixelTab[*pSrc] << 6;  pSrc++;
    Pixels |= (unsigned long)UnPixelTab[*pSrc] << 9;  pSrc++;

    *pDst = (byte)(Pixels >> 0);  pDst++;
    *pDst = (byte)(Pixels >> 8);  pDst++;
  }
}

void lcdToFrameBuffer(byte* pSrc, byte* pDst)
{
  unsigned long Pixels;
  unsigned short X;
  unsigned short Y;

  for (Y = 0; Y < LCD_HEIGHT; Y++)
  {
    for (X = 0; X < 7; X++)
    {
      Pixels  =  (unsigned long)*pSrc << 0;  pSrc++;
      Pixels |=  (unsigned long)*pSrc << 8;  pSrc++;
      Pixels |=  (unsigned long)*pSrc << 16; pSrc++;

      *pDst   =  PixelTab[Pixels & 0x07]; pDst++;
      Pixels >>= 3;
      *pDst   =  PixelTab[Pixels & 0x07]; pDst++;
      Pixels >>= 3;
      *pDst   =  PixelTab[Pixels & 0x07]; pDst++;
      Pixels >>= 3;
      *pDst   =  PixelTab[Pixels & 0x07]; pDst++;
      Pixels >>= 3;
      *pDst   =  PixelTab[Pixels & 0x07]; pDst++;
      Pixels >>= 3;
      *pDst   =  PixelTab[Pixels & 0x07]; pDst++;
      Pixels >>= 3;
      *pDst   =  PixelTab[Pixels & 0x07]; pDst++;
      Pixels >>= 3;
      *pDst   =  PixelTab[Pixels & 0x07]; pDst++;
    }
    Pixels  =  (unsigned long)*pSrc << 0; pSrc++;
    Pixels |=  (unsigned long)*pSrc << 8; pSrc++;

    *pDst   =  PixelTab[Pixels & 0x07]; pDst++;
    Pixels >>= 3;
    *pDst   =  PixelTab[Pixels & 0x07]; pDst++;
    Pixels >>= 3;
    *pDst   =  PixelTab[Pixels & 0x07]; pDst++;
    Pixels >>= 3;
    *pDst   =  PixelTab[Pixels & 0x07]; pDst++;
  }
}

void doUpdateScreen()
{
  if (LCDInstance.Dirty && (LCDInstance.pFB0 != NULL) && (LCDInstance.pLcd != NULL))
  {
    lcdToFrameBuffer(LCDInstance.pLcd, hwBuffer);
    memmove((void*)LCDInstance.pFB0, (const void *)hwBuffer, LCD_BUFFER_LENGTH);
    LCDInstance.Dirty = false;
  }
}

void LcdUpdateHandler(int sig)
{
  if (LCDInstance.autoRefresh)
      doUpdateScreen();
}

void LcdCloseDevices()
{
  if (!LcdInitialized())
    return;

  if (LCDInstance.DispFile >= 0)
  {
    close(LCDInstance.DispFile);
    if (LCDInstance.pFB0 != NULL)
      munmap(LCDInstance.pFB0, LCD_BUFFER_LENGTH);
    LCDInstance.pFB0 = NULL;
    LCDInstance.DispFile = -1;
  }
}

bool LcdInit()
{
  int i;
  byte * pTmp;
  if (LcdInitialized()) return true;

  LCDInstance.autoRefresh = true;
  LCDInstance.Dirty = false;
  LCDInstance.pFB0 = NULL;
  LCDInstance.DispFile = -1;
  LCDInstance.font = NULL;
  LCDInstance.pLcd = NULL;
  LCDInstance.currentFont = FONTTYPE_NORMAL;

  LCDInstance.DispFile = open(LMS_LCD_DEVICE_NAME, O_RDWR);
  if (LCDInstance.DispFile != -1)
  {
    pTmp = (byte*)mmap(NULL, LCD_BUFFER_LENGTH, PROT_READ + PROT_WRITE, MAP_SHARED, LCDInstance.DispFile, 0);
    if (pTmp == MAP_FAILED)
    {
      LcdCloseDevices();
      return false;
    }
    else
    {
      LCDInstance.pFB0 = pTmp;
//      LCDInstance.font := @(font_data[0]);
      LCDInstance.pLcd = LCDInstance.displayBuf;
      
      // initialize timer system
      TimerInit();
      
      // register update handler with timer system
      SetTimerCallback(ti250ms, &LcdUpdateHandler);

      return true;
    }
  }
}

bool LcdOpen()
{
  return true;
}

bool LcdClose()
{
  return true;
}

bool LcdExit()
{
  // if not initialized then just exit
  if (!LcdInitialized())
    return true;

  LcdCloseDevices();

  LCDInstance.font = NULL;
  LCDInstance.pLcd = NULL;
  return true;
}

bool LcdInitialized()
{
  return (LCDInstance.DispFile != -1) &&
         (LCDInstance.pFB0 != NULL);
}

void dLcdDrawPixel(byte *pImage, char Color, short X0, short Y0)
{
  if ((X0 >= 0) && (X0 < LCD_WIDTH) && (Y0 >= 0) && (Y0 < LCD_HEIGHT))
  {
    if (Color)
    {
      pImage[(X0 >> 3) + Y0 * LCD_BYTE_WIDTH]  |=  (1 << (X0 % 8));
    }
    else
    {
      pImage[(X0 >> 3) + Y0 * LCD_BYTE_WIDTH]  &= ~(1 << (X0 % 8));
    }
  }
}

char dLcdReadPixel(byte *pImage, short X0, short Y0)
{
  char Result = 0;
  if ((X0 >= 0) && (X0 < LCD_WIDTH) && (Y0 >= 0) && (Y0 < LCD_HEIGHT))
  {
    if ((pImage[(X0 >> 3) + Y0 * LCD_BYTE_WIDTH] & (1 << (X0 % 8))))
    {
      Result = 1;
    }
  }
  return (Result);
}

void dLcdDrawChar(byte *pImage, char Color, short X0, short Y0, char Font, char Char)
{
  short CharWidth;
  short CharHeight;
  short CharByteIndex;
  short LcdByteIndex;
  byte  CharByte;
  short Tmp,X,Y,TmpX,MaxX;
  byte  bC1, bC2;

  CharWidth  = FontInfo[Font].FontWidth;
  CharHeight = FontInfo[Font].FontHeight;

  if ((Char >= FontInfo[Font].FontFirst) && (Char <= FontInfo[Font].FontLast))
  {
    Char -= FontInfo[Font].FontFirst;

    CharByteIndex  = (Char % FontInfo[Font].FontHorz) * ((CharWidth + 7) / 8);
    CharByteIndex += ((Char / FontInfo[Font].FontHorz) * ((CharWidth + 7) / 8) * CharHeight * FontInfo[Font].FontHorz);

    if (((CharWidth % 8) == 0) && ((X0 % 8) == 0))
    {
      // Font aligned
      X0           = (X0 >> 3) << 3;
      LcdByteIndex = (X0 >> 3) + Y0 * LCD_BYTE_WIDTH;
      while (CharHeight)
      {
        Tmp = 0;
        do
        {
          if (LcdByteIndex < LCD_BUFFER_SIZE)
          {
            if (Color)
              CharByte = FontInfo[Font].pFontBits[CharByteIndex + Tmp];
            else
              CharByte = ~FontInfo[Font].pFontBits[CharByteIndex + Tmp];
            pImage[LcdByteIndex + Tmp] = CharByte;
          }
          Tmp++;
        }
        while (Tmp < (CharWidth / 8));
        CharByteIndex += (CharWidth * FontInfo[Font].FontHorz) / 8;
        LcdByteIndex  += LCD_BYTE_WIDTH;
        CharHeight--;
      }
    }
    else
    {
      // Font not aligned
      MaxX = X0 + CharWidth;
      if (Color)
      {
        bC1 = 1;
        bC2 = 0;
      }
      else
      {
        bC1 = 0;
        bC2 = 1;
      }
      for (Y = 0;Y < CharHeight;Y++)
      {
        TmpX = X0;
        for (X = 0;X < ((CharWidth + 7) / 8);X++)
        {
          CharByte = FontInfo[Font].pFontBits[CharByteIndex + X];
          for (Tmp = 0;(Tmp < 8) && (TmpX < MaxX);Tmp++)
          {
            if (CharByte & 1)
            {
              dLcdDrawPixel(pImage,bC1,TmpX,Y0);
            }
            else
            {
              dLcdDrawPixel(pImage,bC2,TmpX,Y0);
            }
            CharByte >>= 1;
            TmpX++;
          }
        }
        Y0++;
        CharByteIndex += ((CharWidth + 7) / 8) * FontInfo[Font].FontHorz;
      }
    }
  }
}

void dLcdDrawText(byte *pImage, char Color, short X0, short Y0, char Font, char *pText)
{
  while (*pText)
  {
    if (X0 < (LCD_WIDTH - FontInfo[Font].FontWidth))
    {
      dLcdDrawChar(pImage,Color,X0,Y0,Font,*pText);
      X0 += FontInfo[Font].FontWidth;
    }
    pText++;
  }
}

void dLcdDrawPicture(byte *pImage,char Color,short X0,short Y0,short IconWidth,short IconHeight,byte *pIconBits)
{
  short IconByteIndex;
  short LcdByteIndex;
  short Tmp;
  byte  IconByte;

  IconByteIndex = 0;

  X0           = (X0 >> 3) << 3;
  LcdByteIndex = (X0 >> 3) + Y0 * LCD_BYTE_WIDTH;

  while (IconHeight)
  {
    for (Tmp = 0;Tmp < (IconWidth / 8);Tmp++)
    {
      if (Color)
        IconByte = pIconBits[IconByteIndex + Tmp];
      else
        IconByte = ~pIconBits[IconByteIndex + Tmp];

      pImage[LcdByteIndex + Tmp] = IconByte;
    }

    IconByteIndex += IconWidth / 8;
    LcdByteIndex  += LCD_BYTE_WIDTH;
    IconHeight--;
  }
}

void dLcdDrawIcon(byte *pImage, char Color, short X0, short Y0, char Icon, char Num)
{
  short IconByteIndex;
  short IconHeight;
  short IconWidth;
  byte  *pIconBits;

  IconHeight = dLcdGetIconHeight(Icon);
  IconWidth  = dLcdGetIconWidth(Icon);

  if ((Num >= 0) && (Num <= dLcdGetNumIcons(Icon)))
  {
    pIconBits     = dLcdGetIconBits(Icon);
    IconByteIndex = ((short)Num * IconWidth * IconHeight) / 8;
    dLcdDrawPicture(pImage,Color,X0,Y0,IconWidth,IconHeight,&pIconBits[IconByteIndex]);
  }
}

void dLcdGetBitmapSize(IP pBitmap, short *pWidth, short *pHeight)
{
  *pWidth  = 0;
  *pHeight = 0;

  if (pBitmap)
  {
    *pWidth  = (short)pBitmap[0];
    *pHeight = (short)pBitmap[1];
  }
}

void dLcdDrawBitmap(byte *pImage, char Color, short X0, short Y0, IP pBitmap)
{
  short  BitmapWidth;
  short  BitmapHeight;
  short  BitmapByteIndex;
  byte   *pBitmapBytes;
  byte   BitmapByte;
  short  Tmp,X,Y,TmpX,MaxX;
  short  LcdByteIndex;
  byte   bC1, bC2;

  if (pBitmap)
  {
    BitmapWidth   =  (short)pBitmap[0];
    BitmapHeight  =  (short)pBitmap[1];
    MaxX          =  X0 + BitmapWidth;
    pBitmapBytes  =  &pBitmap[2];

    if ((BitmapWidth >=0) && (BitmapHeight >= 0))
    {
      if ((X0 % 8) || (BitmapWidth % 8))
      { // X is not aligned
        BitmapWidth = ((BitmapWidth + 7) >> 3) << 3;
        if (Color)
        {
          bC1 = 1;
          bC2 = 0;
        }
        else
        {
          bC1 = 0;
          bC2 = 1;
        }
        for (Y = 0;Y < BitmapHeight;Y++)
        {
          BitmapByteIndex = (Y * BitmapWidth) / 8;
          TmpX            = X0;

          for (X = 0;X < (BitmapWidth / 8);X++)
          {
            BitmapByte = pBitmapBytes[BitmapByteIndex + X];

            for (Tmp = 0;(Tmp < 8) && (TmpX < MaxX);Tmp++)
            {
              if (BitmapByte & 1)
              {
                dLcdDrawPixel(pImage,bC1,TmpX,Y0);
              }
              else
              {
                dLcdDrawPixel(pImage,bC2,TmpX,Y0);
              }
              BitmapByte >>= 1;
              TmpX++;
            }
          }
          Y0++;
        }
      }
      else
      { // X is byte aligned
        BitmapByteIndex = 0;
        LcdByteIndex    = (X0 >> 3) + Y0 * LCD_BYTE_WIDTH;
        while (BitmapHeight)
        {
          X  =  X0;
          for (Tmp = 0;Tmp < (BitmapWidth / 8);Tmp++)
          {
            if (((LcdByteIndex + Tmp) < LCD_BUFFER_SIZE) && (X < LCD_WIDTH) && (X >= 0))
            {
              if (Color)
                BitmapByte = pBitmapBytes[BitmapByteIndex + Tmp];
              else
                BitmapByte = ~pBitmapBytes[BitmapByteIndex + Tmp];
              pImage[LcdByteIndex + Tmp] = BitmapByte;
            }
            X +=  8;
          }
          BitmapByteIndex += BitmapWidth / 8;
          LcdByteIndex    += LCD_BYTE_WIDTH;
          BitmapHeight--;
        }
      }
    }
  }
}

void LcdRefresh()
{
  if (!LcdInitialized())
    return;
  doUpdateScreen();
}

void LcdSetAutoRefresh(bool bOn)
{
  LCDInstance.autoRefresh = bOn;
}

bool LcdUpdate()
{
  if (!LcdInitialized())
    return false;

  doUpdateScreen();
  LCDInstance.Dirty = false;
  return true;
}

bool LcdClean()
{
  if (!LcdInitialized())
    return false;
  LCDInstance.currentFont = FONTTYPE_NORMAL;
  memset((void*)LCDInstance.pLcd, 0, LCD_BUFFER_SIZE);
  LCDInstance.Dirty = true;
  return true;
}

void LcdClearDisplay()
{
  LcdClean();
  LCDInstance.Dirty = true;
}

bool LcdScroll(short Y)
{
  if (LcdInitialized())
  {
    if ((Y > 0) && (Y < LCD_HEIGHT))
    {
      memmove(LCDInstance.pLcd,&(LCDInstance.pLcd[LCD_BYTE_WIDTH * Y]),(LCD_HEIGHT - Y) * LCD_BYTE_WIDTH);
      memset(&(LCDInstance.pLcd[(LCD_HEIGHT - Y) * LCD_BYTE_WIDTH]),0,LCD_BYTE_WIDTH * Y);
    }
    else if ((Y < 0) && (Y > -LCD_HEIGHT))
    {
      Y = ABS(Y);
      memmove(&(LCDInstance.pLcd[LCD_BYTE_WIDTH * Y]),LCDInstance.pLcd,(LCD_HEIGHT - Y) * LCD_BYTE_WIDTH);
      memset(LCDInstance.pLcd,0,LCD_BYTE_WIDTH * Y);
    }
    return true;
  }
  return false;
}

bool LcdSelectFont(byte FontType)
{
  if (!LcdInitialized())
    return false;

  if (FontType >= NUM_FONTTYPES)
  {
    LCDInstance.currentFont = FONTTYPE_NORMAL;
  }
  else
  {
    LCDInstance.currentFont = FontType;
  }
  return true;
}

byte* LcdGetDisplay()
{
  if (!LcdInitialized())
    return NULL;

  return LCDInstance.pLcd;
}

byte* LcdGetFrameBuffer()
{
  if (!LcdInitialized())
    return NULL;

  // read from frame buffer into hwBuffer
  memmove((void *)hwBuffer, (const void*)LCDInstance.pFB0, LCD_BUFFER_LENGTH);
  // convert to display buffer
  frameBufferToLcd(hwBuffer, LCDInstance.pLcd);
  // return display buffer
  return LCDInstance.pLcd;
}

static const unsigned char reverse_bits_table[] = {
  0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
  0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
  0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
  0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
  0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
  0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
  0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
  0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
  0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
  0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
  0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
  0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
  0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
  0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
  0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
  0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
};

byte reverse_bits(byte b)
{
  return reverse_bits_table[b];
}

void _lcdWriteBytesToFile(ImageFormat fmt, byte* data, char* filename, byte width, byte height)
{
  char fullname[128];
  char* fn_copy = strdup(filename);
  char *base, *path;
  path = dirname(fn_copy);
  base = basename(filename);

  byte len = strlen(base);
  // check for and remove extension if it exists
  char* ext = strrchr(base, '.');
  if (ext) {
    len = ext-base;
  }
  // now build full path
  strcpy(fullname, path);
  strcat(fullname, "/");
  strncat(fullname, base, len);
  switch(fmt)
  {
    case ifP1:
    case ifP4:
      strcat(fullname, ".pbm");
      break;
    case ifBMP:
      strcat(fullname, ".bmp");
      break;
    case ifPNG:
      strcat(fullname, ".png");
      break;
    default:
      // default is XBM
      strcat(fullname, ".xbm");
      break;
  }

  FILE * pFile = NULL;
  pFile = fopen(fullname, "w");

  if (pFile != NULL)
  {
    int i, j, k, cnt, bw;
    bw = ((width + 7) / 8);
    switch (fmt)
    {
      case ifP1:
        fprintf(pFile, "P1\n%d %d\n", width, height);
        for (i = 0; i < height; i++)
        {
          byte b;
          for (j = 0; j < bw-1; j++)
          {
            // get a byte
            b = reverse_bits(data[i*bw+j]);
            // output 8 bits per byte except for last byte per line
            for (k = 7; k >= 0; k--)
            {
              fprintf(pFile, "%c ", (b & (1 << k)) ? '1' : '0');
            }
          }
          // handle last byte per line
          b = reverse_bits(data[i*bw+(bw-1)]);
          // how many bits are extra?
          cnt = bw*8 - width; // e.g., 6 if width = 178
          for (k = 7; k >= cnt; k--)
          {
            fprintf(pFile, "%c ", (b & (1 << k)) ? '1' : '0');
          }
          fprintf(pFile, "\n");
        }
        break;
      case ifP4:
        fprintf(pFile, "P4\n%d %d\n", width, height);
        cnt = bw*height;
        for (i=0; i < cnt; i++)
        {
          byte b = reverse_bits(data[i]);
          fwrite(&b, 1, 1, pFile);
        }
        break;
      case ifBMP:
      case ifPNG:
        printf("BMP and PNG image formats are not yet supported\n");
        break;
      default:
        // XBM format
        fprintf(pFile, "#define %s_width %d\n", base, width);
        fprintf(pFile, "#define %s_height %d\n", base, height);
        fprintf(pFile, "static char %s_bits[] = {\n", base);
        cnt = bw*height;
        for (i=0; i < cnt; i++)
        {
          fprintf(pFile, "0x%2.2X,", data[i]);
          if ((i+1) % 12 == 0)
            fprintf(pFile, "\n");
        }
        fprintf(pFile, " };\n");
        break;
    }
    fclose(pFile);
  }
}

void LcdWriteDisplayToFile(char* filename, ImageFormat fmt)
{
  if (!LcdInitialized())
    return;

  byte * pSrc = LcdGetDisplay();
  _lcdWriteBytesToFile(fmt, pSrc, filename, 178, 128);
}

void LcdWriteFrameBufferToFile(char* filename, ImageFormat fmt)
{
  if (!LcdInitialized())
    return;

  byte * pSrc = LcdGetFrameBuffer();
  _lcdWriteBytesToFile(fmt, pSrc, filename, 178, 128);
}

bool LcdText(char Color, short X, short Y, char* Text)
{
  if (!LcdInitialized())
    return false;

  dLcdDrawText(LCDInstance.pLcd, Color, X, Y, LCDInstance.currentFont, Text);
  LCDInstance.Dirty = true;
  return true;
}

bool LcdIcon(char Color, short X, short Y, char IconType, char IconNum)
{
  if (!LcdInitialized())
    return false;

  dLcdDrawIcon(LCDInstance.pLcd, Color, X, Y, IconType, IconNum);
  LCDInstance.Dirty = true;
  return true;
}

bool LcdBmpFile(char Color, short X, short Y, char* Name)
{
  if (LcdInitialized())
  {
    byte pBmp[LCD_BUFFER_SIZE];
    int File = -1;
    File = open(Name, O_RDONLY);
    if (File >= 0)
    {
      read(File, pBmp, LCD_BUFFER_SIZE);
      close(File);
      dLcdDrawBitmap(LCDInstance.pLcd, Color, X, Y, (IP)pBmp);
      LCDInstance.Dirty = true;
      return true;
    }
  }
  return false;
}

bool LcdPicture(char Color, short X, short Y, IP pBitmap)
{
  if (!LcdInitialized())
    return false;

  dLcdDrawBitmap(LCDInstance.pLcd, Color, X, Y, pBitmap);
  LCDInstance.Dirty = true;
  return true;
}

bool LcdFillWindow(char Color, short Y, short Y1)
{
  if (!LcdInitialized())
    return false;

  short Y2, Y3, Tmp;
  
  LCDInstance.currentFont = FONTTYPE_NORMAL;

  if ((Y + Y1) < LCD_HEIGHT)
  {
    if ((Color == 0) || (Color == 1))
    {
      Y *= LCD_BYTE_WIDTH;

      if (Y1)
      {
        Y1 *= LCD_BYTE_WIDTH;
      }
      else
      {
        Y1 = LCD_BUFFER_SIZE - Y;
      }

      if (Color)
      {
        Color = -1;
      }
      memset(&(LCDInstance.pLcd[Y]), Color, Y1);
    }
    else
    {
      if (Y1 == 0)
      {
        Y1 = LCD_HEIGHT;
      }
      Y2 = LCD_BYTE_WIDTH;
      for (Tmp = Y;Tmp < Y1;Tmp++)
      {
        Y3 = Tmp * LCD_BYTE_WIDTH;
        memset(&(LCDInstance.pLcd[Y3]), Color, Y2);
        Color = ~Color;
      }
    }
  }
  LCDInstance.Dirty = true;
  return true;
}

//****************************************************************************
//****************************************************************************
//****************************************************************************

#define TRANSLATE_Y(_Y) (LCD_HEIGHT - 1 - (_Y))

// OP codes supported by RIC files
enum {
  IMG_DESCRIPTION_ID = 0, // Ignored at this time
  IMG_SPRITE_ID = 1,
  IMG_VARMAP_ID = 2,
  IMG_COPYBITS_ID = 3,
  IMG_PIXEL_ID = 4,
  IMG_LINE_ID = 5,
  IMG_RECTANGLE_ID = 6,
  IMG_CIRCLE_ID = 7,
  IMG_NUMBOX_ID = 8,
  IMG_ELLIPSE_ID = 9,
  IMG_POLYGON_ID = 10
};

#define IMG_SYMB_USEARGS(_v) (_v & (SWORD)0xF000)
#define IMG_SYMB_MAP(_v)  ((_v & 0x0F00) >> 8)
#define IMG_SYMB_ARG(_v)  (_v & 0x00FF)

int DisplayLineHeight()
{
  // return the height of a character in the current font
  return dLcdGetFontHeight(LCDInstance.currentFont);
}

void DisplayEraseLine(byte Line)
{
  int cnt = DisplayLineHeight()*LCD_BYTE_WIDTH;
  memset((void*)&(LCDInstance.pLcd[Line*cnt]), 0, cnt);
  LCDInstance.Dirty = true;
}

void DisplayErase()
{
  memset((void*)LCDInstance.pLcd, 0, LCD_BUFFER_SIZE);
  LCDInstance.Dirty = true;
}

void DisplaySetPixel(byte X, byte Y)
{
  if ((X < LCD_WIDTH) && (Y < LCD_HEIGHT))
  {
    LCDInstance.pLcd[(X / 8) + (LCD_BYTE_WIDTH * Y)] |= (1 << (X % 8));
    LCDInstance.Dirty = true;
  }
}

void DisplayClrPixel(byte X, byte Y)
{
  if ((X < LCD_WIDTH) && (Y < LCD_HEIGHT))
  {
    LCDInstance.pLcd[(X / 8) + (LCD_BYTE_WIDTH * Y)] &= ~(1 << (X % 8));
    LCDInstance.Dirty = true;
  }
}

void DisplayXorPixel(byte X, byte Y)
{
  if ((X < LCD_WIDTH) && (Y < LCD_HEIGHT))
  {
    LCDInstance.pLcd[(X / 8) + (LCD_BYTE_WIDTH * Y)] ^= (1 << (X % 8));
    LCDInstance.Dirty = true;
  }
}

byte Masks[] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};

void DisplayFillScreen(byte StartX, byte StartY, byte PixelsX, byte PixelsY, byte PixelMode)
{
  byte X1, Y1, X2, Y2, X, Y, M;
  byte* pDst;

  X1 = StartX;
  Y1 = StartY;
  X2 = (byte)((int)StartX + (int)PixelsX - 1);
  Y2 = (byte)((int)StartY + (int)PixelsY - 1);

  if (X2 > (LCD_WIDTH-1))
    X2 = (LCD_WIDTH-1);
  if (Y2 > (LCD_HEIGHT-1))
    Y2 = (LCD_HEIGHT-1);

  X = (X1 / 8) * 8; // multiple of 8

  while (X <= X2)
  {
    M = 0xff;
    if (X < X1)
      M &= ~Masks[X1 % 8];
    if ((X2-X) < 8)
      M &= Masks[(X2 % 8) + 1];
    pDst = &(LCDInstance.pLcd[(X / 8) + (LCD_BYTE_WIDTH * Y1)]);
    switch (PixelMode)
    {
      case DRAW_PIXELS_INVERT:
        for (Y = Y1; Y <= Y2; Y++)
        {
          *pDst ^= M;
          pDst += LCD_BYTE_WIDTH;
        }
        break;
      case DRAW_PIXELS_CLEAR:
        for (Y = Y1; Y <= Y2; Y++)
        {
          *pDst &= ~M;
          pDst += LCD_BYTE_WIDTH;
        }
        break;
      default:
        for (Y = Y1; Y <= Y2; Y++)
        {
          *pDst |= M;
          pDst += LCD_BYTE_WIDTH;
        }
        break;
    }
    X += 8;
  }
  LCDInstance.Dirty = true;
}

void DisplayLineX(byte X1, byte X2, byte Y, byte PixelMode)
{
  byte X, M, t;
  byte* pDst;

  if (Y > LCD_HEIGHT) return;
  if (X1 > X2)
  {
    t = X1; X1 = X2; X2 = t;
  }
  if (X2 > (LCD_WIDTH-1))
    X2 = (LCD_WIDTH-1);

  // starting point of X is the byte containing X1
  X = (X1 / 8) * 8;

  while (X <= X2)
  {
    M = 0xff;
    if (X < X1)
      M &= ~Masks[X1 % 8];
    if ((X2-X) < 8)
      M &= Masks[(X2 % 8) + 1];
    pDst = &(LCDInstance.pLcd[(X / 8) + (LCD_BYTE_WIDTH * Y)]);
    switch (PixelMode)
    {
      case DRAW_PIXELS_INVERT:
        *pDst ^= M;
        break;
      case DRAW_PIXELS_CLEAR:
        *pDst &= ~M;
        break;
      default:
        *pDst |= M;
        break;
    }
    X += 8;
  }
  LCDInstance.Dirty = true;
}

void DisplayLineY(byte X, byte Y1, byte Y2, byte PixelMode)
{
  byte Y, M, t;
  byte* pDst;

  if (X > LCD_WIDTH) return;
  if (Y1 > Y2)
  {
    t = Y1; Y1 = Y2; Y2 = t;
  }
  if (Y2 > (LCD_HEIGHT-1))
    Y2 = (LCD_HEIGHT-1);

  M = 1 << (X % 8);
  pDst = &(LCDInstance.pLcd[(X / 8) + (LCD_BYTE_WIDTH * Y1)]);
  for (Y = Y1; Y <= Y2; Y++)
  {
    switch (PixelMode)
    {
      case DRAW_PIXELS_INVERT:
        *pDst ^= M;
        break;
      case DRAW_PIXELS_CLEAR:
        *pDst &= ~M;
        break;
      default:
        *pDst |= M;
        break;
    }
    pDst += LCD_BYTE_WIDTH;
  }
  LCDInstance.Dirty = true;
}

void DisplayFrame(byte StartX, byte StartY, byte PixelsX, byte PixelsY, byte PixelMode)
{
  DisplayLineX(StartX, StartX + PixelsX-1, StartY, PixelMode);
  if (PixelsY > 1)
  {
    DisplayLineY(StartX, StartY + 1, StartY + PixelsY - 1, PixelMode);
    DisplayLineY(StartX + PixelsX - 1, StartY + 1, StartY + PixelsY - 1, PixelMode);
  }
  LCDInstance.Dirty = true;
}

void DisplayDraw(byte Cmd, byte PixelMode, byte X1, byte Y1, byte X2, byte Y2)
{
  if (!LcdInitialized())
    return;
    
  switch (Cmd)
  {
    case DISPLAY_ERASE_ALL :
      DisplayErase();
      break;
    case DISPLAY_PIXEL :
      switch (PixelMode)
      {
        case DRAW_PIXELS_INVERT:
          DisplayXorPixel(X1, Y1);
          break;
        case DRAW_PIXELS_CLEAR:
          DisplayClrPixel(X1, Y1);
          break;
        default:
          DisplaySetPixel(X1, Y1);
          break;
      }
      break;
    case DISPLAY_HORIZONTAL_LINE :
      DisplayLineX(X1,X2,Y1,PixelMode);
      break;
    case DISPLAY_VERTICAL_LINE :
      DisplayLineY(X1,Y1,Y2,PixelMode);
      break;
    case DISPLAY_CHAR :
//      DisplayChar(IOMapDisplay.pFont, PixelMode, X1, Y1, X2);
      break;
    case DISPLAY_ERASE_LINE :
      DisplayEraseLine(X1);
      break;
    case DISPLAY_FILL_REGION :
      DisplayFillScreen(X1, Y1, X2, Y2, PixelMode);
      break;
    case DISPLAY_FRAME :
      DisplayFrame(X1, Y1, X2, Y2, PixelMode);
      break;
  }
}

bool CmdResolveDrawingMode(unsigned short DrawingOptions, byte* pPixelMode, byte* pFillMode)
{
  // Extract shape fill option:
  if (DrawingOptions & DRAW_OPT_FILL_SHAPE)
    *pFillMode = DRAW_SHAPE_FILLED;
  else
    *pFillMode = DRAW_SHAPE_HOLLOW;

  // Extract pixel drawing options:
  if (DrawingOptions & DRAW_OPT_INVERT)
  {
    //Drawing with white pixels:
    switch (DrawingOptions & DRAW_OPT_LOGICAL_OPERATIONS)
    {
      //Only these cases do anything:
      case DRAW_OPT_LOGICAL_COPY:
      case DRAW_OPT_LOGICAL_AND:
        *pPixelMode = DRAW_PIXELS_CLEAR;
        return true;
    }
  }
  else
  {
    //Drawing with black pixels:
    switch (DrawingOptions & DRAW_OPT_LOGICAL_OPERATIONS)
    {
      //Only these cases do anything:
      case DRAW_OPT_LOGICAL_COPY:
      case DRAW_OPT_LOGICAL_OR:
          *pPixelMode = DRAW_PIXELS_SET;
          return true;
      case DRAW_OPT_LOGICAL_XOR:
          *pPixelMode = DRAW_PIXELS_INVERT;
          return true;
    }
  }
  // If no operation is required, set defaults and return FALSE.
  // e.g. 'AND' on its own is meaningless for line drawing,
  // 'INVERT + OR' and 'INVERT + XOR'  do nothing either.
  *pPixelMode = DRAW_PIXELS_SET;
  *pFillMode  = DRAW_SHAPE_HOLLOW;
  return false;
}

void CmdSetPixel(int X, int Y, byte PixelMode)
{
  Y = TRANSLATE_Y(Y);
  if ((X >= 0) && (X < LCD_WIDTH) && (Y >= 0) && (Y < LCD_HEIGHT))
    DisplayDraw(DISPLAY_PIXEL, PixelMode, (byte)X, (byte)Y, 0, 0);
}

void CmdDrawLine(int x1, int y1, int x2, int y2, byte PixelMode)
{
  int tx, ty, dx, dy;
  int d, x, y, ax, ay, sx, sy;
  
  dx = x2-x1;
  dy = y2-y1;

  //Clip line ends vertically - easier if y1<y2:
  if (y1 > y2)
  {
    tx = x1; x1 = x2; x2 = tx;
    ty = y1; y1 = y2; y2 = ty;
  }

  //Is line completely off screen?
  if ((y2 < 0) || (y1 >= LCD_HEIGHT)) return;

  //Trim y1 end:
  if (y1 < 0)
  {
    if ((dx != 0) && (dy != 0))
      x1 = x1 + (((0-y1)*dx) / dy);
    y1 = 0;
  }
  //Trim y2 end:
  if (y2 > LCD_HEIGHT-1)
  {
    if ((dx != 0) && (dy != 0))
      x2 = x2 - (((y2-(LCD_HEIGHT-1))*dx) / dy);
    y2 = LCD_HEIGHT-1;
  }

  //Clip horizontally - easier if x1<x2
  if (x1 > x2)
  {
    tx = x1; x1 = x2; x2 = tx;
    ty = y1; y1 = y2; y2 = ty;
  }

  //Is line completely off screen?
  if ((x2 < 0) || (x1 >= LCD_WIDTH)) return;

  //Trim x1 end:
  if (x1 < 0)
  {
    if ((dx != 0) && (dy != 0))
      y1 = y1 + (((0-x1)*dy) / dx);
    x1 = 0;
  }
  //Trim x2 end:
  if (x2 > LCD_WIDTH-1)
  {
    if ((dx != 0) && (dy != 0))
      y2 = y2 - (((x2-(LCD_WIDTH-1))*dy) / dx);
    x2 = LCD_WIDTH-1;
  }

  if (x1 == x2)
  {
    // vertical line or a single point
    if (y1 == y2)
    {
      DisplayDraw(DISPLAY_PIXEL, PixelMode, (byte)x1, TRANSLATE_Y(y1), 0, 0);   //JJR
    }
    else
    {
      DisplayDraw(DISPLAY_VERTICAL_LINE, PixelMode, x1, TRANSLATE_Y(y1), 0, TRANSLATE_Y(y2));
    }
  }
  else if (y1 == y2)
  {
    // horizontal line (single point already dealt with)
    DisplayDraw(DISPLAY_HORIZONTAL_LINE, PixelMode, x1, TRANSLATE_Y(y1), x2, 0);   //JJR
  }
  else
  {
    // Initialize variables
    dx = x2-x1;
    ax = ABS(dx) << 1;
    sx = SGN(dx);
    dy = y2-y1;
    ay = ABS(dy) << 1;
    sy = SGN(dy);
    x  = x1;
    y  = y1;
    if (ax > ay)
    {    // x dominant
      d = ay - (ax >> 1);
      while (true)
      {
        DisplayDraw(DISPLAY_PIXEL, PixelMode, (byte)x, TRANSLATE_Y(y), 0, 0);   //JJR
        if (x == x2) return;
        if (d >= 0)
        {
          y += sy;
          d -= ax;
        }
        x += sx;
        d += ay;
      }
    }
    else
    {      // y dominant
      d = ax - (ay >> 1);
      while (true)
      {
        DisplayDraw(DISPLAY_PIXEL, PixelMode, (byte)x, TRANSLATE_Y(y), 0, 0);   //JJR
        if (y == y2) return;
        if (d >= 0)
        {
          x += sx;
          d -= ay;
        }
        y += sy;
        d += ax;
      }
    }
  }
}

void CmdDrawRect(int left, int bottom, int width, int height, byte PixelMode, byte FillMode)
{
  int x1 = left;
  int x2 = left + width;
  int y1 = bottom;
  int y2 = bottom + height;
  int t;
  
  if (x1 > x2)
  {
    t = x1; x1 = x2; x2 = t;
  }
  if (y1 > y2)
  {
    t = y1; y1 = y2; y2 = t;
  }

  if ((y2 == y1) || (x2 == x1))
  {
    // height == 0 so draw a single pixel horizontal line OR
    // width == 0 so draw a single pixel vertical line
    CmdDrawLine(x1, y1, x2, y2, PixelMode);
    return;
  }
  // rectangle has abs(width) or abs(height) >= 1
  if (FillMode == DRAW_SHAPE_FILLED)
  {
    if ((x2 < 0) || (y2 < 0) || (x1 > LCD_WIDTH-1) || (y1 > LCD_HEIGHT-1))
      return;
    if (x1 < 0)
      x1 = 0;
    if (y1 < 0)
      y1 = 0;
    if (x2 > LCD_WIDTH-1)
      x2 = LCD_WIDTH-1;
    if (y2 > LCD_HEIGHT-1)
      y2 = LCD_HEIGHT-1;
    DisplayDraw(DISPLAY_FILL_REGION, PixelMode, x1, TRANSLATE_Y(y2), x2-x1+1, y2-y1+1);
  }
  else
  {
    //Use the full line drawing functions rather than horizontal/vertical
    //functions so these get clipped properly.  These will fall straight
    //through to the faster functions anyway.
    //Also don't re-draw parts of slim rectangles since XOR might be on.

    CmdDrawLine(x1, y1, x2, y1, PixelMode);
    if (y2 > y1)
    {
      CmdDrawLine(x1, y2, x2, y2, PixelMode);
      if (y2 > y1+1)
      {
        CmdDrawLine(x2, y1+1, x2, y2-1, PixelMode);
        if (x2 > x1)
          CmdDrawLine(x1, y1+1, x1, y2-1, PixelMode);
      }
    }
  }
}

void CmdDrawEllipse(short xc, short yc, short a, short b, byte PixelMode, byte FillMode)
{
//			(* e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 *)
  short x  = 0;
  short y  = b;
  short rx = x;
  short ry = y;
  unsigned short width = 1;
  unsigned short height = 1;
  int a2 = (int)a*(int)a;
  int b2 = (int)b*(int)b;
  int crit1 = -((a2 / 4) + (a % 2) + b2);
  int crit2 = -((b2 / 4) + (b % 2) + a2);
  int crit3 = -((b2 / 4) + (b % 2));
  int t = -a2*y; //(* e(x+1/2,y-1/2) - (a^2+b^2)/4 *)
  int dxt  = 2*b2*x;
  int dyt  = -2*a2*y;
  int d2xt = 2*b2;
  int d2yt = 2*a2;

  if (b == 0)
  {
    CmdDrawRect(xc-a, yc, 2*a, 0, PixelMode, FillMode);
    return;
  }
  if (a == 0)
  {
    CmdDrawRect(xc, yc-b, 0, 2*b, PixelMode, FillMode);
    return;
  }

  while ((y >= 0) && (x <= a))
  {
    if (FillMode != DRAW_SHAPE_FILLED)
    {
      CmdSetPixel(xc+x, yc+y, PixelMode);
      if ((x != 0) || (y != 0))
        CmdSetPixel(xc-x, yc-y, PixelMode);
      if ((x != 0) && (y != 0))
      {
        CmdSetPixel(xc+x, yc-y, PixelMode);
        CmdSetPixel(xc-x, yc+y, PixelMode);
      }
    }
    if ((t + b2*x <= crit1) ||     //(* e(x+1,y-1/2) <= 0 *)
        (t + a2*y <= crit3))       //(* e(x+1/2,y) <= 0 *)
    {
      if (FillMode == DRAW_SHAPE_FILLED)
      {
        if (height == 1)
        {
          ; //(* draw nothing *)
        }
        else if (ry*2+1 > (height-1)*2)
        {
          CmdDrawRect(xc-rx, yc-ry, width-1, height-1, PixelMode, FillMode);
          CmdDrawRect(xc-rx, yc+ry, width-1, -(height-1), PixelMode, FillMode);
          ry -= (height-1);
          height = 1;
        }
        else
        {
          CmdDrawRect(xc-rx, yc-ry, width-1, ry*2, PixelMode, FillMode);
          ry -= ry;
          height = 1;
        }
        rx++;
        width += 2;
      }
      x++;
      dxt += d2xt;
      t   += dxt;
    }
    else if (t - a2*y > crit2) //(* e(x+1/2,y-1) > 0 *)
    {
      y--;
      dyt += d2yt;
      t   += dyt;
      if (FillMode == DRAW_SHAPE_FILLED)
        height++;
    }
    else
    {
      if (FillMode == DRAW_SHAPE_FILLED)
      {
        if (ry*2+1 > height*2)
        {
          CmdDrawRect(xc-rx, yc-ry, width-1, height-1, PixelMode, FillMode);
          CmdDrawRect(xc-rx, yc+ry, width-1, -(height-1), PixelMode, FillMode);
        }
        else
        {
          CmdDrawRect(xc-rx, yc-ry, width-1, ry*2, PixelMode, FillMode);
        }
        width += 2;
        ry -= height;
        height = 1;
        rx++;
      }
      x++;
      dxt += d2xt;
      t   += dxt;
      y--;
      dyt += d2yt;
      t   += dyt;
    }
  }
  if (FillMode == DRAW_SHAPE_FILLED)
  {
    if (ry > height)
    {
      CmdDrawRect(xc-rx, yc-ry, width-1, height-1, PixelMode, FillMode);
      CmdDrawRect(xc-rx, yc+ry, width-1, -(height-1), PixelMode, FillMode);
    }
    else
    {
      CmdDrawRect(xc-rx, yc-ry, width-1, ry*2, PixelMode, FillMode);
    }
  }
}

void CmdDrawCircle(int cx, int cy, int radius, byte PixelMode, byte FillMode)
{
  CmdDrawEllipse(cx, cy, radius, radius, PixelMode, FillMode);
}

char CircleOutEx(int x, int y, byte radius, unsigned long options)
{
  if (!LcdInitialized())
    return 1;
  byte pixelMode, fillMode;
  if (CmdResolveDrawingMode(options, &pixelMode, &fillMode))
    CmdDrawCircle(x, y, radius, pixelMode, fillMode);
  return 0;
}

char LineOutEx(int x1, int y1, int x2, int y2, unsigned long options)
{
  if (!LcdInitialized())
    return 1;
  byte pixelMode, fillMode;
  if (CmdResolveDrawingMode(options, &pixelMode, &fillMode))
    CmdDrawLine(x1, y1, x2, y2, pixelMode);
  return 0;
}

char PointOutEx(int x, int y, unsigned long options)
{
  if (!LcdInitialized())
    return 1;
  byte pixelMode, fillMode;
  if (CmdResolveDrawingMode(options, &pixelMode, &fillMode))
    CmdSetPixel(x, y, pixelMode);
  return 0;
}

char RectOutEx(int x, int y, int width, int height, unsigned long options)
{
  if (!LcdInitialized())
    return 1;
  byte pixelMode, fillMode;
  if (CmdResolveDrawingMode(options, &pixelMode, &fillMode))
    CmdDrawRect(x, y, width, height, pixelMode, fillMode);
  return 0;
}

char TextOutEx(int x, int y, char* str, unsigned long options)
{
  if (!LcdInitialized())
    return 1;
//  byte pixelMode, fillMode;
//  if (CmdResolveDrawingMode(options, &pixelMode, &fillMode))
//    CmdDrawRect(x, y, width, height, pixelMode);
  return 0;
}

char NumOutEx(int x, int y, int value, unsigned long options)
{
  if (!LcdInitialized())
    return 1;
  return 0;
}

char EllipseOutEx(int x, int y, byte radiusX, byte radiusY, unsigned long options)
{
  if (!LcdInitialized())
    return 1;
  byte pixelMode, fillMode;
  if (CmdResolveDrawingMode(options, &pixelMode, &fillMode))
    CmdDrawEllipse(x, y, radiusX, radiusY, pixelMode, fillMode);
  return 0;
}

char PolyOutEx(PLocationType points, unsigned long options)
{
  return 0;
}

char GraphicOutEx(int x, int y, char* filename, unsigned long options)
{
  return 0;
}

char GraphicArrayOutEx(int x, int y, byte* data, unsigned long options)
{
  return 0;
}

OS: Win XP Home 32,
path is :

Code: Select all

C:\CSLite\bin;C:\CSLite\tools;C:\Programme\NVIDIA....
(verified)
bcc diagnostics says:
hc_bcc diagn.zip
(8.57 KiB) Downloaded 387 times
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: EV3 Firmware download via BricxCC

Post by afanofosc »

What does this have to do with EV3 firmware download via BricxCC?

The header files must not be put into the project manager, period.

Have you tried sending an email to the author of BricxCC?

The code you pasted in is not "example" code. It is library code. The sample code is in the files with the word "test" in their name, such as lcd_test_c.c

You can't break an existing install of BricxCC by extracting a new test release zip over the existing install.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: EV3 Firmware download via BricxCC

Post by afanofosc »

joto1000 wrote:Hello, I'm new with EV3.

What do I have to do to get a C Code running on EV3?
I followed the 9 steps mentioned above, but I don't get it running on my EV3.

What should I do with the files from the lms_api? Do I have to link or compile them? And how can I do this?

Can anybody help me ;) ?

I would highly recommend emailing the author of BricxCC for assistance. Did you watch his videos about this subject on YouTube?

Just so it is abundantly clear, it is not terribly useful to run native code on the EV3 in this manner. At some point in the future it will be much more useful, i.e., when there is a nice comm layer to the EV3 when it is not running the standard VM executable but all the LMS kernel modules are correctly loaded. It is possible to compile and download code from BricxCC to an EV3 booting up from a micro SD card via SCP but that is not something I would recommend a novice computer user try.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: EV3 Firmware download via BricxCC

Post by HaWe »

thank you!
It was not clear that the code I used was no code I might use.
I now tried the screen test file code, and it works.

But out_test_cpp does not work, here is another error:
out_test_cpp.cpp: In function 'int main()':
out_test_cpp.cpp:31: error: 'Wait' was not declared in this scope
make: *** [out_test_cpp] Error 1
Anyway, sorry if I abused your thread to post sth off-topic, but in my understanding the problem I reported could be related to the the release http://bricxcc.sourceforge.net/test_rel ... 130912.zip which you mentioned in your TOP. I admittedly don't understand anything about firmware or new firmware or firmware on SD cards , but you wrote
" if a few of you with EV3s could try it out and let me know if you run into trouble I would be extremely grateful." So I tried it out, reported some trouble, and I thought that was what you might be grateful about (regardless if there might be other experienced users who could provide help instead).

About that project manager thing: In the read_1st txt was written:
25. The ... tools are your friends. Use them.
Use Ctrl+Enter to ... include (C/C++) to open the referenced file.
...
30. To successfully compile C/C++ projects you will need to create a project file for the main
source file. View|Project Manager (Ctrl+Alt+F11). This will list the main source file.
Additional required source code files (not headers) need to be listed in this (resizable) window.
I didn't understand that this means that headers do not only not need to be listet but instead are forbidden to be listed and so the project manager is supposed to be no friend to use in this case.

But finally, why should we suddenly start " emailing the author of BricxCC for assistance"?
Is the "assisting author of BricxCC" no longer member of this forum?
What about help from other experienced users if the "author of BricxCC" might be too busy in the moment (but of course appreciating also particularly the author to join the discussion)?
Is this forum not for users to ask questions about BCC and publicly communicate problems and all that any longer?
What for instead?
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: EV3 Firmware download via BricxCC

Post by afanofosc »

I ask that people who try out alpha pre-release versions of BricxCC email me since otherwise there is way too much noise in these forums.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: EV3 Firmware download via BricxCC

Post by HaWe »

yes man, all over the noise - same to me, it's coming from getting older and older I guess... :?
totokan
Posts: 45
Joined: 28 Sep 2013, 04:22

Re: EV3 Firmware download via BricxCC

Post by totokan »

Here is a guide I put together for my students, I think it may make things a bit more clear for you Doc. You add the .c files to project manager, not the .h. The header (.h file) should be included in your program at the top, #include "ev3_lcd.h" and the corresponding .c file (ev3_lcd.c) added to the project manager.
https://docs.google.com/document/d/1tA2 ... sp=sharing
joto1000
Posts: 4
Joined: 02 Oct 2013, 08:09

Re: EV3 Firmware download via BricxCC

Post by joto1000 »

Thanks totokan, that is exactly what I'm looking for.
Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests