glcd issue

83 views
Skip to first unread message

Joep Suijs

unread,
Aug 8, 2011, 1:18:06 PM8/8/11
to jal...@googlegroups.com
Hi guys, Seb,

The glcd issue on the jallist, which stated that graphics works, but
character not surprised me since I tested it at the time. However I
seem to have missed some enhancments on the lib. Seb, could you look
into this issue (and while you're at it, add your name to the lib ;) ?

Thanks,
Joep

Piers Goodhew

unread,
Aug 18, 2011, 7:46:07 AM8/18/11
to jal...@googlegroups.com
Having just got some ks0108 glcd stuff to work (on a 16f723a), it appears to me that:

  • glcd_ks0108.jal line 453 defines "lcd_write_char", while glcd_common.jal is expecting "glcd_write_char" (see line 216). This is a regression? Earlier revs seem to have "glcd", but the diff function here in google code doesn't totally make sense to me so I'm not sure
  • correcting that, and defining a font (by including both glcd_nXn_font and glcd_font) enables me to output at least one char via the glcd pseudo var
I posted earlier on the yahoo group (before I found the missing G), but it's awaiting moderation .. and can be safely ignored I think.

PG

Piers Goodhew

unread,
Aug 18, 2011, 8:12:52 AM8/18/11
to jal...@googlegroups.com
further (awaiting moderation here) glcd_char_goto() is written to go to a pixel co-ordinate, whereas the glcd examples all clearly expect it to go to a character position.

Once I'm approved, should open a ticket or two? Or will it all be taken care of for me?

PG

mattschinkel

unread,
Aug 18, 2011, 8:16:43 AM8/18/11
to jallib
Yes, glcd_common.jal does need lcd_write_char, which is defined in
glcd_ks0108.jal.

We made some changes to glcd_common and need to make some
documentation on this sometime soon.

You should also take a look at other GLCD samples, like:
http://jallib.googlecode.com/svn/trunk/sample/18f4620_glcd_touch_stm032qvt_003.jal

Which are you haveing trouble with? I guess I didn't see your
question.

Matt.

On Aug 18, 7:46 am, Piers Goodhew <pie...@gmail.com> wrote:
> Having just got some ks0108 glcd stuff to work (on a 16f723a), it appears to
> me that:
>
>    - glcd_ks0108.jal line 453 defines "lcd_write_char", while
>    glcd_common.jal is expecting "*g*lcd_write_char" (see line 216). This is
>    a regression? Earlier revs seem to have "glcd", but the diff function here
>    in google code doesn't totally make sense to me so I'm not sure
>    - correcting that, *and* defining a font (by including both glcd_nXn_font

mattschinkel

unread,
Aug 18, 2011, 8:39:11 AM8/18/11
to jallib
> further (awaiting moderation here) glcd_char_goto() is written to go to a
> pixel co-ordinate, whereas the glcd examples all clearly expect it to go to
> a character position.

It should be a pixel co-ordinate.

and I see your issue now... there is no glcd_write_char, but you do
have lcd_write_char in ks0108. Did you try to rename?

It would be great if you could test and fix issues, then commit it to
jallib.

Matt.

mattschinkel

unread,
Aug 18, 2011, 8:59:40 AM8/18/11
to jallib
Actually glcd_write_char is not required. It is optional since
glcd_common can write characters on it's own.

glcd_common may be faster or slower then a glcd_write_char in the
ks0108 library depending on the method of writing a character. Of
course you will want to write characters as fast as possible :)

stm032qvt-003 sample has an example use of the pseudo var "glcd", and
does not use glcd_write_char.

I don't own a ks0108 so I am unable to test.

Matt.

Piers Goodhew

unread,
Aug 18, 2011, 9:03:02 AM8/18/11
to jal...@googlegroups.com


On Thursday, 18 August 2011 22:16:43 UTC+10, mattschinkel wrote:
Yes, glcd_common.jal does need lcd_write_char, which is defined in
glcd_ks0108.jal.

To be precise, it needs glcd_write_char , which is defined nowhere.

Which are you haveing trouble with? I guess I didn't see your
question.

Having made the changes I outlined, that is: add a G to glcd_ks0108; modify glcd_goto_char; and including 2 font files, it seems to be working pretty well.

If glcd_char_goto expects pixels, then the glcd example is incorrect.

I will endeavour to submit a patch once everything's clear ..

PG

Piers Goodhew

unread,
Aug 18, 2011, 9:05:11 AM8/18/11
to jal...@googlegroups.com
I know it's not *meant* to be required, but it sure as heck made quite a difference having it! Now I have text working with it, I'll remove the G and see what happens, but right now it's bedtime for me!

mattschinkel

unread,
Aug 18, 2011, 9:08:37 AM8/18/11
to jallib
Please post your working code. Would you allow us to replace the
current sample with your working one?

Are there other issues that need to be fixed?

Matt.

Piers Goodhew

unread,
Aug 18, 2011, 9:48:57 PM8/18/11
to jal...@googlegroups.com
Happy to post code and have it rolled into jallib, will post after a bit more work and testing (because, yes, there are probably a few more issues..)

(NB I wont be able to test on anything other than the 16f723a/my glcd)

PG

Piers Goodhew

unread,
Aug 19, 2011, 9:08:30 AM8/19/11
to jal...@googlegroups.com
OK, if you make the "G" addition to glcd_ks0108.jal, the following code, adapted from the not-working-for-me 16f877a_glcd_ks0108.jal, works.

Further:
  • removing the "g" from glcd_write_char (in glcd_ks0108) results in big white blocks, not chars (some bug further up in the pbp routine?)
  • Not having the extra 2 font includes (include glcd_5x7_font include glcd_font ) and the glcd_font_use() will result in no text of any kind (with or without the "g fix")
  • the very first comment isn't right. No game of life here!

-- Title: Test program shows Conway's 'game of life' on a ks0108 graphic LCD

-- Author: Joep Suijs, Copyright (c) 2008-2011, all rights reserved.

-- Adapted-by: 

-- Compiler: >=2.4m

-- Revision: $Revision: 2760 $

--

-- This file is part of jallib  (http://jallib.googlecode.com)

-- Released under the ZLIB license (http://www.opensource.org/licenses/zlib-license.html)

--

-- Description: 

-- http://en.wikipedia.org/wiki/Conway's_Game_of_Life

--

--

-- This file has been generated from:

--    * board: board_16f877a_startersguide.jal

--    * test : test_glcd_ks0108.jal

--

-- (and then ported to the 16f723a, the serial (and some other) stuff commented out, 

-- and set up to use the int osc, by Piers Goodhew, August 2011)

--


;@jallib section chipdef

-- chip setup

include 16f723a


-- configuration memory settings (fuses)

pragma target clock 4_000_000       -- xtal frequency

pragma target OSC      INTOSC_NOCLKOUT       -- internal to start with I think

pragma target PLLEN   F16MHz -- int osc PLL enabled (higher frequencies)

pragma target WDT      disabled     -- no watchdog

pragma target DEBUG    disabled     -- no debugging

pragma target MCLR external         -- reset externally


-- GRAPHIC_LCD IO definition

var volatile byte GLCD_DATAPRT     is portc

var volatile byte GLCD_DATAPRT_DIR is portc_direction


var volatile bit GLCD_RW  is pin_a4

var volatile bit GLCD_CS1 is pin_a2

var volatile bit GLCD_E   is pin_a5

var volatile bit GLCD_DI  is pin_a3

var volatile bit GLCD_RST is pin_b0

var volatile bit GLCD_CS2 is pin_a1


var volatile bit GLCD_RW_DIRECTION  is pin_a4_direction

var volatile bit GLCD_CS1_DIRECTION is pin_a2_direction

var volatile bit GLCD_E_DIRECTION   is pin_a5_direction

var volatile bit GLCD_DI_DIRECTION  is pin_a3_direction

var volatile bit GLCD_RST_DIRECTION is pin_b0_direction

var volatile bit GLCD_CS2_DIRECTION is pin_a1_direction


include print

include random


OSCCON_IRCF = 0b01 -- Clock to 4MHz (TODO: lose if we're on xtal)


include delay     

include glcd_5x7_font

include glcd_font

include glcd_ks0108      

include glcd_common

glcd_init()

glcd_font_use(FONT_5X7)


const byte str1[] = "Test graph display.      "      -- define a string

;print_string(serial_hw_data, str1)                 -- output string


;glcd_box  ( 0,0, 127,63)  

     

include print


glcd_char_y_pos  = 20;  

glcd_char_x_pos = 20


;glcd_line(0, 0, 32, 63)

;glcd_line(0, 0, 64, 63)

;glcd_line(0, 0, 127,63)    


print_string(glcd, str1)

glcd_box( 0,0, 127,63)  


delay_100ms(10)



forever loop


   delay_100ms(5)


   -- fill with chars    

   var byte x, y, char;

   char = 32 

   for 8 using y loop 

  glcd_char_goto(0, (y+1) * _glcd_font_current_height )

      for 25 using x loop

         glcd = char

         char = char + 1

         if (char > 122) then char = 32 end if   

      end loop

   end loop 


   ;serial_hw_data = "+"


end loop


Joep Suijs

unread,
Aug 19, 2011, 9:23:57 AM8/19/11
to jal...@googlegroups.com
That comment is indeed obsolete. It's easy to remove this and
regenerate the samples. Just say the word and I will take care
The point is this does not fix the issue and I am not able to do
actual testing on this code. I also do not understand why this sample
seems to pass buildbot if there is a missing procedure...

Joep

2011/8/19 Piers Goodhew <pie...@gmail.com>:

> --
> You received this message because you are subscribed to the Google Groups
> "jallib" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/jallib/-/49QjHNp1sukJ.
> To post to this group, send email to jal...@googlegroups.com.
> To unsubscribe from this group, send email to
> jallib+un...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/jallib?hl=en.
>

mattschinkel

unread,
Aug 19, 2011, 3:06:48 PM8/19/11
to jallib
I ment for you to rename lcd_write_char to glcd_write_char.

Is this working code that you have shown and can it go on SVN? If not,
can you make a list of things that don't work?

I'll try to have a close look at your code although i don't have a
lcd.

Matt.

On Aug 19, 9:08 am, Piers Goodhew <pie...@gmail.com> wrote:
> OK, if you make the "G" addition to glcd_ks0108.jal, the following code,
> adapted from the not-working-for-me 16f877a_glcd_ks0108.jal, works.
>
> Further:
>
>    - removing the "g" from glcd_write_char (in glcd_ks0108) results in big
>    white blocks, not chars (some bug further up in the pbp routine?)
>    - Not having the extra 2 font includes (include glcd_5x7_font include
>     glcd_font ) and the glcd_font_use() will result in no text of any kind
>    (with or without the "g fix")
>    - the very first comment isn't right. No game of life here!
>
> -- Title: Test program shows Conway's 'game of life' on a ks0108 graphic LCD
>
> -- Author: Joep Suijs, Copyright (c) 2008-2011, all rights reserved.
>
> -- Adapted-by:
>
> -- Compiler: >=2.4m
>
> -- Revision: $Revision: 2760 $
>
> --
>
> -- This file is part of jallib  (http://jallib.googlecode.com)
>
> -- Released under the ZLIB license (http://www.opensource.org/licenses/zlib-license.html)
>
> --
>
> -- Description:
>
> --http://en.wikipedia.org/wiki/Conway's_Game_of_Life

mattschinkel

unread,
Aug 19, 2011, 5:06:39 PM8/19/11
to jallib
> - removing the "g" from glcd_write_char (in glcd_ks0108) results in big
> white blocks, not chars (some bug further up in the pbp routine?)

There is no "g"in glcd_write_char (in glcd_ks0108). It should be
glcd_write_char (not lcd_write_char). I don't think block writes are
working for ks0108. I scanned through the code and ''glcd" pseudo var
should be working if you name the procedure glcd_write_char.

You can test glcd_write_char on it's own to see if it works. For
example:
glcd_write_char(0,0,"A") -- write character "A" at 0,0.

Can someone please verify this... Does ks0108 write 8 pixles at a
time, each bit writing top to bottom? If so, everything looks ok to me
as long as you rename the write_char procedure to glcd_write_char.

Matt.

Piers Goodhew

unread,
Aug 19, 2011, 5:59:57 PM8/19/11
to jal...@googlegroups.com


On Friday, 19 August 2011 23:23:57 UTC+10, Joep wrote:
That comment is indeed obsolete. It's easy to remove this and
regenerate the samples.  Just say the word and I will take care
The point is this does not fix the issue and I am not able to do
actual testing on this code. I also do not understand why this sample
seems to pass buildbot if there is a missing procedure..

It falls back to another procedure if glcd_write_char is missing, so I suspect that's why it passes. 

PG

Piers Goodhew

unread,
Aug 19, 2011, 6:00:07 PM8/19/11
to jal...@googlegroups.com


On Saturday, 20 August 2011 07:06:39 UTC+10, mattschinkel wrote:
> - removing the "g" from glcd_write_char (in glcd_ks0108) results in big
>   white blocks, not chars (some bug further up in the pbp routine?)

There is no "g"in glcd_write_char (in glcd_ks0108). It should be
glcd_write_char (not lcd_write_char). I don't think block writes are
working for ks0108. I scanned through the code and ''glcd" pseudo var
should be working if you name the procedure glcd_write_char.

Sorry, I'm going to have to try to be more concise here. We don't seem to be communicating. I've already said it does work if you name it glcd_write_char. 

Attached is my glcd_ks0108.jal - only changes are line 5 (revision) and 453.


You can test glcd_write_char on it's own to see if it works. For
example:
glcd_write_char(0,0,"A") -- write character "A" at 0,0.

This works.  I said that in my first post.

PG

glcd_ks0108.jal

Joep Suijs

unread,
Aug 20, 2011, 4:50:32 AM8/20/11
to jal...@googlegroups.com
Hi Piers,

2011/8/19 Piers Goodhew <pie...@gmail.com>:


>
> It falls back to another procedure if glcd_write_char is missing, so I
> suspect that's why it passes.

I guess that that must be it, but that seems to be fall-back to a
non-working routine.
Anyway - I fixed the comment and regenerated three samples, which
means they compile with the current svn code base. I could not figure
out what has happened since my last test (somewhere last year) and I
am afraid this did not yet fix code.I hope this will be resolved
shortly. If not, I'd probably be able to have a test-board available
and work on it in a month or so.

Joep

Piers Goodhew

unread,
Aug 20, 2011, 7:50:39 AM8/20/11
to jal...@googlegroups.com
I'll keep poking away in the meantime, if I find anything constructive, I'll share it ...

PG

mattschinkel

unread,
Aug 20, 2011, 8:36:56 AM8/20/11
to jallib
At one time during our GLCD upgrades, Seb and I had to rename
procedrues to add the G in front of them. Maybe we missed this one. I
renamed lcd_write_char to glcd_write_char in SVN.

Piers, you will only be able to use fonts that are less then 8 pixels
high unless you modify glcd_write_char and add more fonts.

It looks to me that KS0108 may be slow to draw shapes, images etc.
Maybe you can let us know how performance is.

I thought you said you have other issues as well?

Thanks,
Matt.

Joep Suijs

unread,
Aug 20, 2011, 8:52:44 AM8/20/11
to jal...@googlegroups.com
2011/8/20 mattschinkel <mattsc...@hotmail.com>:

> At one time during our GLCD upgrades, Seb and I had to rename
> procedrues to add the G in front of them. Maybe we missed this one. I
> renamed lcd_write_char to glcd_write_char in SVN.

It would be interesting to know how it resolves such a missing
procedure. We know it does, since there we can generate samples. I saw
some conditional compile stuff, maybe that's related?

Joep

mattschinkel

unread,
Aug 20, 2011, 10:14:16 AM8/20/11
to jallib
> It would be interesting to know how it resolves such a missing
> procedure. We know it does, since there we can generate samples. I saw
> some conditional compile stuff, maybe that's related?

There is a if defined statement for the procedure glcd_write_char in
glcd_common.

Matt.

Piers Goodhew

unread,
Aug 21, 2011, 6:31:34 AM8/21/11
to jal...@googlegroups.com


On Saturday, 20 August 2011 22:36:56 UTC+10, mattschinkel wrote:
Piers, you will only be able to use fonts that are less then 8 pixels
high unless you modify glcd_write_char and add more fonts.

Yes, I tried a 9px one, not so good.
 
It looks to me that KS0108 may be slow to draw shapes, images etc.
Maybe you can let us know how performance is.

Doesn't seem too bad - I don't really have anything to compare it with. Seems reasonably comparable to a commodore 64. This is an early test:

 
I thought you said you have other issues as well? 

Well there's obviously something not right with glcd_write_char_pbp but I can't say what yet. I thought I'd wait until I had a concise, constructive list (and I'm only getting a few tens of minutes of development per night in at the moment).

PG

mattschinkel

unread,
Aug 21, 2011, 8:11:31 AM8/21/11
to jallib
> Doesn't seem too bad - I don't really have anything to compare it with.
> Seems reasonably comparable to a commodore 64.

Thanks for the video :)

> Well there's obviously something not right with glcd_write_char_pbp but I
> can't say what yet. I thought I'd wait until I had a concise, constructive
> list (and I'm only getting a few tens of minutes of development per night in
> at the moment).

I think you can draw any font with glcd_write_char_pbp, but it may
suffer slowness here.

ks0108 is ment to write 8 pixels at a time. If you wish to write one
pixel, the library reads 8 pixels first, sets the appropriate pixel,
then writes 8 pixels again.

If you look closer at the pseudo var 'glcd', if glcd_write_char does
not exist, and you set GLCD_USE_BLOCK_WRITE = FALSE (the default),
you'll be using glcd_write_char_pbp (which uses glcd_write_pixel) to
draw fonts.

Seb, instead of giving same naming prodecures in lcd device libs like
'glcd_write_char', we could name them like 'ks0108_write_char' then do
an alias during the include block in the sample. Similar to what we
are doing with SPI. This would give the user the option to enable/
disable the 'if defined' statements in glcd_common. What do you think?

example:

const GLCD_USE_BLOCK_WRITE = FALSE
alias glcd_write_pixel is ks0108_write_pixel
alias glcd_write_char is ks0108_write_char -- comment out to draw
fonts with write_pixel
include glcd_common

Matt.

Sebastien Lelong

unread,
Aug 21, 2011, 8:51:53 AM8/21/11
to jal...@googlegroups.com


Le 21 août 2011 14:11, "mattschinkel" <mattsc...@hotmail.com> a écrit :
> Seb, instead of giving same naming prodecures in lcd device libs like
> 'glcd_write_char', we could name them like 'ks0108_write_char' then do
> an alias during the include block in the sample.

IIRC we did things like this to idenntify, within API, which proc are device specific, and which are generic. things go like this for other glcd lib as well. during refactoring I try to maintain existing api but renamed ks108_. 

cheers
seb

mattschinkel

unread,
Aug 21, 2011, 3:55:42 PM8/21/11
to jallib
But write_pixel and write_char are device specific :)

Maybe we made the wrong decision at the time. We never took this way
of doing it (with aliases) into consideration.

I'm not sure how many procedures we're talking about... Here's a list
I can come up with:
lcd_fill
lcd_on
lcd_off
glcd_write_pixel
glcd_write_char

I also see that lcd_fill, lcd_on, lcd_off should be glcd_. Maybe we
never renamed anything in this lib?

Matt.

On Aug 21, 8:51 am, Sebastien Lelong <sebastien.lel...@gmail.com>
wrote:

Piers Goodhew

unread,
Aug 27, 2011, 6:01:08 AM8/27/11
to jal...@googlegroups.com
Eureka moment - glcd_ks0108,jal, in glcd_write_pixel

line 193:

      data = data | !( 1 << yy )


should read:

      data = data & !( 1 << yy )


Seems to make other text routines work, as well as anything else where you change to pen colour to GLCD_WHITE (which is how I found it).

PG

Joep Suijs

unread,
Aug 27, 2011, 9:05:31 AM8/27/11
to jal...@googlegroups.com
Well done!
This particular line is fixed and it would be great if you could
verify if the current svn set of libs works.

Having said this, this bug has been there for a long time and I am
sure the sample file did work despite of this. So what has changed by
the refactoring what made the sample fail? With this answer, we can
judge if the sample still works as expected and if it needs adaption
or extension...

Joep

2011/8/27 Piers Goodhew <pie...@gmail.com>:

> --
> You received this message because you are subscribed to the Google Groups
> "jallib" group.
> To view this discussion on the web visit

> https://groups.google.com/d/msg/jallib/-/ZrI3-giLy2UJ.

Mike@watty

unread,
Aug 27, 2011, 3:53:36 PM8/27/11
to jallib

I pointed out bugs long ago in GLCD when I was doing Catpad and
uploaded fixes also I have differently organised version too

I don't understand how it reverted back to broken versions


I use
procedure PlotPixel(byte in x, byte in y, bit in onoff) is
var byte data , yy
var byte side = _KS0108_LEFT -- Stores which chip to use on the LCD
if x > 127 then
x = x -128
end if
if x > SCREEN_SUB_X then -- Check for first or second display area
x = x - (SCREEN_SUB_X +1)
side = _KS0108_RIGHT
end if
if y > 191 then
y = y -192
elsif y > 127 then
y = y - 128
elsif y > SCREEN_MAX_Y then
y = y -SCREEN_ROWS
end if
_ks0108_inst() -- Set for instruction
_ks0108_column(side,x) -- Set the horizontal address
_ks0108_page(side,(y / 8)) -- Set the page address
_ks0108_data() -- Set for data
data = _ks0108_read(side) -- Need two reads to get data at new
address
data = _ks0108_read(side) -- DO NOT REMOVE 2nd Read!
-- add XOR code
if onoff == 1 then
-- bit_set(data, y%SCREEN_BLIT_PIXELS) -- Turn the pixel on
yy = y % SCREEN_BLIT_PIXELS
data = data | ( 1 << yy )
else -- or
-- bit_clear(data, y%SCREEN_BLIT_PIXELS) -- turn the pixel off
yy = y % SCREEN_BLIT_PIXELS
data = data & !( 1 << yy )
end if
_ks0108_inst() -- Set for instruction
_ks0108_column(side,x) -- Set the horizontal address
_ks0108_data() -- Set for data
_ks0108_write(side, data) -- Write the pixel data
end procedure

Mike@watty

unread,
Aug 27, 2011, 3:59:15 PM8/27/11
to jallib
For characters I use the MUCH faster aligned byte mode:


-- use for sprites or fonts that are multiple of 8 high
procedure BlitColumn (byte in x, byte in y, byte in column ) is
_ks0108_inst() -- Set for instruction
if (x > 128) then
x = x -128
end if
if y > 191 then
y = y -192
elsif y > 127 then
y = y - 128
elsif y > SCREEN_MAX_Y then
y = y -SCREEN_ROWS
end if
if (x > SCREEN_SUB_X ) then
_ks0108_column(_KS0108_RIGHT, x-(SCREEN_SUB_X +1)) -- Set the
horizontal address
_ks0108_page(_KS0108_RIGHT, (y / 8)) -- Set the page address
_ks0108_data() -- Set for data
_ks0108_write(_KS0108_RIGHT, column) -- Write the pixel data

else
_ks0108_column(_KS0108_LEFT,x) -- Set the horizontal address
_ks0108_page(_KS0108_LEFT, (y / 8)) -- Set the page address
_ks0108_data() -- Set for data
_ks0108_write(_KS0108_LEFT, column) -- Write the pixel data

end if
end procedure


-- Title: dev_glcd_ks0108 - Library for KS0108 compatible LCD
-- Author: Serkan Ayyýldýz Copyright (c) 2006..2009, all rights
reserved.
-- Adapted-by: Joep Suijs, Michael Watterson (c)2010
-- Compiler: >=2.4
--
-- This file is part of jallib (http://jallib.googlecode.com)
-- Released under the ZLIB license
-- (http://www.opensource.org/licenses/zlib-license.html)
--
-- Sources:
--
-- Description: Library for KS0108 / KS0107 graphic lcd with 128x64
resolution.
--
--
-- Notes:
-- This panel uses 2 off 64 x64 sharing drivers on one axis
-- if CSI and CS1 both active then both halves can written
simultaneously.

-- ******************************

-- Default port usage, all D, most B and one E

-- using port E allows sharing D & B with a Keyboard.
-- *****************************
if (defined(GLCD_RW )== false) then
alias GLCD_CS2 is pin_b2
alias GLCD_CS2_direction is pin_b2_direction
alias GLCD_CS1 is pin_b3
alias GLCD_CS1_direction is pin_b3_direction
alias GLCD_RW is pin_b6
alias GLCD_RW_direction is pin_b6_direction
alias GLCD_DI is pin_b7 -- LCD command/data select.
alias GLCD_DI_direction is pin_b7_direction
alias GLCD_E is pin_E2
alias GLCD_E_direction is pin_E2_direction
alias GLCD_LED is pin_E1
alias GLCD_LED_direction is pin_E1_direction
alias GLCD_dataprt is portd -- LCD data
alias GLCD_DATAPRT_DIR is portd_direction
end if




-- ******************************

-- PUBLIC

-- *****************************
const SCREEN_ROWS = 64
const SCREEN_COLS = 128
const SCREEN_MAX_X = SCREEN_COLS -1
const SCREEN_SUB_X = 63
const SCREEN_MAX_Y = SCREEN_ROWS -1
const SCREEN_BLIT_PIXELS = 8

-- *******************************

-- Private

-- *******************************




const _KS0108_LEFT = 0
const _KS0108_RIGHT = 1
const _KS0108_BOTH = 3
const _KS0108_CMD_ON = 0x3F
const _KS0108_CMD_OFF = 0x3E
const _KS0108_CMD_PAGE = 0xB8
const _KS0108_CMD_COLUMN = 0x40
const _KS0108_CMD_TOP_RAM = 0xC0



-- Purpose: Write a byte of data to the specified chip
-- Inputs: 1) chipSelect - which chip to write the data to
-- 2) data - the byte of data to write
procedure _ks0108_write(byte in side, byte in data) is
if side == _KS0108_RIGHT then -- Choose which side to write to
GLCD_CS2 = high
elsif side == _KS0108_LEFT then
GLCD_CS1 = high
else
GLCD_CS1 = high
GLCD_CS2 = high
end if
GLCD_RW = low -- Set for writing
GLCD_DATAPRT = data -- Put the data on the port
GLCD_DATAPRT_DIR = all_output
_usec_delay (1)
GLCD_E = high -- Pulse the enable pin
_usec_delay (2)
--delay2_us
GLCD_E = low
GLCD_CS1 = low -- Reset the chip select lines
GLCD_CS2 = low
--delay_2us()
_usec_delay (2)
end procedure

-- Purpose: Reads a byte of data from the specified chip
-- Ouputs: A byte of data read from the chip
function _ks0108_read(byte in side) return byte is
var byte data -- Stores the data read from the LCD
GLCD_DATAPRT_DIR = all_input -- Set port d to input
if side == _KS0108_RIGHT then -- Choose which side to write to
GLCD_CS2 = high
elsif side == _KS0108_LEFT then
GLCD_CS1 = high
else -- can only read one side at a time
GLCD_CS1 = low
GLCD_CS2 = low
return (0) -- exit
end if
GLCD_RW = high -- Set for reading
_usec_delay (1) -- delay_cycles(1)
GLCD_E = high -- Pulse the enable pin
_usec_delay (2)
data = GLCD_DATAPRT -- Get the data from the display's output
register
GLCD_E = low
GLCD_CS1 = low -- Reset the chip select lines
GLCD_CS2 = low
_usec_delay (2)

return data -- Return the read data
end function

-- Purpose: Turn the display on
procedure _ks0108_on() is
_ks0108_write(_KS0108_LEFT, _KS0108_CMD_ON)
_ks0108_write(_KS0108_RIGHT, _KS0108_CMD_ON)
end procedure

-- Purpose: Turn the display off
procedure _ks0108_off() is
_ks0108_write(_KS0108_LEFT, _KS0108_CMD_OFF)
_ks0108_write(_KS0108_RIGHT, _KS0108_CMD_OFF)
end procedure

-- Purpose: Set the page number
-- Inputs: A page number (0 - 7)
procedure _ks0108_page(byte in side , byte in page) is
_ks0108_write(side, _KS0108_CMD_PAGE | page)
end procedure

-- Purpose: Set the column address
-- Inputs: The column address (0 - SCREEN_SUB_X)
procedure _ks0108_column(byte in side, byte in column) is
_ks0108_write(side, _KS0108_CMD_COLUMN | column)
end procedure

-- Purpose: Specify reads and writes are instructions
procedure _ks0108_inst() is
GLCD_DI = low
end procedure

-- Purpose: Specify reads and writes are data
procedure _ks0108_data() is
GLCD_DI = high
end procedure


procedure _ks0108_write_byte(byte in x, byte in y, byte in veri) is
var byte side = _KS0108_LEFT -- Stores which chip to use on the LCD
if x > 127 then
x = x -128
end if
if (x > SCREEN_SUB_X)then -- Check for first or second display
area
x = x - (SCREEN_SUB_X +1)
side = _KS0108_RIGHT
end if
if y > 191 then
y = y -192
elsif y > 127 then
y = y - 128
elsif y > SCREEN_MAX_Y then
y = y -SCREEN_ROWS
end if
_ks0108_inst() -- Set for instruction
_ks0108_column(side,x) -- Set the horizontal address
_ks0108_page(side,(y / SCREEN_BLIT_PIXELS)) -- Set the page
address
_ks0108_data() -- Set for data
_ks0108_write(side, ! veri) -- Write the pixel data
end procedure


-- Purpose: Fill the LCD screen with the passed in color
-- Inputs: ON - turn all the pixels on
-- OFF - turn all the pixels off
procedure _ks0108_fill(byte in data) is
var byte i, j
i = 0 -- Loop through the vertical pages
for (SCREEN_ROWS / SCREEN_BLIT_PIXELS) loop
_ks0108_inst() -- Set for instruction
_ks0108_page(_KS0108_LEFT,i) -- Set page address
_ks0108_page(_KS0108_RIGHT,i)
_ks0108_column(_KS0108_LEFT,0) -- Set horizontal address to 0
_ks0108_column(_KS0108_RIGHT,0)
_ks0108_data() -- Set for data
-- Loop through the horizontal sections
for SCREEN_SUB_X +1 loop
_ks0108_write(_KS0108_LEFT ,data) -- Write the byte of
data
_ks0108_write(_KS0108_RIGHT,data)
end loop
i = i + 1
end loop
end procedure

-- Purpose: Initialize the LCD.
-- Call before using any other LCD function.
procedure _ks0108_init() is
-- Initialze some pins
GLCD_DATAPRT = 0x00
GLCD_DATAPRT_DIR = all_output
GLCD_RW_DIRECTION = output
GLCD_CS1_DIRECTION = output
GLCD_E_DIRECTION = output
GLCD_DI_DIRECTION = output
--GLCD_RST_DIRECTION = output
GLCD_CS2_DIRECTION = output
--GLCD_RST = high
GLCD_E = low
GLCD_CS1 = low
GLCD_LED = off
GLCD_LED_direction = output

_ks0108_inst() -- Set for instruction
_ks0108_write(_KS0108_LEFT, _KS0108_CMD_TOP_RAM | 0) -- First RAM
line at the top of the screen
_ks0108_write(_KS0108_RIGHT, _KS0108_CMD_TOP_RAM | 0) -- First RAM
line at the top of the screen
_ks0108_page (_KS0108_LEFT ,0) -- Set the page address to 0
_ks0108_page (_KS0108_RIGHT,0)
_ks0108_column(_KS0108_LEFT ,0) -- Set the column address to 0
_ks0108_column(_KS0108_RIGHT,0)
_ks0108_on() -- Turn the display on
_ks0108_fill(0) -- Clear the display
end procedure

var byte _ks0108_lastLcdCmd = 0 -- private current state of LCD
panel



In my "graphics library"

procedure PlotChar(byte in x, byte in y, byte in ch, bit in inkColour,
bit in large, bit in bold ) is
; 96 * 5 bytes = 455
const byte _FONT_5x7_MAP[] = {
0x00, 0x00, 0x00, 0x00, 0x00, ;; space, 32
0x00, 0x00, 0x2f, 0x00, 0x00, ;; !, 33
0x00, 0x07, 0x00, 0x07, 0x00, ;; ", 34
0x14, 0x7f, 0x14, 0x7f, 0x14, ;; #, 35
0x24, 0x2a, 0x7f, 0x2a, 0x12, ;; $, 36
0xc4, 0xc8, 0x10, 0x26, 0x46, ;; %, 37
0x36, 0x49, 0x55, 0x22, 0x50, ;; &, 38
0x00, 0x05, 0x03, 0x00, 0x00, ;; ', 39
0x00, 0x1c, 0x22, 0x41, 0x00, ;; (, 40
0x00, 0x41, 0x22, 0x1c, 0x00, ;; ), 41
0x14, 0x08, 0x3E, 0x08, 0x14, ;; *, 42
0x08, 0x08, 0x3E, 0x08, 0x08, ;; +, 43
0x00, 0x00, 0x50, 0x30, 0x00, ;; ,, 44
0x10, 0x10, 0x10, 0x10, 0x10, ;; -, 45
0x00, 0x60, 0x60, 0x00, 0x00, ;; ., 46
0x20, 0x10, 0x08, 0x04, 0x02, ;; /, 47
0x3E, 0x51, 0x49, 0x45, 0x3E, ;; 0, 48
0x00, 0x42, 0x7F, 0x40, 0x00, ;; 1, 49
0x42, 0x61, 0x51, 0x49, 0x46, ;; 2, 50
0x21, 0x41, 0x45, 0x4B, 0x31, ;; 3, 51
0x18, 0x14, 0x12, 0x7F, 0x10, ;; 4, 52
0x27, 0x45, 0x45, 0x45, 0x39, ;; 5, 53
0x3C, 0x4A, 0x49, 0x49, 0x30, ;; 6, 54
0x01, 0x71, 0x09, 0x05, 0x03, ;; 7, 55
0x36, 0x49, 0x49, 0x49, 0x36, ;; 8, 56
0x06, 0x49, 0x49, 0x29, 0x1E, ;; 9, 57
0x00, 0x36, 0x36, 0x00, 0x00, ;; :, 58
0x00, 0x56, 0x36, 0x00, 0x00, ;; ;, 59
0x08, 0x14, 0x22, 0x41, 0x00, ;; <, 60
0x14, 0x14, 0x14, 0x14, 0x14, ;; =, 61
0x00, 0x41, 0x22, 0x14, 0x08, ;; >, 62
0x02, 0x01, 0x51, 0x09, 0x06, ;; ?, 63
0x32, 0x49, 0x59, 0x51, 0x3E, ;; @, 64
0x7E, 0x11, 0x11, 0x11, 0x7E, ;; A, 65
0x7F, 0x49, 0x49, 0x49, 0x36, ;; B, 66
0x3E, 0x41, 0x41, 0x41, 0x22, ;; C, 67
0x7F, 0x41, 0x41, 0x22, 0x1C, ;; D, 68
0x7F, 0x49, 0x49, 0x49, 0x41, ;; E, 69
0x7F, 0x09, 0x09, 0x09, 0x01, ;; F, 70
0x3E, 0x41, 0x49, 0x49, 0x7A, ;; G, 71
0x7F, 0x08, 0x08, 0x08, 0x7F, ;; H, 72
0x00, 0x41, 0x7F, 0x41, 0x00, ;; I, 73
0x20, 0x40, 0x41, 0x3F, 0x01, ;; J, 74
0x7F, 0x08, 0x14, 0x22, 0x41, ;; K, 75
0x7F, 0x40, 0x40, 0x40, 0x40, ;; L, 76
0x7F, 0x02, 0x0C, 0x02, 0x7F, ;; M, 77
0x7F, 0x04, 0x08, 0x10, 0x7F, ;; N, 78
0x3E, 0x41, 0x41, 0x41, 0x3E, ;; O, 79
0x7F, 0x09, 0x09, 0x09, 0x06, ;; P, 80
0x3E, 0x41, 0x51, 0x21, 0x5E, ;; Q, 81
0x7F, 0x09, 0x19, 0x29, 0x46, ;; R, 82
0x46, 0x49, 0x49, 0x49, 0x31, ;; S, 83
0x01, 0x01, 0x7F, 0x01, 0x01, ;; T, 84
0x3F, 0x40, 0x40, 0x40, 0x3F, ;; U, 85
0x1F, 0x20, 0x40, 0x20, 0x1F, ;; V, 86
0x3F, 0x40, 0x38, 0x40, 0x3F, ;; W, 87
0x63, 0x14, 0x08, 0x14, 0x63, ;; X, 88
0x07, 0x08, 0x70, 0x08, 0x07, ;; Y, 89
0x61, 0x51, 0x49, 0x45, 0x43, ;; Z, 90
0x00, 0x7F, 0x41, 0x41, 0x00, ;; [, 91
0x55, 0x2A, 0x55, 0x2A, 0x55, ;; \, 92
0x00, 0x41, 0x41, 0x7F, 0x00, ;; ], 93
0x04, 0x02, 0x01, 0x02, 0x04, ;; ^, 94
0x40, 0x40, 0x40, 0x40, 0x40, ;; _, 95
0x00, 0x01, 0x02, 0x04, 0x00, ;; ', 96
0x20, 0x54, 0x54, 0x54, 0x78, ;; a, 97
0x7F, 0x48, 0x44, 0x44, 0x38, ;; b, 98
0x38, 0x44, 0x44, 0x44, 0x20, ;; c, 99
0x38, 0x44, 0x44, 0x48, 0x7F, ;; d, 100
0x38, 0x54, 0x54, 0x54, 0x18, ;; e, 101
0x08, 0x7E, 0x09, 0x01, 0x02, ;; f, 102
0x0C, 0x52, 0x52, 0x52, 0x3E, ;; g, 103
0x7F, 0x08, 0x04, 0x04, 0x78, ;; h, 104
0x00, 0x44, 0x7D, 0x40, 0x00, ;; i, 105
0x20, 0x40, 0x44, 0x3D, 0x00, ;; j, 106
0x7F, 0x10, 0x28, 0x44, 0x00, ;; k, 107
0x00, 0x41, 0x7F, 0x40, 0x00, ;; l, 108
0x7C, 0x04, 0x18, 0x04, 0x78, ;; m, 109
0x7C, 0x08, 0x04, 0x04, 0x78, ;; n, 110
0x38, 0x44, 0x44, 0x44, 0x38, ;; o, 111
0x7C, 0x14, 0x14, 0x14, 0x08, ;; p, 112
0x08, 0x14, 0x14, 0x18, 0x7C, ;; q, 113
0x7C, 0x08, 0x04, 0x04, 0x08, ;; r, 114
0x48, 0x54, 0x54, 0x54, 0x20, ;; s, 115
0x04, 0x3F, 0x44, 0x40, 0x20, ;; t, 116
0x3C, 0x40, 0x40, 0x20, 0x7C, ;; u, 117
0x1C, 0x20, 0x40, 0x20, 0x1C, ;; v, 118
0x3C, 0x40, 0x30, 0x40, 0x3C, ;; w, 119
0x44, 0x28, 0x10, 0x28, 0x44, ;; x, 120
0x0C, 0x50, 0x50, 0x50, 0x3C, ;; y, 121
0x44, 0x64, 0x54, 0x4C, 0x44, ;; z, 122
0x08, 0x7F, 0x41, 0x41, 0x00, ;; {, 123
0x00, 0x00, 0x7F, 0x00, 0x00, ;; |, 124
0x00, 0x41, 0x41, 0x7F, 0x08, ;; }, 125
0x10, 0x20, 0x10, 0x40, 0x10 ;; ~, 126
}

var word indx = 0
var byte cx, bitIdx
var bit ink
if (ch > 31)& (ch < 127) then
indx = indx + 5 * word(ch - 32)
if large then
for 5 loop
cx = _FONT_5x7_MAP[indx]
if ! inkColour then
cx = !cx
end if
bitIdx = 1 -- index bits of font
for 8 loop
ink = ((cx & bitIdx) > 0)
PlotPixel(x, y, ink)
PlotPixel(x+1, y, ink)
PlotPixel(x, y+1, ink)
PlotPixel(x+1, y+1, ink)
if (bitIdx < 128) then
bitIdx = bitIdx * 2
end if
y = y +2
end loop
y = y -16
indx = indx + 1
x = x + 2
end loop
elsif ((y % 8) == 0) then -- only on 8 boundries
for 5 loop
cx = _FONT_5x7_MAP[indx]
if !inkColour then
cx = ! cx
end if
BlitColumn (x, y, cx)
indx = indx + 1
x = x + 1
end loop
if bold then
indx = indx-5
x = x -4
for 4 loop
cx = _FONT_5x7_MAP[indx]
-- plot in OR mode
PlotColumn(x, y, cx, inkColour, false)
indx = indx + 1
x = x + 1
end loop
cx = _FONT_5x7_MAP[indx]
if !inkColour then
cx = ! cx
end if
BlitColumn (x, y, cx)
end if
else -- not on 8 bit boundary, so BlitColumn and PlotColumn
don't work!
for 5 loop
cx = _FONT_5x7_MAP[indx]
if ! inkColour then -- black background, white text
cx = !cx
end if
bitIdx = 1
for 8 loop
ink = ((cx & bitIdx) > 0)
PlotPixel(x, y, ink)
if bold then
if (inkColour & ink) then
PlotPixel(x+1, y, on)
elsif ((!inkColour) & (!ink)) then
PlotPixel(x+1, y, off)
end if
end if
if (bitIdx < 128) then
bitIdx = bitIdx * 2
end if
y = y +1
end loop -- rows of font
y = y -8
indx = indx + 1
x = x+1
end loop -- cols of font
end if -- double or normal
end if -- characters
end procedure



Piers Goodhew

unread,
Aug 27, 2011, 6:42:29 PM8/27/11
to jal...@googlegroups.com
Off the top of my head, I wonder if tests were passed because pixel erasing was not tried and the ks0108_write_char routine was the only one used ...

PG

Joep Suijs

unread,
Aug 28, 2011, 4:00:48 AM8/28/11
to jal...@googlegroups.com
@Piers
You're right about that: at the time I only tested writing a box and
printing chars. The game-of-life app I created as a demo did not use
the pixel write (erase) due to its low performance.

@Mike:
Iirc you supplied quite a lot of alternative (improved, extended &
modified) code, but nobody (including you and me) spent the time and
effort to figure out the relevant parts and integrate them properly
into jallib.
You are right about the performance of the pixel routine (see my
remark above). However, replacing it by a byte-oriented routine will
limit us to fonts of 8 bits high. And in addition to this, the fonts
can only be placed on rows that are multiples of 8. So I'd prefer a
flexible routine over a limited one. In an ideal case, there would be
an option to use the byte-oriented one automagicly when possible and
revert to the bit one when required. This does require significant
testing e.g. to check if 8-bit and other-sized fonts are printed
properly at any place on the screen. And with the integration of the
other glcd libs, I'm not sure if this affects this lib only, or can
(should) be generic implemented and tested on other graphic displays
too.

Joep

2011/8/28 Piers Goodhew <pie...@gmail.com>:


> Off the top of my head, I wonder if tests were passed because pixel erasing
> was not tried and the ks0108_write_char routine was the only one used ...
> PG
>

> --
> You received this message because you are subscribed to the Google Groups
> "jallib" group.
> To view this discussion on the web visit

> https://groups.google.com/d/msg/jallib/-/OPxyL3T0eg0J.

Piers Goodhew

unread,
Sep 5, 2011, 7:20:33 AM9/5/11
to jal...@googlegroups.com
Belatedly confirming that the current svn build produces visible text output when I point my modified-for-16f723a "glcd_ks0108" sample at it.

I saw Mike's efforts when I was starting up with my glcd. As long as nobody's in a hurry I might work on:
  • incorporating those changes
  • producing a more effective sample/test code, with multiple fonts, graphics primitives and erasure.
[That's if I can fit more than 1 font into my 192 bytes ...]

Right off the bat, Mike: is there any reason you're doing this
    if y > 191 then 
         y = y -192 
    elsif y > 127 then 
         y = y - 128 
    elsif y > SCREEN_MAX_Y then 
         y = y -SCREEN_ROWS 
    end if 

rather than:
    y = y & 63 -- or equivalent constant

Am I missing something? It's entirely possible.

PG

Joep Suijs

unread,
Sep 5, 2011, 10:51:54 AM9/5/11
to jal...@googlegroups.com
Hi Piers,

> Belatedly confirming that the current svn build produces visible text output
> when I point my modified-for-16f723a "glcd_ks0108" sample at it.

Thanks for the feedback!

> Right off the bat, Mike: is there any reason you're doing this
>     if y > 191 then
>          y = y -192
>     elsif y > 127 then
>          y = y - 128
>     elsif y > SCREEN_MAX_Y then
>          y = y -SCREEN_ROWS
>     end if
>
> rather than:
>     y = y & 63 -- or equivalent constant

Check with y=180 (not sure if it is an intended difference though).

Joep

Piers Goodhew

unread,
Sep 5, 2011, 11:15:59 PM9/5/11
to jal...@googlegroups.com


On Tuesday, 6 September 2011 00:51:54 UTC+10, Joep wrote:

> rather than:
>     y = y & 63 -- or equivalent constant

Check with y=180 (not sure if it is an intended difference though).

Is that a trick question? I don't think they are different.

I got all unit-testy, the following Ruby script (which runs all the Jal if/thens unmodified*) says they produce the same value for all 8-bit numbers:

#! /usr/bin/ruby


SCREEN_MAX_Y = 63

SCREEN_ROWS = 64


def three_ifs_way(y)

    if y > 191 then 

         y = y - 192 

    elsif y > 127 then 

         y = y - 128 

    elsif y > SCREEN_MAX_Y then 

         y = y - SCREEN_ROWS 

    end

    return y

end


def one_AND_way(y)

    return y & 63

end


#### main loop


return_value = 0


for i in 0..255

    if three_ifs_way(i) != one_AND_way(i) then

        puts "Bad! Methods differ for value #{i}"

        return_value += 1

    end

end

exit return_value 


* had to change "end if" to just "end" 

Joep Suijs

unread,
Sep 6, 2011, 12:47:37 AM9/6/11
to jal...@googlegroups.com

You are right. Not a trick question - my mistake.

Joep

Op dinsdag 6 september 2011 schreef Piers Goodhew (pie...@gmail.com) het volgende:
> --
> You received this message because you are subscribed to the Google Groups "jallib" group.
> To view this discussion on the web visit https://groups.google.com/d/msg/jallib/-/SUe3qf3xYfAJ.

> To post to this group, send email to jal...@googlegroups.com.
> To unsubscribe from this group, send email to jallib+un...@googlegroups.com <jallib%2Bunsu...@googlegroups.com>.

Rob Hamerling

unread,
Nov 25, 2011, 5:33:54 AM11/25/11
to jal...@googlegroups.com

Hi all, esp. Michael Watterson,

While adding comments to the math library I think I found an error in
one of the routine:

> -- Original: Michael Watterson
> function round_fixed(sword in fixed_point) return sbyte is
> if ((fixed_point & 0x10) > 0) then -- 128 and more = 0.5
> return (sbyte(fixed_point >> 8) + 1)
> else
> return (sbyte(fixed_point >> 8))
> end if
> end function

I think the 'if' statement should be:

if ((fixed_point & 0x80) > 0) then

Do you agree or do I misunderstand the fixed point notation?

Regards, Rob.


--
R. Hamerling, Netherlands --- http://www.robh.nl

Oliver Seitz

unread,
Nov 25, 2011, 5:46:09 AM11/25/11
to jal...@googlegroups.com

> Do you agree or do I misunderstand the fixed point
> notation?

Could that be the notation

<sbyte>.<sbyte>

which I did not copy to print_scalable?

Greets,
Kiste

Rob Hamerling

unread,
Nov 25, 2011, 5:58:40 AM11/25/11
to jal...@googlegroups.com

I think the fixed point notation in math.jal is <sbyte>.<byte>

Rob Hamerling

unread,
Nov 25, 2011, 6:19:14 AM11/25/11
to jal...@googlegroups.com

Hi Kiste,

On 25-11-11 11:46, Oliver Seitz wrote:

> which I did not copy to print_scalable?

I had a quick look in print_scalable and found not a single procedure
documented the way is should be according to Jalapi recommendations. Not
that print.jal is any better!!! And there are more libs requiring
improved docs!
Are you still working on print_scalable? Then please add comments such
that Jalapi will generate proper cocimentation files and a first time
user understands how to work with the procedures and functions.

Oliver Seitz

unread,
Nov 25, 2011, 6:51:40 AM11/25/11
to jal...@googlegroups.com

--- Rob Hamerling <robham...@gmail.com> schrieb am Fr, 25.11.2011:

> Von: Rob Hamerling <robham...@gmail.com>
> Betreff: [jallib] print_scalable
> An: jal...@googlegroups.com
> Datum: Freitag, 25. November, 2011 12:19 Uhr
>
> Hi Kiste,
>
> On 25-11-11 11:46, Oliver Seitz wrote:
>
> > which I did not copy to print_scalable?
>
> I had a quick look in print_scalable and found not a single
> procedure documented the way is should be according to
> Jalapi recommendations. Not that print.jal is any better!!!

I have to admit that I only took care to keep compatibility with print.jal. I did not think of first time users yet...

> Are you still working on print_scalable? Then please add
> comments such that Jalapi will generate proper cocimentation
> files and a first time user understands how to work with the
> procedures and functions.

It is on my to-do list, but JAL in general sits on a very low priority these days. That will hopefully change some day.

Greets,
Kiste

Reply all
Reply to author
Forward
0 new messages