Subsecond Timing (No Slot Clock) and Embedded Subroutines in Aztec C65

180 views
Skip to first unread message

Bill Buckels

unread,
Sep 12, 2013, 6:14:13 AM9/12/13
to
Available for Download from the following Link:

http://www.aztecmuseum.ca/extras/REALTIME.zip

Code Listing Follows:

/* ------------------------------------------------------------------------
System : Manx Aztec C65 Version 3.2b
MS-DOS cross-development environment
Platform : Apple IIe 128K PRODOS 8
Program : realtime (C) Copyright Bill Buckels 2013.
All rights reserved.

Description : Aztec C65 Demo

1. Standalone Program to Read the Date and Time from SMT Peripherals
No-Slot Clock (NSC). If an NSC is installed, using the code shown below,
you can provide sub-second accuracy in an Aztec C65 program, for either
ProDOS 8 or DOS 3.3 (the code is the same for either).

2. This program also demonstrates how Aztec C65's inline assembly can be
used to directly call 6502 machine language subroutines from within an
Aztec C65 program.

This program does not need any of the programs that were distributed with
the NSC Utilites Disk to read the time and date from the NSC because
already embedded within the realtime program (this program) is Craig
Peterson's READ.TIME program (see source code below).

The READ.TIME program is a clock driver which contains 2 subroutines; one
for installing itself, and the other for reading the NSC.

READ.TIME can be installed from within an Aztec C65 Program as easily as it
can be installed by BRUNning it from BASIC (as Craig suggests).

3. To write this program, all I did was to view READ.TIME in CiderPress's
Hex Viewer, and to copy the output to my programmer's editor using the
Windows Clipboard. I then massaged the hex values to change them to a C
language byte array. Rather than loading an external file from disk, I
simply load the code from memory to the location specified in Craig
Peterson's "ReadMe" which is on the NSC Version 1.4 disk. A snippet from
the "Read Me" which explains the details about how all this works is in the
source comments below.

The same technique, or variations thereof, can be applied for running other
machine language modules from within Aztec C65.

Written by : Bill Buckels
Date Written : September 2013

Revision : 1.0 First Release
Licence : You may use this program for whatever you wish as long
as you agree that Bill Buckels has no warranty or
liability obligations whatsoever from said use.
------------------------------------------------------------------------ */


/* Copyright Bill Buckels 2013 */

#define READ_TIME_ADDR 0x260
#define READ_TIME_LEN 366

/* The READ.TIME program Version 1.4 (C) Copyright Craig Peterson 1991 */
char _read_time[READ_TIME_LEN] = {
0xa9,0x00,0x8d,0xde,0x02,0xa9,0x03,0x09,
0xc0,0x8d,0x1f,0x03,0x8d,0x22,0x03,0x8d,
0x31,0x03,0x8d,0x3f,0x03,0xa9,0x03,0x8d,
0xdf,0x02,0xd0,0x16,0x00,0x00,0x00,0x00,
0x00,0x00,0x2f,0x00,0x00,0x2f,0x00,0x00,
0x20,0x00,0x00,0x3a,0x00,0x00,0x3a,0x00,
0x00,0x8d,0x20,0x0b,0x03,0xa2,0x07,0xbd,
0x03,0x03,0xdd,0xe0,0x02,0x90,0x0f,0xdd,
0xe8,0x02,0xb0,0x0a,0xca,0x10,0xf0,0xce,
0xdf,0x02,0xd0,0xe6,0x18,0x60,0xee,0xde,
0x02,0xad,0xde,0x02,0xc9,0x08,0x90,0xaf,
0xd0,0x1d,0xa9,0xc0,0xa0,0x15,0x8d,0x1b,
0x03,0x8c,0x1a,0x03,0xa0,0x07,0x8d,0x1f,
0x03,0x8c,0x1e,0x03,0x88,0x8d,0x6f,0x03,
0x8c,0x6e,0x03,0xa9,0xc8,0xd0,0x95,0xa9,
0x4c,0x8d,0x16,0x03,0x38,0x60,0x00,0x00,
0x00,0x01,0x01,0x01,0x00,0x00,0x00,0x00,
0x64,0x0d,0x20,0x38,0x98,0x3c,0x3c,0x64,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x18,0x90,0x09,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x38,0x08,0x78,0xa9,0x00,
0x8d,0x04,0x03,0x8d,0x80,0x02,0xad,0xa3,
0x03,0xad,0xff,0xcf,0x48,0x8d,0x00,0xc3,
0xad,0x04,0xc3,0xa2,0x08,0xbd,0xbf,0x03,
0x38,0x6a,0x48,0xa9,0x00,0x2a,0xa8,0xb9,
0x00,0xc3,0x68,0x4a,0xd0,0xf4,0xca,0xd0,
0xec,0xa2,0x08,0xa0,0x08,0xad,0x04,0xc3,
0x6a,0x66,0x42,0x88,0xd0,0xf7,0xa5,0x42,
0x9d,0x7f,0x02,0x4a,0x4a,0x4a,0x4a,0xa8,
0xa5,0x42,0xc0,0x00,0xf0,0x08,0x29,0x0f,
0x18,0x69,0x0a,0x88,0xd0,0xfb,0x9d,0x02,
0x03,0xca,0xd0,0xd7,0xad,0x80,0x02,0x8d,
0x83,0x02,0x68,0x30,0x03,0x8d,0xff,0xcf,
0xa0,0x11,0xa2,0x06,0xbd,0xc7,0x03,0x99,
0x80,0x02,0xbd,0x80,0x02,0x48,0x29,0x0f,
0x09,0x30,0x88,0x99,0x80,0x02,0x68,0x4a,
0x4a,0x4a,0x4a,0xd0,0x0c,0xe0,0x01,0xf0,
0x04,0xe0,0x04,0xd0,0x04,0xa9,0x20,0xd0,
0x02,0x09,0x30,0x88,0x99,0x80,0x02,0x88,
0xca,0xd0,0xd1,0x28,0xb0,0x19,0x20,0xbe,
0xde,0x20,0xe3,0xdf,0x20,0x6c,0xdd,0x85,
0x85,0x84,0x86,0xa9,0x80,0xa0,0x02,0xa2,
0x8d,0x20,0xe9,0xe3,0x20,0x9a,0xda,0x60,
0x5c,0xa3,0x3a,0xc5,0x5c,0xa3,0x3a,0xc5,
0x2f,0x2f,0x20,0x3a,0x3a,0x8d};

/*

Snippet from the NSC Version 1.4 "ReadMe"

The READ.TIME program allows you to read the time from the clock while
using BASIC or assembly language programs. You install the program by
typing 'BRUN READ.TIME', which will load READ.TIME in page $300 of your
Apple and automatically find the location of your No-Slot Clock. Then from
BASIC you just type 'CALL 768,T$', and the clock date and time will be
placed in the variable following the comma after '768'. This variable can
be any valid string variable. From assembly language, after 'BRUN'ing
READ.TIME, you just do a 'JSR $30B', and the ascii string representing the
time will be placed at $280-$291. Also, the hex values for the time are
placed at $303-$30A, as was true of the old CLOCKREAD program. If no
clock is present, a null value is returned to T$ and at location $304. See
the STARTUP program on the /No.Slot.Clock disk for an example of using this
call from BASIC. This version 1.4 of the NS.CLOCK.UTILS time setting
program now fully supports the day of the week function of the clock.
READ.TIME will return the day of the week in location 774 ($306). A 1
represents Sunday, a 2 Monday, ... up to a 7 for Saturday. READ.TIME is
not relocatable and will always load in part of page $200 and $300.

*/

/* load the clock driver from the embedded _read_time byte array...

note: this could also have been loaded from the READ.TIME disk file
like any other "well-behaved" subroutine written in 6502 machine code.

*/
initnsc()
{

char *brunptr = (char *)READ_TIME_ADDR;
int i;

/* bload read.clock to $260 */
for (i = 0; i < READ_TIME_LEN; i++) brunptr[i] = _read_time[i];

#asm
jsr $260 ; call init clock
#endasm

}

/* a structure to point into the registers in the NSC READ.TIME
driver... see notes above and the NSC manual for more details */
struct nsctm {
char year;
char month;
char date;
char day;
char hours;
char minutes;
char seconds;
char hundredths;
};

struct nsctm *nsctime = (struct nsctm *)(0x303);
char nscasctime[19];

/* read the current date time and time from the NSC */
readnsc()
{
char *ascptr = (char *)0x280;
int i;

#asm
jsr $30b ; call read clock
#endasm

/* transfer ascii string to our buffer */
nscasctime[18] = 0;
for (i=0;i<18;i++)nscasctime[i] = ascptr[i];

}

main()
{
crt80();
printf("NSClock Test\n");

/* install the NSC driver */
initnsc();

/* call the NSC and get the "new values" each time
a key is pressed... press ESC to end the demo */
for (;;) {
readnsc();

printf("\nCurrent Time: %s",nscasctime);
printf("Year %d Month %d Day %d Dow %d\n",
(int)nsctime->year,(int)nsctime->month,
(int)nsctime->date,(int)nsctime->day);
printf("Hours %d Minutes %d Seconds %d Hundredths %d\n",
(int)nsctime->hours,(int)nsctime->minutes,
(int)nsctime->seconds,(int)nsctime->hundredths);

printf("Press ESC to Exit, Any other key to continue...\n");
if (getch() == 27) break;
}
_exit();
}


mver...@libero.it

unread,
Sep 12, 2013, 7:52:25 AM9/12/13
to
Are you, or someone else, interested in the same thing (more or less) made in UCSD Pascal?

Marco.
Message has been deleted

Bill Buckels

unread,
Sep 12, 2013, 3:57:40 PM9/12/13
to

<mver...@libero.it> wrote:
> Il giorno gioved� 12 settembre 2013 12:14:13 UTC+2, Bill Buckels ha
> scritto:
>> Available for Download from the following Link:
>> http://www.aztecmuseum.ca/extras/REALTIME.zip

>Are you, or someone else, interested in the same thing (more or less) made
>in UCSD Pascal?

Hi Marco,

Of course I'd like to see it.

You can send it to my email if you like... and there is lots of space in
this ng for threads too:)

Bill


Marco Verpelli

unread,
Sep 13, 2013, 4:26:21 AM9/13/13
to
On Thursday, September 12, 2013 9:57:40 PM UTC+2, Bill Buckels wrote:
> <mver...@libero.it> wrote:
>
> > Il giorno giovedì 12 settembre 2013 12:14:13 UTC+2, Bill Buckels ha
>
> > scritto:
>
> >> Available for Download from the following Link:
>
> >> http://www.aztecmuseum.ca/extras/REALTIME.zip
>
>
>
> >Are you, or someone else, interested in the same thing (more or less) made
>
> >in UCSD Pascal?
>
>
>
> Hi Marco,
>
>
>
> Of course I'd like to see it.
>
>
>
> You can send it to my email if you like... and there is lots of space in
>
> this ng for threads too:)
>
>
>
> Bill

I use this program to startup Pascal on my //c. The code is sto^H^H^H ... based on many other source, so I do not claim any copyright.

First assembly:
--------------------------------------------------------------------------------
.MACRO POP ;POP A WORD FROM STACK
PLA
STA %1
PLA
STA %1+1
.ENDM

.MACRO PUSH ;PUSH A WORD INTO STACK
LDA %1+1
PHA
LDA %1
PHA
.ENDM

.TITLE "NSC - TIMESTAMP"

RETURN .EQU 00 ;PASCAL RETURN ADDRESS
TS .EQU 02 ;RECORD RETURN ADDRESS
TEMP .EQU 04 ;USED IN BCD -> BIN CONVERSION
RDCXROM .EQU 0C015 ;>127 IF ROM CX IN USE
SETSLOTCXROM .EQU 0C006 ;DISABLE ROM CX
SETINTCXROM .EQU 0C007 ;ENABLE ROM CX
CLOCK .EQU 0C300 ;CLOCK IN SLOT #3
WRITE0 .EQU CLOCK ;A2=0 (WRITE) A0=DATA
WRITE1 .EQU CLOCK+1
READ .EQU CLOCK+4 ;A2=1 (READ) D0=DATA

;READ THE NoSlotClock.
;RETURN 8 WORDS = 16 BYTES, THIS DATA CORRESPOND
;TO A RECORD DECLARED IN PASCAL SOURCE AS:
;
;type timerec=record
; year:0..99;
; month:1..12;
; day:1..31;
; dow:1..7;
; hour:0..12;
; minute:0..59;
; second:0..59;
; hundredth:0.99
; end;
;
;THE PROCEDURE IS DECLARED IN PASCAL SOURCE AS:
;
;procedure timestamp(var ts:timerec);

.PROC TIMESTAMP,1 ;THE PARAMETER IS THE RECORD ADDRESS

POP RETURN ;SAVE PASCAL RETURN ADDRESS
POP TS ;SAVE RECORD ADDRESS

;SAVE ROM STATUS

SEI ;NO INTERRUPT WHILE READ THE CLOCK
LDA RDCXROM
PHP
STA SETINTCXROM ;SELECT ROM AND CLOCK

;PREPARE THE CLOCK FOR READ

LDA READ ;SEND PATTERN
LDY #07
$1 LDX #07
LDA PATTERN,Y
$2 ROR A
PHA
BCS $3
LDA WRITE0
BCC $4
$3 LDA WRITE1
$4 PLA
DEX
BPL $2
DEY
BPL $1

;READ THE CLOCK

LDY #0F ;RETURN 8 WORDS = 16 BYTES
$5 LDA #00 ;HIGH WORD IS ALWAYS 0
STA @TS,Y
DEY
LDX #07
$6 PHA
LDA READ
ROR A
PLA
ROR A
DEX
BPL $6

;BCD -> BIN CONVERSION

PHA ;SAVE ORIGINAL VALUE
AND #0F0 ;TAKE HIGH NIBBLE
LSR A ;/ 2 = HIGH NIBBLE * 8
STA TEMP ;SAVE * 8
LSR A ;/ 4
LSR A ;/ 8 = HIGH NIBBLE * 2
ADC TEMP
STA TEMP ;ACCUMULATOR = HIGH NIBBLE * 10
PLA ;RESTORE ORIGINAL VALUE
AND #00F ;TAKE LOW NIBBLE
ADC TEMP ;ADD IT TO HIGH NIBBLE
STA @TS,Y ;RETURN LOW WORD

DEY
BPL $5

;THE END

PLP ;RESTORE ROM CX STATE
BMI $7
STA SETSLOTCXROM ;PUT IT BACK

$7 PUSH RETURN ;RETURN TO PASCAL
RTS

;CLOCK ACTIVATION PATTERN

PATTERN .BYTE 05C,0A3,03A,0C5,05C,0A3,03A,0C5

.END ;END OF CODE

Second Pascal:
--------------------------------------------------------------------------------
{ONLY for version 1.3 128k}
program setdate;
type date=packed record {date on disk}
month:1..12;
day:1..31;
year:0..99
end;
timerec=record {date from clock}
year:0..99;
month:1..12;
day:1..31;
dow:1..7; {1=Sunday in this century}
hour:0..12;
minute:0..59;
second:0..59;
hundredth:0..99
end;
var block:array[0..255] of date; {disk I/O buffer}
ts:timerec;

procedure poke(address:integer;value:date);
var memref:record {ye old variable record trick}
case integer of
1:(addr:integer);
2:(ptr:^date)
end;
begin
memref.addr:=address;
memref.ptr^:=value
end;

procedure timestamp(var ts:timerec);external;

procedure print2(value:integer); {print 2 digits (0d or dd)}
begin
if value<10
then write('0');
write(value)
end;

begin
unitread(4,block,512,2); {disk -> buffer}
timestamp(ts); {read the clock}
block[10].month:=ts.month; {write date into buffer}
block[10].day:=ts.day;
block[10].year:=ts.year;
unitwrite(4,block,512,2); {buffer -> disk}
{write date in RAM}
poke(-18342,block[10]); {pascal 1.2 and 1.3 128k}
{display date and time}
writeln;
case ts.dow of
1:write('Sun');
2:write('Mon');
3:write('Tue');
4:write('Wed');
5:write('Thu');
6:write('Fri');
7:write('Sat')
end;
write(' ');print2(ts.day);write('-');
case ts.month of
1:write('Jan');
2:write('Feb');
3:write('Mar');
4:write('Apr');
5:write('May');
6:write('Jun');
7:write('Jul');
8:write('Aug');
9:write('Sep');
10:write('Oct');
11:write('Nov');
12:write('Dec')
end;
write('-');print2(ts.year);write(' ');
print2(ts.hour);write(':');print2(ts.minute);
end.
--------------------------------------------------------------------------------

In my old notes I wrote the address for the others version of UCSD Pascal. If only I can find it...

Here is the link for a disk image with the source:

https://doc-0k-b8-docs.googleusercontent.com/docs/securesc/ha0ro937gcuc7l7deffksulhg5h7mbp1/btob5rrvq0srgadeuqt4nik424cjreiu/1379059200000/12813824801444082568/*/0B7aRV0UmyLVNcE9LRmI4cTV3a2s?h=16653014193614665626&e=download

Marco Verpelli

unread,
Sep 13, 2013, 5:08:02 AM9/13/13
to
Found it!

poke(-21992,block[10]) pascal 1.1
poke(-18342,block[10]) pascal 1.2 and 1.3 128k
poke(-21252,block[10]) pascal 1.2 and 1.3 64k

Benoit0123

unread,
Sep 17, 2013, 2:37:34 AM9/17/13
to
Hello Marco,

Marco Verpelli wrote:
> On Thursday, September 12, 2013 9:57:40 PM UTC+2, Bill Buckels wrote:
(snip)
> ;SAVE ROM STATUS
>
> SEI ;NO INTERRUPT WHILE READ THE CLOCK
> LDA RDCXROM
> PHP
> STA SETINTCXROM ;SELECT ROM AND CLOCK
It seems that your routine disables the interrupts without reinstating them
aa the read is completed.
> PLP ;RESTORE ROM CX STATE
> BMI $7
> STA SETSLOTCXROM ;PUT IT BACK
May I suggest that you put the SEI instruction after the PHP so that the
relevant PLP at the end of your routine
will restore the I bit too from the saved P and interrupts continue to work
they used to before calling your routine?

Best regards,
Benoît



Marco Verpelli

unread,
Sep 17, 2013, 3:11:07 AM9/17/13
to
Thank you, UCSD Pascal never crash after running this routine, so I was unable to spot the bug.

Marco

mver...@libero.it

unread,
Jun 25, 2015, 7:46:50 AM6/25/15
to
... and now after nearly two years the next step in NSC and Aztec C.

Bill Buckels show to us how to incorporate ML in C source (tanks for all your code!)

My try is a stripped version, and an example how to mixing assembly and C.

--- time.c ---
void main()
{
struct ncstime {
char year;
char month;
char date;
char day;
char hours;
char minutes;
char seconds;
char hundredths;
} time;
static char *weekdayname[] = {"Sun","Mon","Tues","Wednes",
"Thurs","Fri","Satur"};
extern void readnsc();

readnsc(&time);
printf("%sday %02x/%02x/%02x %02x:%02x:%02x.%02x\n",
weekdayname[time.day & 0xf -1],time.month,time.date,time.year,
time.hours,time.minutes,time.seconds,time.hundredths);

--- readnsc.a65 ---
instxt "zpage.h"

clrrom equ $CFFF
writensc equ $C300 ;assume NSC in slot #3 (OK for AppleWin emulator)
readnsc equ writensc+4

public readnsc_

readnsc_

ldy #2
lda (SP),y
sta R1
ldy #3
lda (SP),y
sta R1+1

php
sei
lda clrrom
pha
sta writensc
lda readnsc
ldx #7
writepat lda pattern,x
sec
ror
l1 pha
lda #$00
rol
tay
lda writensc,y
pla
lsr
bne l1
dex
bpl writepat
ldy #7
l5 ldx #7
l6 pha
lda readnsc
ror
pla
ror
dex
bpl l6
sta (R1),y
dey
bpl l5
pla
bmi l3
sta clrrom
l3 plp
rts

pattern fcb $5C,$A3,$3A,$C5,$5C,$A3,$3A,$C5
--- end ---

Here the disk image:

https://drive.google.com/file/d/0Bz0ReUsiwYcpaWdYNVJnZkdBOVE/view?usp=sharing

Marco

qkumba

unread,
Jun 25, 2015, 5:40:31 PM6/25/15
to
Regarding this:

l6 pha
lda readnsc
ror
pla
ror

can it be this?

l6 lsr readnsc
ror

David Empson

unread,
Jun 25, 2015, 5:57:42 PM6/25/15
to
No, because that would cause a read and write access to the NSC's read
location, which would break the required access pattern.

--
David Empson
dem...@actrix.gen.nz

mver...@libero.it

unread,
Jun 26, 2015, 2:42:42 AM6/26/15
to
> No, because that would cause a read and write access to the NSC's read
> location, which would break the required access pattern.

Right. You must respect the sequence.

Marco

Bill Buckels

unread,
Jun 26, 2015, 7:37:40 PM6/26/15
to
Marco wrote:

>Bill Buckels show to us how to incorporate ML in C source (tanks for all
>your code!)

You're quite welcome... here's the cc65 NSC equivalent... (sort of )

http://www.appleoldies.ca/cc65/programs/REALTIME.zip

Maybe you want to write an improved version of this next:)

Bill


Bill Garber

unread,
Jun 27, 2015, 12:31:14 AM6/27/15
to

"Bill Buckels" <bbuc...@mts.net> wrote in
message news:mmkno2$jif$1...@speranza.aioe.org...
I would add solving the number Dow(Day of week)
to the three letter abbreviation, if you please.

Thank you,

Bill Garber - I love my
C1 D0 D0 CC C5 A0 C9 C9 C7 D3
http://www.sepa-electronics.com


mver...@libero.it

unread,
Jun 27, 2015, 3:24:27 AM6/27/15
to
1) We have a little problem with the DOW. The dox say 01 = Monday ... 07 = Sunday. But, see Pascal remarks, in this century 01 = Sunday. So you must check all your old program and add an note in your agenda for the first day of the next century.

2) I'll give a try to cc65. Shame this don't run natively on Apple.

Marco

P.S. Bill I misspelled your name, my finger (mind!) get twisted. That is why I like compilers: they warning you!

Bill Buckels

unread,
Jun 27, 2015, 7:13:43 PM6/27/15
to
Marco wrote:
>I'll give a try to cc65. Shame this don't run natively on Apple.

It would not be possible to to run a modern optimizing compiler of the
quality of cc65 on a slow old computer. And the code cc65 generates is far
quicker and less stack intensive than Aztec C65. The binaries are tiny; just
better in every modern way.

However, everyone is aware of my love for Aztec C65 which may not make sense
to a coder who is not also a historian.

If we could have got the Aztec C source code we could have modernized it,
but it was discarded, and in my mind we have done all we can with Aztec C65
and it was time for my twisted mind to move forward

>P.S. Bill I misspelled your name, my finger (mind!) get twisted. That is
>why I like compilers: they warning you!

My Italian is far worse than your English. Once I took a train to Sorrento
from Rome and I missed my stop and ended-up in Pompeii. But I finally got to
Sorrento and caught the bus to Praino after waving my hands a lot:)

Bill

Bill


mver...@libero.it

unread,
Jun 28, 2015, 3:01:38 AM6/28/15
to

[OT]
Ride a train in the south: tanks God you are still alive.

Last December as usual we decide to spend the Christmas holidays in Antibes. We made the trip with a French Railways train. What happened? Charlie (or God) stole the handle and the train it won't stop going. No way to slow down.
They missed completely the Antibes station and marooned all of us in Cannes. Only after I acted, on purpose, as a mad they decided to use a TGV to get back in Antibes: two hours for ~11 km

Marco

[/OT]

mver...@libero.it

unread,
Jun 29, 2015, 2:03:30 PM6/29/15
to
Back to the Apple II businnes.

Here are my adventure with CC65:

I'm a new user of this compiler. Downloaded the win-snapshot. Made the few changes necessary in the C code. First run: the compiler report no warnins no errors. Great! But... wait a minute... wtf: ok no errors but also no code generated. Turned out it was the endline character. The compiler likes CR/LF or LF, of course my file was CR (the natural way for Apple II). Spend a little more time with the syntax of the assembler. Lost an afternoon searching in the documentation how to pass parameters from C to ML, nothing! Brownsed the wiki and found an example: no cigar! Look at the source code of the compiler: Fiat Lux!

Please don't get me wrong I don't want to criticize this tools or the developers. It's a manna from the heaven for those intentioned in serious programming and the learning curve is hard. I don't want spend too much time dealing with a DOS windows.

Anywhere here the source code, the makefile and a disk image.

https://drive.google.com/file/d/0Bz0ReUsiwYcpMkwzUzlWT1JlaFk/view?usp=sharing

Marco.
Reply all
Reply to author
Forward
0 new messages