KS0713

KS0713 Driver Module and modified GLCD.bas by Mark Rodgers

Modification Details

The two pieces of code below are modifications to existing code supplied with the current Swordfish Compiler(Ver 2.0.0.2).

The first piece is named KS0713.bas and is a modified version of S1D10605.bas

The Samsung KS0713 and Epson S1D10605 appear to be very similar and share the same command codes when addressing the internal processor, there are some minor differences in the particular displays chosen for these tests, but it seems the core code(written by David) is transferable.

The second piece of code is named GLCD_KS0173.bas and is a modified version of the compilers supplied GLCD.bas, the only changes are to allow the KS0713 to be brought into the code one writes using the compilers syntax, namely #option GLCD_MODEL = KS0713

No other changes affecting the normal use of this module are made and it can be used without problem on any existing code.

Display Type

The display used to confirm operation was a Displaytech 64128COG series obtained from RS Components(in the UK), part number 532-7114, it was chosen primarily due to a very low cost of 7.40 for one off.

The display was hardwired to operate in the parallel mode(take PS pin high) and to use 6800 mode(take MI pin high) and the pins DB0 to DB7, RST, E, R/W, RS, RST and CS1B were connected to the 18F452.

Details Of Use

The use of the driver is similar to the existing drivers with the exception of one addition in the KS0713.bas and that is a function called GLCD_FLIP_DISPLAY. This function allows the KS0713 display to be flipped over allowing the display to be mounted with its pins at the top or the bottom, at the moment this is not able to be achieved at run time, only at compile time. The function is Boolean and defaults, if not declared, as GLCD_FLIP_DISPLAY=False, error trapping and reporting is employed.

All other pins are as the exiting defaults and are changeable in the same way as any other driver supplied with the compliler.

How To Integrate With Swordfish

The Graphic LCD components of Swordfish are in Mecanique\Swordfish\Library\GLCD, the existing file GLCD.bas should be renamed GLCD_original.bas(or something you like) and the GLCD_KS0713.bas here should be copied in to the directory and renamed GLCD.bas, the KS0713 is now supported.

To recap the usage:-

Declare that you wish to bring the KS0713 into your program:-

  • #option GLCD_MODEL = KS0713

Decide which way up the display should be:-

  • GLCD_FLIP_DISPLAY=False, system default if not declared
  • GLCD_FLIP_DISPLAY=True, inverts the display

I take no credit for the core of the code presented here, that lies with David and Steven.


The KS0713.bas Module code:-

{
****************************************************************
*  Name    : KS0713.BAS                                        *
*  Author  : David John Barker                                 *
*  Modified: Mark Rodgers, 18,04,07                            *
*  Notice  : Copyright (c) 2006 Mecanique                      *
*          : All Rights Reserved                               *
*  Date    : 02/05/2006                                        *
*  Version : 1.0                                               *
*  Notes   : This is "S1D10605.bas" Modified to work with      *
*            the SAMSUNG KS0713 COG-128X64 chipset and was     *
*            tested using Displaytech 64128COG series from     *
*            RS, part number 532-7114.                         *
*            The module is hardwired For parallel use(PS High) *
*            and 6800 mode(MI High).                           *
*            A new command has been added to allow the display *
*            to be mounted either way up and still print the   *
*            characters correctly.                             *
*            This new command is GLCD_FLIP_DISPLAY.            *
*            It is Boolean and defaults(if not declared) False.*
****************************************************************
}
Module KS0713

// import the graphics module...
#DEFINE GLCD_PIXEL_01
#DEFINE GLCD_COLOR_01
#DEFINE GLCD_XY_08
Include "Graphics.bas"
Include "system.bas"  

// default module options - user options can override these values...
#option GLCD_DATA = PORTD        // Data port
#option GLCD_RS = PORTE.2        'modified for KS0713, Data Or command
#option GLCD_EN = PORTE.0        // EN pin
#option GLCD_RW = PORTC.0        // RW pin
#option GLCD_CS1 = PORTE.1       // chip Select
#option GLCD_RST = PORTC.1       // reset
#option GLCD_ASPECT_RATIO = 100  'modified For KS0713, aspect ratio, smaller number will squeeze y For GLCD circles And Box
#option GLCD_INIT_DELAY = 100    // initialisation delay (ms)
#option GLCD_FLIP_DISPLAY=False  'normal display mode(not upsidedown)

// validate Data port...
#IF IsOption(GLCD_DATA) 
   #IF Not IsValidPort(GLCD_DATA)
      #ERROR GLCD_DATA, "Invalid option. DATA must be a valid port name."
   #ENDIF
   #IFDEF GLCD_DATA@ Then
      #ERROR GLCD_DATA@, "Invalid option. DATA port cannot be a single bit value."
   #ENDIF
#ENDIF

    'validate RS pin, modified for KS0713
#IF IsOption(GLCD_RS) And Not IsValidPortPin(GLCD_RS) 
   #ERROR GLCD_RS, "Invalid option. RS must be a valid port pin."
#ENDIF

// validate EN pin...
#IF IsOption(GLCD_EN) And Not IsValidPortPin(GLCD_EN) 
   #ERROR GLCD_EN, "Invalid option. EN must be a valid port pin."
#ENDIF

// validate RW pin...
#IF IsOption(GLCD_RW) And Not IsValidPortPin(GLCD_RW) 
   #ERROR GLCD_RW, "Invalid option. RW must be a valid port pin."
#ENDIF

// validate CS1 pin...
#IF IsOption(GLCD_CS1) And Not IsValidPortPin(GLCD_CS1) 
   #ERROR GLCD_CS1, "Invalid option. CS1 must be a valid port pin."
#ENDIF

// validate CS2 pin...
#IF IsOption(GLCD_RST) And Not IsValidPortPin(GLCD_RST) 
   #ERROR GLCD_RST, "Invalid option. RST must be a valid port pin."
#ENDIF

// validate initialisation delay...
#IF IsOption(GLCD_INIT_DELAY)
   #IF Not (GLCD_INIT_DELAY in (0 To 1000))
      #ERROR GLCD_INIT_DELAY, "Invalid option. GLCD initialize delay must be between 0 and 1000 (ms)."
   #ENDIF
#ENDIF

    'test for boolean value when FLIP_DISPLAY is specified
#IF IsOption(GLCD_FLIP_DISPLAY) And Not False
    #IF IsOption(GLCD_FLIP_DISPLAY) And Not True 
        #ERROR GLCD_FLIP_DISPLAY, "Invalid option. Value must be True or False (Boolean)" 
    #ENDIF
#ENDIF

// now create Data TRIS...
#option _GLCD_DATA_TRIS = GetTRIS(GLCD_DATA)

// GLCD width And height...
Public Const
   GLCDWidth = 128,
   GLCDHeight = 64,
   Flip=GLCD_FLIP_DISPLAY

// x, y position...
Public Dim
   Pos As TPosition


    'KS0713 control commands, modified for KS0713   
Const
   cmdOn = $AF,
   cmdOff = $AE,
   cmdStartLine = $40,
   cmdPage = $B0,
   cmdColumnMS = $10,
   cmdColumnLS = $0F,   
   cmdADCNormal = $A0,
   cmdADCReverse = $A1,
   cmdDisplayNormal = $A6,
   cmdDisplayReverse = $A7,
   cmdDisplayAllOff = $A4,
   cmdDisplayAllOn = $A5,
   cmdBias19 = $A2,
   cmdBias17 = $A3,
   cmdModify = $E0,
   cmdEnd = $EE,
   cmdReset = $E2,
   cmdScanTopBottom = $C0,
   cmdScanBottomTop = $C8,
   cmdPowerControl = $28,
   cmdV5Voltage = $20,
   cmdContrast = $81, 
   cmdStaticOn = $AD,
   cmdStaticOff = $AC, 
   GLCDDelay = GLCD_INIT_DELAY,
   FLIP_DISPLAY=GLCD_FLIP_DISPLAY     

// port And pin settings, these are brought into
// the program by using the above options...
Dim        
   Data As GLCD_DATA,           // Data in (PORT) 
   TRISData As _GLCD_DATA_TRIS, // Data TRIS
   RS As GLCD_RS.GLCD_RS@,      'modified for KS0713, RC pin (Data Or command)
   EN As GLCD_EN.GLCD_EN@,      // EN pin
   RW As GLCD_RW.GLCD_RW@,      // RW pin (Read Or write)
   CS1 As GLCD_CS1.GLCD_CS1@,   // chip Select
   RST As GLCD_RST.GLCD_RST@    // reset

{
****************************************************************************
* Name    : StrobeEN (Private)                                             *
* Purpose : Strobe the GLCD EN pin                                         *
****************************************************************************
}    
Inline Sub StrobeEN()
   CS1 = 0
   EN = 1
   DelayUS(1)
   EN = 0 
   CS1 = 1
End Sub
{
****************************************************************************
* Name    : GLCDData (PRIVATE)                                             *
* Purpose : Switch To GLCD Data mode                                       *
*           Modified For KS0713                                            *
****************************************************************************
}    
Inline Sub GLCDData()
   RS = 1
End Sub
{
****************************************************************************
* Name    : GLCDInst (PRIVATE)                                             *
* Purpose : Switch To GLCD instruction mode                                *
*           Modified For KS0713                                            *
****************************************************************************
}    
Inline Sub GLCDInst()
   RS = 0	
End Sub
{
****************************************************************************
* Name    : GLCDRead (PRIVATE)                                             *
* Purpose : Set GLCD To Read mode                                          *
****************************************************************************
}    
Inline Sub GLCDRead()
   RW = 1
End Sub
{
****************************************************************************
* Name    : GLCDWrite (PRIVATE)                                            *
* Purpose : Set GLCD To write mode                                         *
****************************************************************************
}    
Inline Sub GLCDWrite()
   RW = 0	
End Sub
{
****************************************************************************
* Name    : WaitForIdle (PRIVATE)                                          *
* Purpose : Block further GLCD access Until signalled ready.               *
****************************************************************************
}     
Sub WaitForIdle()
   Dim Timeout As Byte
   Timeout = $FF 
   TRISData = $FF     // Set Data bus To Input
   GLCDInst	          // instruction Data
   GLCDRead           // Read mode
   Repeat
      ClrWDT
      Dec(Timeout)
      StrobeEN 
   Until (Data.7 = 0) Or (Timeout = 0)
End Sub 
{
****************************************************************************
* Name    : SetData (PRIVATE)                                              *
* Purpose : Write a Data Byte To GLCD                                      *
****************************************************************************
}     
Sub SetData(pData As Byte) 
   WaitForIdle      // block Until Not busy
   TRISData = $00   // Set Data bus To Output
   GLCDData         // access display RAM Data
   GLCDWrite        // write mode
   Data = pData     // write To the bus
   StrobeEN         // write To GLCD
End Sub
{
****************************************************************************
* Name    : GetData (PRIVATE)                                              *
* Purpose : Read Byte from GLCD                                            *
****************************************************************************
}     
Function GetData() As Byte
   WaitForIdle      // block Until Not busy
   TRISData = $FF   // Set Data bus To Input
   GLCDData         // access display RAM Data
   GLCDRead         // Read mode
   StrobeEN         // latch Data
   Result = Data    // get the Data
End Function  
{
****************************************************************************
* Name    : Command (PRIVATE)                                              *
* Purpose : Write a command Byte To GLCD                                   *
****************************************************************************
}     
Sub Command(pCommand As Byte) 
   WaitForIdle          // block Until Not busy
   TRISData = $00       // Set Data bus To Output
   GLCDInst             // instruction mode
   GLCDWrite            // write mode
   Data = pCommand      // write To the bus
   StrobeEN             // write To GLCD
End Sub
{
****************************************************************************
* Name    : CommandWithData (PRIVATE)                                      *
* Purpose : Write a command plus extra Data Byte To GLCD                   *
****************************************************************************
}     
Sub CommandWithData(pCommand,pData As Byte) 
   WaitForIdle          // block Until Not busy
   TRISData = $00       // Set Data bus To Output
   GLCDInst             // instruction mode
   GLCDWrite            // write mode
   Data = pCommand      // write To the bus
   StrobeEN             // write To GLCD
   Data = pData
   StrobeEN
End Sub
{
****************************************************************************
* Name    : SetPosition (PRIVATE)                                          *
* Purpose : Set GLCD x And y positions                                     *
*         : Modified for use with "GLCD_FLIP_DISPLAY" command              * 
****************************************************************************
}     
Sub SetPosition()     
   Command(cmdPage Or Pos.y)           // Set y position
   If Flip=False Then
        Command($10 Or (Pos.x + 4 >> 4))    // Set x, upper nibble
        Command($0F And Pos.x + 4)          // Set x, lower nibble
   EndIf

   If Flip=True Then
        Command($10 Or (Pos.x  >> 4))   'setting For the KS0713, Set x, upper nibble
        Command($0F And Pos.x )         'setting For the KS0713, Set x, lower nibble
   EndIf
End Sub
{
****************************************************************************
* Name    : WriteByte                                                      *
* Purpose : Write a Byte At x, PAGE                                        *
****************************************************************************
} 
Public Sub WriteByte(pValue As Byte)
   SetPosition
   SetData(pValue)
End Sub 
{
****************************************************************************
* Name    : ReadByte                                                       *
* Purpose : Read a Byte At x, PAGE                                         *
****************************************************************************
} 
Public Function ReadByte() As Byte
   SetPosition
   GetData
   Result = GetData
End Function
{
****************************************************************************
* Name    : SetPixel                                                       *
* Purpose : Set Pixel At Pixel location x,y                                *
****************************************************************************
} 
Public Sub SetPixel(pX, pY As Byte)
   Dim YBit As Byte
   Dim Pixel As Byte

   If (pX < GLCDWidth) And (pY < GLCDHeight) Then

      YBit = 1 << (pY Mod 8)
      Pos.y = pY / 8
      Pos.x = pX

      SetPosition
      GetData
      Pixel = GetData  

      // pen is white...
      If Pen.Color = 0 Then
         If Pen.Mode = pmCopy Then
            YBit = Not YBit
            Pixel = Pixel And YBit
         EndIf

      // pen is black...
      Else

         // pen copy Or merge...
         If Pen.Mode <> pmXOR Then
            Pixel = Pixel Or YBit

         // pen XOR
         Else
            If (Pixel And YBit) = 0 Then
               Pixel = Pixel Or YBit
            Else
               YBit = Not YBit
               Pixel = Pixel And YBit
            EndIf      
         EndIf
      EndIf
      SetPosition
      SetData(Pixel)
   EndIf
End Sub
{
****************************************************************************
* Name    : GetPixel                                                       *
* Purpose : Return Pixel colour At Pixel position x, y                     *
****************************************************************************
}
Public Function GetPixel(pX, pY As Byte) As TColor
   Dim Pixel As Byte
   Pos.y = pY / 8
   Pos.x = pX
   SetPosition
   GetData
   Pixel = GetData >> (pY Mod 8) 
   Result = Pixel.0  
End Function
{
****************************************************************************
* Name    : Cls                                                            *
* Purpose : Clear the GLCD screen                                          *
*         : Modified For use with "GLCD_FLIP_DISPLAY" Command              *
****************************************************************************
} 
Public Sub Cls()
   Dim x, y As Byte
   y = 0
   If Flip=False Then
    x = 4
   EndIf
   If Flip=True Then
    x=0                'use when flipped
   EndIf   
   Repeat	
	  Command(cmdPage Or y)
      Repeat    	
         Command(cmdColumnMS Or (x >> 4)) 
         Command(cmdColumnLS And x) 
         SetData($00)
         Inc(x)
      Until x > 131
	  Inc(y)
   Until y > 7	
End Sub 
{
****************************************************************************
* Name    :  SetContrast                                                   *
* Purpose :  Set the GLCD contrast                                         *
****************************************************************************
}    
Public Sub SetContrast(pValue As Byte)
   CommandWithData(cmdContrast,pValue)
End Sub
{
****************************************************************************
* Name    : Sleep                                                          *
* Purpose : Put the GLCD To Sleep Or wake it up                            *
****************************************************************************
}    
Public Sub Sleep(pOn As Boolean = true)
   If pOn Then
      Command(cmdOff)
      Command(cmdDisplayAllOn)
      Command(cmdStaticOff)
   Else
      Command(cmdDisplayAllOff)
      Command(cmdOn)
   EndIf   
End Sub
{
****************************************************************************
* Name    : StandBy                                                        *
* Purpose : Put the GLCD into standby mode Or wake it up                   *
****************************************************************************
}    
Public Sub StandBy(pOn As Boolean = true)
   If pOn Then
      Command(cmdOff)
      Command(cmdDisplayAllOn)
      CommandWithData(cmdStaticOn, 3)
   Else
      Command(cmdStaticOff)
      Command(cmdDisplayAllOff)
      Command(cmdOn)
   EndIf
End Sub
{
****************************************************************************
* Name    : Initialize                                                     *
* Purpose : Configure the GLCD before use                                  *
*         : This section is Modified To work with the KS0713               *
****************************************************************************
} 
Sub Initialize()
   Pos.x = 0
   Pos.y = 0  
   DelayMS(GLCDDelay) // start up delay, allow GLCD To settle
   Output(RW)         // Read/write is Low
   Low(EN)            // Enable is Low
   Output(RS)         'setting for the KS0713' Data Or instruction is Low (command mode)
   Output(CS1)        // screen 
   High(RST)          // reset

   Command(cmdReset)                // software reset
   Command(cmdBias19)               'setting for the KS0713
   If Flip=False Then
    Command(cmdADCReverse)          'setting For the KS0713, ADC Output = reversed
   EndIf
    If Flip=True Then
    Command(cmdADCNormal)           'setting For the KS0713, ADC Output = normal
   EndIf
   Command(cmdDisplayAllOff)        // display all point normal
   Command(cmdV5Voltage Or 5)       'setting for the KS0713, internal resistor ratio (0..7)
   Command(cmdPowerControl Or $07)  // internal power supply mode

   SetContrast(25)                  'setting for the KS0713, LCD contrast
   Command(cmdStaticOff)            // static indicator is off
   Command(cmdOn)                   // display is On
   If Flip=False Then
        Command(cmdScanBottomTop)   'setting For the KS0713, scan bottom to top 
   EndIf
   If Flip=True Then
        Command(cmdScanTopBottom)   'setting For the KS0713, scan top to bottom
   EndIf
   Command(cmdDisplayNormal)        // display normal polarity(not negative!)
   Command(cmdStartLine)            // display start Line (Or value For Line number) 
End Sub


Initialize

The GLCD_KS0713.bas Module code:-

{
****************************************************************
*  Name    : GLCD_KS0713.BAS                                   *
*  Author  : David John Barker                                 *
*          : Steven Wright                                     *
*  Modified: Mark Rodgers 19,04,07                             *
*  Notice  : Copyright (c) 2006 Mecanique                      *
*          : All Rights Reserved                               *
*  Date    : 02/05/2006                                        *
*  Version : 1.2                                               *
*  Notes   : 1.2 Added CreateMask() For 1 Bit y fonts          *
*          : 1.3 Added support For S1D13700                    *
*          : Modified To support SAMSUNG KS0713                *
****************************************************************
}
Module GLCD

// validate model...
#option GLCD_MODEL = KS0108
#IF Not (GLCD_MODEL in (KS0108, S1D10605, S1D15G00, SED1520, S1D13700, KS0713))
   #ERROR GLCD_MODEL, "Invalid option. GLCD model not recognized."
#ENDIF

// import KS0108 driver...
#IF GLCD_MODEL = KS0108
Include "KS0108.bas"                
Public Dim
   Pos As KS0108.Pos, 
   Cls As KS0108.Cls,
   SetPixel As KS0108.SetPixel,
   WriteByte As KS0108.WriteByte,
   ReadByte As KS0108.ReadByte,
   GetPixel As KS0108.GetPixel
#ENDIF

// import S1D10605 driver...
#IF GLCD_MODEL = S1D10605
Include "S1D10605.bas"               
Public Dim
   Pos As S1D10605.Pos, 
   Cls As S1D10605.Cls,
   SetPixel As S1D10605.SetPixel,
   SetContrast As S1D10605.SetContrast,
   WriteByte As S1D10605.WriteByte,
   ReadByte As S1D10605.ReadByte,
   GetPixel As S1D10605.GetPixel,
   Sleep As S1D10605.Sleep,
   StandBy As S1D10605.StandBy   
#ENDIF

// import S1D15G00 driver...
#IF GLCD_MODEL = S1D15G00
Include "S1D15G00.bas"  
Public Dim
   Pos As S1D15G00.Pos, 
   Cls As S1D15G00.Cls,
   SetPixel As S1D15G00.SetPixel,
   SetContrast As S1D15G00.SetContrast,
   Fill As S1D15G00.Fill,
   Contrast As S1D15G00.Contrast,
   MakeColor As S1D15G00.MakeColor,
   SetImage As S1D15G00.SetImage,
   CopyImage As S1D15G00.CopyImage
#ENDIF

// import SED1520 driver...
#IF GLCD_MODEL = SED1520
Include "SED1520.bas"  
Public Dim
   Pos As SED1520.Pos, 
   Cls As SED1520.Cls,
   SetPixel As SED1520.SetPixel,
   WriteByte As SED1520.WriteByte,
   ReadByte As SED1520.ReadByte,
   GetPixel As SED1520.GetPixel
#ENDIF

// import S1D13700 driver...
#IF GLCD_MODEL = S1D13700
Include "S1D13700.bas"  
Public Dim
   Pos As S1D13700.Pos, 
   Cls As S1D13700.Cls,
   SetPixel As S1D13700.SetPixel,
   WriteByte As S1D13700.WriteByte,
   ReadByte As S1D13700.ReadByte,
   GetPixel As S1D13700.GetPixel,
   ShowLayer As S1D13700.ShowLayer,
   SwitchLayer As S1D13700.SwitchLayer,
   Fill As S1D13700.Fill,
   SetImage As S1D13700.SetImage
#ENDIF

    'load the KS0713 driver file
#IF GLCD_MODEL = KS0713
Include "KS0713.bas"               
Public Dim
   Pos As KS0713.Pos, 
   Cls As KS0713.Cls,
   SetPixel As KS0713.SetPixel,
   SetContrast As KS0713.SetContrast,
   WriteByte As KS0713.WriteByte,
   ReadByte As KS0713.ReadByte,
   GetPixel As KS0713.GetPixel,
   Sleep As KS0713.Sleep,
   StandBy As KS0713.StandBy
#ENDIF

// import graphics And math...
Include "Graphics.bas"
Include "math.bas"

// import constants...
Public Const
   Width = GLCDWidth,
   Height = GLCDHeight

// text out alignment constants
Public Const
   taLeft = $01,
   taCenter = $02,
   taRight = $04

// make graphics vriables available For this
// module interface
Public Dim
   SetFont As Graphics.SetFont,
   TextWidth As Graphics.TextWidth,
   Pen As Graphics.Pen,
   Brush As Graphics.Brush,
   Font As Graphics.Font,
   TextAlign As Byte

// default is equal apect ratio, change in GLCD model CORE...
#option GLCD_ASPECT_RATIO = 100
Const AspectRatio = GLCD_ASPECT_RATIO 

{
****************************************************************************
* Name    : WriteImageByte (PRIVATE)                                       *
* Purpose : Write an image Byte To GLCD At Pixel position x,y              *
****************************************************************************
} 
#IFNDEF GLCD_SETIMAGE
#IFDEF GLCD_PIXEL_01
Sub WriteImageByte(pX, pY As TXY, pValue As Byte)
   Dim Line, ShiftValue, YBit, YBitReverse As Byte
   Dim LastPosY As Byte

   LastPosY = Pos.y           // SAVE y position
   YBit = pY Mod 8            // Offset
   YBitReverse = 8 - YBit     // reverse Offset
   Pos.y = pY / 8             // align To PAGE
   Pos.x = pX                 // SAVE x

   // get first Byte...
   Line = ReadByte   

   // Mask, If needed...
   If Pen.Mode = pmCopy Then
      Line = Line << YBitReverse
      Line = Line >> YBitReverse
   EndIf

   // merge Then write Data...   
   ShiftValue = pValue << YBit
   If Pen.Mode = pmXOR Then
      Line = Line Xor ShiftValue
   Else
      Line = Line Or ShiftValue
   EndIf
   WriteByte(Line)

   // get Next Byte...
   If YBit <> 0 Then
      Inc(Pos.y)
      Line = ReadByte

      // Mask, If needed...
      If Pen.Mode = pmCopy Then
         Line = Line >> YBit
         Line = Line << YBit
      EndIf

      // merge Then write Data...
      ShiftValue = pValue >> YBitReverse
      If Pen.Mode = pmXOR Then
         Line = Line Xor ShiftValue
      Else
         Line = Line Or ShiftValue
      EndIf   
      WriteByte(Line) 
   EndIf

   // Restore y position...
   Pos.y = LastPosY   
End Sub 
{
****************************************************************************
* Name    : SetImage                                                       *
* Purpose : BitBlit image To GLCD At Pixel location x,y                    *
*         : NOTE - This subroutine only supports $01 (monochrome) bitmaps  *
*         :        For drivers with ReadByte And WriteByte implemented     *
****************************************************************************
} 
Public Sub SetImage(pX, pY As TXY, ByRefConst pImage() As Byte, pMode As Byte = cmCopy)
   Dim Image As TImage
   Dim x,y,Width,Height As Byte
   Dim Line As Byte
   Dim LastPen As TPen
   Dim Index As Word

   LastPen = Pen
   Pen.Mode = pMode

   // get bitmap Width And Height...
   Image.Width = pImage(1)
   Image.Height = pImage(2)

   // Byte aligned Bit blit... 
   Index = 4
   y = pY
   Height = Image.Height / 8
   While Height > 0
      x = pX
      Width = Image.Width
      While Width > 0
         WriteImageByte(x,y,pImage(Index))
         Inc(Index)
         Inc(x)
         Dec(Width)
      Wend
      Inc(y,8)
      Dec(Height)
   Wend 

   // non Byte aligned Bit blit...
   pY = y
   Image.Height = Image.Height Mod 8   
   If Image.Height > 0 Then
      x = pX
      Width = Image.Width
      While Width > 0     
         Line = pImage(Index)
         Height = Image.Height
         y = pY
         While Height > 0
            Pen.Color = Line.0
            SetPixel(x,y)
            Line = Line >> 1
            Dec(Height)
            Inc(y)
         Wend
         Inc(Index)
         Dec(Width)
         Inc(x)
      Wend
   EndIf   
   Pen = LastPen   
End Sub
#ENDIF // GLCD_PIXEL_01
#ENDIF // GLCD_SETIMAGE

{
****************************************************************************
* Name    : Line                                                           *
* Purpose : Draws a Line using a Bresenham Line drawing algorithm          *
****************************************************************************
}
#IFNDEF GLCD_LINE
Public Sub Line(x1, y1, x2, y2 As TXY)
   Dim P, diff As LongInt
   Dim incx, incy  As Integer
   Dim dx_ge_dy As Boolean
   Dim dy, dx, delta As Word
   Dim PenPos As Byte
   Dim Length As Byte

   // x direction...
   incx = 1
   If x1 > x2 Then
      incx = -1
   EndIf   

   // y direction
   incy = 1
   If y1 > y2 Then
      incy = -1
   EndIf   

   dx = abs(x2 - x1)
   dy = abs(y2 - y1)

   If dx >= dy Then
      dx_ge_dy = true
      dy = dy * 2
      P = dy - dx
      delta = dx
   Else
      dx_ge_dy = false
      dx = dx * 2
      P = dx - dy
      delta = dy
   EndIf   
   diff = P - delta

   Inc(delta)

   PenPos = 0
   Length = Pen.Style

   Repeat
      If Pen.Style > 0 Then
         If PenPos < Length Then
            SetPixel(x1, y1)
         EndIf
         Inc(PenPos)
         If PenPos > Length Then
            PenPos = 0
         EndIf
      Else
         SetPixel(x1, y1) 
      EndIf
      If P < 0 Then
         If dx_ge_dy Then
            Inc(P, dy)
            Inc(x1, incx)
         Else
            Inc(P, dx)
            Inc(y1, incy)
         EndIf   
      Else
         Inc(P, diff)
         Inc(x1, incx)
         Inc(y1, incy)
     EndIf
     Dec(delta)
   Until delta = 0 
End Sub
#ENDIF // GLCD_LINE

{
****************************************************************************
* Name    : Plot (PRIVATE)                                                 *
* Purpose : Plots a Set of ellipse quadrant points                         *
****************************************************************************
}
#IFNDEF GLCD_ELLIPSE
Sub Plot(pCX, pCY, pX, pY As TXY)
   SetPixel(pCX + pX, pCY + pY)
   SetPixel(pCX - pX, pCY + pY)
   SetPixel(pCX - pX, pCY - pY)
   SetPixel(pCX + pX, pCY - pY)
End Sub
{
****************************************************************************
* Name    : Ellipse                                                        *
* Purpose : Draws an ellipse                                               *
*         : A Fast Bresenham Type Algorithm For Drawing Ellipses           *
*         : John Kennedy                                                   *
*         : Mathematics Department, Santa Monica College                   *
*         : Santa Monica, CA 90405 - http://homepage.smc.edu/kennedy_john  *
****************************************************************************
}
Public Sub Ellipse(pCX, pCY, pXRadius, pYRadius As TXY)
  Dim x, y As TXY
  Dim XChange, YChange As LongInt
  Dim EllipseError As LongInt
  Dim TwoASquare, TwoBSquare As LongInt
  Dim StoppingX, StoppingY As LongInt
  Dim PenPos As Byte
  Dim Length As Byte

  Length = Pen.Style

  TwoASquare = 2 * pXRadius * pXRadius
  TwoBSquare = 2 * pYRadius * pYRadius
  x = pXRadius
  y = 0
  XChange = pYRadius * pYRadius * (1 - 2 * pXRadius)
  YChange = pXRadius * pXRadius
  EllipseError = 0
  StoppingX = TwoBSquare * pXRadius
  StoppingY = 0
  PenPos = 0
  While StoppingX >= StoppingY  
      If Pen.Style > 0 Then
         If PenPos < Length Then
            Plot(pCX, pCY, x, y)
         EndIf
         Inc(PenPos)
         If PenPos > Length Then
            PenPos = 0
         EndIf
      Else
         Plot(pCX, pCY, x, y)
      EndIf
      Inc(y)
      Inc(StoppingY, TwoASquare)
      Inc(EllipseError, YChange)
      Inc(YChange,TwoASquare)
      If (2 * EllipseError + XChange) > 0  Then
          Dec(x)
          Dec(StoppingX, TwoBSquare)
          Inc(EllipseError, XChange)
          Inc(XChange,TwoBSquare)
      EndIf
  Wend

  x = 0
  y = pYRadius
  XChange = pYRadius * pYRadius
  YChange = pXRadius * pXRadius * (1 - 2 * pYRadius)
  EllipseError = 0
  StoppingX = 0
  StoppingY = TwoASquare * pYRadius
  PenPos = 0
  While StoppingX <= StoppingY 
      If Pen.Style > 0 Then
         If PenPos < Length Then
            Plot(pCX, pCY, x, y)
         EndIf
         Inc(PenPos)
         If PenPos > Length Then
            PenPos = 0
         EndIf
      Else
         Plot(pCX, pCY, x, y)
      EndIf
      Inc(x)
      Inc(StoppingX, TwoBSquare)
      Inc(EllipseError, XChange)
      Inc(XChange,TwoBSquare)
      If (2 * EllipseError + YChange) > 0  Then
          Dec(y)
          Dec(StoppingY, TwoASquare)
          Inc(EllipseError, YChange)
          Inc(YChange,TwoASquare)
      EndIf
  Wend
End Sub
#ENDIF // GLCD_ELLIPSE

{
****************************************************************************
* Name    : Circle                                                         *
* Purpose : Draws a Circle, y is scaled To compensate For aspect ratio     *
****************************************************************************
} 
#IFNDEF GLCD_CIRCLE
Public Sub Circle(pCX, pCY, pRadius As TXY)
   #IF GLCD_ASPECT_RATIO <> 100
   Ellipse(pCX, pCY, pRadius, pRadius * AspectRatio / 100)
   #ELSE
   Ellipse(pCX, pCY, pRadius, pRadius)
   #ENDIF
End Sub
#ENDIF // GLCD_CIRCLE

{
****************************************************************************
* Name    : HLine (PRIVATE)                                                *
* Purpose : Draws a horizontal Line                                        *
****************************************************************************
}
#IFNDEF GLCD_RECTANGLE
Sub HLine(pX1, pX2, pY As TXY)
   Dim PenPos As Byte
   Dim Length As Byte
   PenPos = 0
   Length = Pen.Style
   While pX1 <= pX2
      If Pen.Style > 0 Then
         If PenPos < Length Then
            SetPixel(pX1,pY)
         EndIf
         Inc(PenPos)
         If PenPos > Length Then
            PenPos = 0
         EndIf
      Else
         SetPixel(pX1,pY)
      EndIf
      Inc(pX1)
   Wend   
End Sub
{
****************************************************************************
* Name    : VLine (PRIVATE)                                                *
* Purpose : Draw a vertical Line                                           *
****************************************************************************
}
Sub VLine(pX, pY1, pY2 As TXY)
   Dim PenPos As Byte
   Dim Length As Byte
   PenPos = 0
   Length = Pen.Style
   While pY1 <= pY2
      If Pen.Style > 0 Then
         If PenPos < Length Then
            SetPixel(pX,pY1)
         EndIf
         Inc(PenPos)
         If PenPos > Length Then
            PenPos = 0
         EndIf
      Else
         SetPixel(pX,pY1)
      EndIf
      Inc(pY1)
   Wend   
End Sub
{
****************************************************************************
* Name    : Rectangle                                                      *
* Purpose : Draws a rectangle                                              *
****************************************************************************
} 
Public Sub Rectangle(px1, py1, px2, py2 As TXY)
   Dim Swap As TXY

   If px2 < px1 Then
      Swap = px1
      px1 = px2
      px2 = Swap
   EndIf

   If py2 < py1 Then
      Swap = py1
      py1 = py2
      py2 = Swap
   EndIf

   HLine(px1, px2, py1)
   VLine(px2, py1, py2)
   HLine(px1, px2, py2)
   VLine(px1, py1, py2) 
End Sub
#ENDIF // GLCD_RECTANGLE

{
****************************************************************************
* Name    : Square                                                         *
* Purpose : Draws a square, y is scaled To compensate For aspect ratio     *
****************************************************************************
} 
#IFNDEF GLCD_SQUARE
Public Sub Square(pX, pY, pSize As TXY)
   #IF GLCD_ASPECT_RATIO <> 100
   Rectangle(pX, pY, pX + pSize, pY + pSize * AspectRatio / 100)
   #ELSE
   Rectangle(pX, pY, pX + pSize, pY + pSize)
   #ENDIF
End Sub
#ENDIF // GLCD_SQUARE

{
****************************************************************************
* Name    : MoveTo                                                         *
* Purpose : Moves graphics Cursor To given point before calling LineTo()   *
****************************************************************************
} 
Public Sub MoveTo(pX, pY As TXY)
   Pos.x = pX
   Pos.y = pY
End Sub
{
****************************************************************************
* Name    : LineTo                                                         *
* Purpose : Draws a Line from the current graphics Cursor position         *
****************************************************************************
} 
Public Sub LineTo(pX, pY As TXY)
   Line(Pos.x, Pos.y, pX, pY)
   Pos.x = pX
   Pos.y = pY
End Sub

// monchrome Font rendering, WriteChar has Not be implemented
// in main GLCD driver module...
#IFNDEF GLCD_WRITECHAR
#IFDEF GLCD_PIXEL_01
Dim 
   FCharLocation,    // unmodified y (Pixel) character location (Set in WriteChar)
   FMaskYPosition,   // current Mask y position
   FMaskYMax As TXY  // Max y position
{
****************************************************************************
* Name    : ApplyFontStyle (PRIVATE)                                       *
* Purpose : Apply Font rendering style                                     *
****************************************************************************
}   
Function ApplyFontStyle(pTarget, pSource As Byte) As Byte
   If Font.Style = fsXOR Then
      Result = pTarget Xor pSource
   Else
      Result = pTarget Or pSource
   EndIf
End Function
{
****************************************************************************
* Name    : CreateMask (PRIVATE)                                           *
* Purpose : Create a Font Mask - a 1 will preserve the background, 0 will  *
*         : Clear                                                          *
****************************************************************************
} 
Function CreateMask() As Byte
   Dim FontHeight As Byte
   FontHeight = FCharLocation + Font.Height 
   result = $FF
   Repeat
      result = result >> 1
      result.7 = 1
      If (FMaskYPosition >= FCharLocation) And (FMaskYPosition < FontHeight) Then
         result.7 = 0
      EndIf
      Inc(FMaskYPosition)
   Until FMaskYPosition >= FMaskYMax
   Inc(FMaskYMax,8)
End Function
{
****************************************************************************
* Name    : WriteCharacterByte (PRIVATE)                                   *
* Purpose : Write a Font character Byte To GLCD                            *
****************************************************************************
} 
Sub WriteCharacterByte(pValue As Byte)
   Dim Line, YBit, YBitReverse As Byte
   Dim LastPosY As Byte

   LastPosY = Pos.y         // SAVE y position
   YBit = Pos.y Mod 8       // Offset
   YBitReverse = 8 - YBit   // reverse Offset
   Pos.y = Pos.y / 8        // align To PAGE

   // get Data...
   Line = ReadByte

   // Mask, If required...
   If Font.Style = fsNormal Then
      FMaskYPosition = LastPosY                 // current y position
      FMaskYMax = FMaskYPosition + YBitReverse  
      Line = Line And CreateMask
   EndIf

   // apply Font style, Then write To GLCD...
   Line = ApplyFontStyle(Line,pValue << YBit)
   WriteByte(Line)

   // get Next Byte...
   If YBit <> 0 Then
      Inc(Pos.y)
      Line = ReadByte

      // Mask, If required...
      If Font.Style = fsNormal Then
         Line = Line And CreateMask
      EndIf

      // apply Font style, Then write To GLCD
      Line = ApplyFontStyle(Line, pValue >> YBitReverse)
      WriteByte(Line)
   EndIf

   // Restore y position...
   Pos.y = LastPosY
End Sub 
{
****************************************************************************
* Name    : WriteChar (PRIVATE)                                            *
* Purpose : Write a single character To GLCD                               *
*         : This routine only supports fonts with a y scan Line ($8x xx)   *
****************************************************************************
} 
Sub WriteChar()
   Dim FontByte, FontWidth, FontHeight As Byte
   Dim Mask, LastStyle As Byte

   FCharLocation = Pos.y
   FontWidth = 0
   While FontWidth < Font.Width
      Pos.y = FCharLocation
      FontHeight = 0
      While FontHeight < Font.Height
         FontByte = ReadFontByte
         Inc(FontHeight, 8)
         LastStyle = Font.Style

         If Font.Style = fsInvert Then
            Font.Style = fsNormal
            If FontHeight > Font.Height Then
               Mask = $FF << 8 - (FontHeight - Font.Height)
               FontByte = FontByte Or Mask
            EndIf
            FontByte = Not FontByte               
         EndIf
         WriteCharacterByte(FontByte)         
         Font.Style = LastStyle
         Inc(Pos.y, 8)
      Wend
      Inc(Pos.x) 
      If Pos.x >= Width Then
         Pos.x = 0	
      EndIf
      Inc(FontWidth)
   Wend
   Pos.y = FCharLocation  
End Sub
#ENDIF // GLCD_PIXEL_01

{
****************************************************************************
* Name    : WriteCharPixel (PRIVATE)                                       *
* Purpose : Write a character Pixel To the GLCD                            *
****************************************************************************
} 
#IFDEF GLCD_PIXEL_08
Sub WriteCharPixel(pChar As Byte, pPenColor As TColor)
   Pen.Color = pPenColor
   If Brush.Style = bsClear Then
      If pChar.0 = 1 Then
         SetPixel(Pos.x,Pos.y)
      EndIf
   Else
      If pChar.0 = 0 Then
         Pen.Color = Brush.Color
      EndIf
      SetPixel(Pos.x,Pos.y)
   EndIf   
End Sub
{
****************************************************************************
* Name    : WriteChar(PRIVATE)                                             *
* Purpose : Write a single character To GLCD                               *
*         : This routine only supports fonts with a y scan Line ($8x xx)   *
*         : It's device independent, which makes it pretty slow - look at  *
*         : implementing a Device specific routine in the GLCD driver      *
****************************************************************************
} 
Sub WriteChar()
   Dim x, y As TXY
   Dim FontByte, LastPosY As Byte
   Dim PenColor As TColor

   LastPosY = Pos.y
   PenColor = Pen.Color
   If Font.IsScanY Then
      x = 0
      Repeat
         Pos.y = LastPosY
         y = 0
         Repeat
            If y Mod 8 = 0 Then
               FontByte = ReadFontByte
            EndIf   
            WriteCharPixel(FontByte, PenColor)           
            FontByte = FontByte >> 1
            Inc(Pos.y)
            Inc(y)
         Until y = Font.Height
         Inc(Pos.x)
         Inc(x)
      Until x = Font.Width
   EndIf  
   Pen.Color = PenColor
   Pos.y = LastPosY
End Sub
#ENDIF // GLCD_PIXEL_08
#ENDIF // GLCD_WRITECHAR

{
****************************************************************************
* Name    : WriteFontChar                                                  *
* Purpose : Write a Font character To the GLCD                             *
****************************************************************************
} 
Sub WriteFontChar(pChar As Char)
   LoadCharAddress(pChar)
   If Font.IsVariable Then
      Font.Width = ReadFontByte
   EndIf
   WriteChar  
End Sub
{
****************************************************************************
* Name    : WriteLetterSpacing                                             *
* Purpose :                                                                *
****************************************************************************
} 
Sub WriteFontSpace()
   Dim Index As Byte
   Index = Font.LetterSpacing
   While Index > 0
      LoadLetterSpacing
      WriteChar
      Dec(Index)
   Wend
End Sub
{
****************************************************************************
* Name    : WriteItem (OVERLOAD)                                           *
* Purpose : Writes a character To GLCD                                     *
****************************************************************************
} 
Sub WriteItem(pChar As Char)
   WriteFontChar(pChar)
End Sub
{
****************************************************************************
* Name    : WriteItem (OVERLOAD)                                           *
* Purpose : Writes a string To GLCD                                        *
****************************************************************************
} 
Sub WriteItem(pStr As String)
   FSR0 = @pStr
   While INDF0 <> 0
      WriteFontChar(POSTINC0)
      If Font.IsVariable And INDF0 <> 0 Then
         WriteFontSpace
      EndIf   
   Wend
End Sub
{
****************************************************************************
* Name    : SetLocationX (PRIVATE)                                         *
* Purpose : Set Cursor x                                                   *
****************************************************************************
} 
Sub SetLocationX(pX As TXY)
   Pos.x = pX
End Sub
{
****************************************************************************
* Name    : SetLocationY (PRIVATE)                                         *
* Purpose : Set Cursor y                                                   *
****************************************************************************
} 
Sub SetLocationY(pY As TXY)
   Pos.y = pY
End Sub
{
****************************************************************************
* Name    : Write (COMPOUND)                                               *
* Purpose : Write one Or more items To GLCD                                *
****************************************************************************
} 
Public Compound Sub Write(WriteItem)
{
****************************************************************************
* Name    : WriteAt (COMPOUND)                                             *
* Purpose : Write one Or more items At position x, y                       *
****************************************************************************
} 
Public Compound Sub WriteAt(SetLocationX, SetLocationY, WriteItem)
{
****************************************************************************
* Name    : WriteStr                                                       *
* Purpose : Write one item centred in x At position x, y                   *
****************************************************************************
} 
Public Sub WriteStr(pX, pY As TXY, pStr As String)
   Pos.x = pX
   Pos.y = pY
   If TextAlign = taCenter Then
      Dec(Pos.x,TextWidth(pStr) / 2)
   ElseIf TextAlign = taRight Then
      Dec(Pos.x,TextWidth(pStr))
   EndIf      
   WriteItem(pStr)
End Sub

// initialize the module
TextAlign = taLeft

End of post