Forum - MCS Electronics

 

FAQFAQ SearchSearch RegisterRegister Log inLog in

Oscilloscope Clock

 
Post new topic   Reply to topic    www.mcselec.com Forum Index -> BASCOM Project Blog
View previous topic :: View next topic  
Author Message
Dave

Bascom Member



Joined: 05 Feb 2005
Posts: 314
Location: OR

usa.gif
PostPosted: Mon Dec 03, 2012 8:56 pm    Post subject: Oscilloscope Clock Reply with quote

Hello Bascom fans.
About a year ago I purchased a digital scope, my old analog scope has been
collecting dust ever since. I thought a scope clock would be a fitting retirement
for this old 20MHz analog scope. I looked around the web and didn't find any
Bascom code for O-scope clocks so I started from zero.

This is my first working version. My goal was to get the timing issues worked
out then latter work on a fancier design. This version does have a few features that I haven't
seen on other scope clocks. One is that the hands move in one degree steps rather then
the more common six degree steps. The other is the that the dial second tick marks brighten
as the second hand sweeps past.

My hardware consist of a ATmega328 running at 20MHz.
The DAC is a AD7302, it's a dual 8bit parallel type.
And there is a 2N2222A transistor to switch the Z axis on and off.
One DAC is the X axis and the other for the Y axis.
(0,0) is the lower left corner. (255,255) is the upper right.

When I started I thought I would be drawing vectors. I imagined writing two sets of xy points
to the DACs and seeing a line between the points. That didn't happen. The rise time of the DAC is way
to fast for my 20MHz scope to display. What I saw when I did that was the two dot but no line in between,
even when the intensity was turned up. Displaying an image is very much like working
with a 256x256 graphics display. Only you have to refresh the whole screen many times per second.

Two thirds of the cpu clk cycles are used to refresh the screen. That routine (isr_DrawScreen:) needs
optimization before the project can grow much more. I would like some help in that area. Also I wonder
if one of the graphics lib could be modified to work with this hardware? Having fast routines like Line and
Circle might be very useful.

Just one more thing.

WARNING: This project will burn an image of the clock onto you crt.
Don't run this on a scope you care about because the damage is permanent.

see on YouTube. http://youtu.be/t-rwKsku9sQ

That's about it. Your comments are appreciated.

Code:

'********** WARNING  WARNING   WARNING ****************
'  This project may damage your scope. Don't try this
'  on an oscilloscope that you care about.
'  It will burn your crt causing permanent damage.
'******************************************************

'--- Scope Clock ver 1.5 ---
'Nov. 30, 2012
'By:David Carr
'dave@technofun.org
'
'Compiled with:
'BASCOM 2.0.7.5.003
'http://mcselec.com/
'
const Vers="Scope_Clk1.5"
const rfm_Addr=&h0C

$regfile = "m328pdef.dat"
$crystal = 20000000

$hwstack = 100
$swstack = 100
$framesize = 100

'Length of the hour, minute and second hands.
const MinLen = 115
const HrLen = 85
'The second hand is a specal case because it has a tail.
'The sum of SecLen+SecYstrt must not be greater then 128.
const SecLen = 154   'Total drawn length of second hand.
const SecYstrt = -30 'Second hand tail length.
const SecYend = SecLen+SecYstrt
const SecIoffst = SecLen-SecYend+1 'Offset for SecHand xy array indexes.
const SecArrayLen = SecLen+1

dim SecDeg as word
dim Tdeg as word
dim i as integer
dim i2 as integer
dim n as byte
dim X as byte
dim Y as byte
dim l as byte
dim w1 as word 'reserved for isr routines
dim w2 as word 'reserved for isr routines
dim Hour as word
dim Minute as word
dim Second as word
dim MinDeg as word
dim Mdeg as word
dim HrDeg as word
dim Hdeg as word
dim SecDecay as word
dim HourFlg as bit
dim MinHandX(MinLen) as byte
dim MinHandY(MinLen) as byte
dim HrHandX(HrLen) as byte
dim HrHandY(HrLen) as byte
dim SecHandX(SecArrayLen) as byte
dim SecHandY(SecArrayLen) as byte
dim sine as single
dim cosine as single
dim s1 as single
dim s2 as single
dim strCmnd as string*1
dim strArg as string*8
dim secFlg as byte

secFlg=3 'show second hand and dot enhancement by default.
HourFlg=1 'show hour dot enhancement by default.
Mdeg=1
Hdeg=1
Hour=12

declare sub SetTime(t as string*8)

'-------- AD7302 is a dual 8 bit DAC. -------
'port configs for DAC.
'Control lines.
DAC_WR alias portd.4
DAC_AB alias portd.3
LDAC alias portb.1

config DAC_WR = output
config DAC_AB = output
config LDAC = output

'DAC data lines map.
'DAC - DB7     DB6     DB5     DB4     DB3     DB2     DB1     DB0
'AVR - PD.7    PD.6    PC.5    PC.4    PC.3    PC.2    PC.1    PC.0

DB0to5 alias Portc
DB6 alias PORTD.6
DB7 alias PORTD.7

config DB0to5 = output
config  DB6 = output
config  DB7 = output
'--------------------------------------------

'Test point and z (crt brightness) ports.
TP alias portd.0
config TP = output 'don't use TP if you use the serial port.
z alias portd.5
config z = output:reset z


'NOTE:
'To replace the wireless features with normal serial I/O remove
'the next section of code and rewrite the subroutine UserInput:

'****** INCLUDE THIS FOR RFM12B BOOTLOADER SUPORT ********
'Include this in projects that need a serial link
'over the RFM12B wireless connection.
'Also this include will cause an automatic jump to the bootloader
'if the uploader is trying to connect.
'
'rfm12b hardware config. See include file.
const rfm_DeviceCode = 3

'Packet lenth is rfm_MaxMsgLen+8 so Msg length must be less then 247.
'128 or less is recomended.
const rfm_MaxMsgLen = 15

$include "C:\Documents and Settings\Edev\Desktop\My Projects\rfm_Include\Inc_RFM12B_Generic_2.8.bas"
rfm_Myaddr=rfm_Addr 'set at the beginning of this file.
'Enable Interrupts
goto PastRfmEvents

rfm_ExitMain:
'disable anything that needs do be disabled
'before jumping to the bootloader.
   disable interrupts
   reset z
   stop timer1
   stop TIMER0
   goto rfm_BootLoaderAddr
return

'When a rfm message is ready.
'Normaly this sub should be left empty.
'It's called from an interrupt routine
'so interrupts are disabled while here.
rfm_MsgEvent:
    'reset Rx Message Flag.
    rfm_RxMsgFlg=0
    gosub User_Input
return

'These two routines are called just before and just
'after rfm tx a packet. Normally these will be left
'empty. But if interrupts are using much of the cpu
'cycles they should be disabled/enabled here.
rfm_PreTx:
   disable OC0A
   disable OC1A
return

rfm_PostTx:
    enable OC0A
    enable OC1A
return

PastRfmEvents:
rfm_Tx vers
'***********************************************************

'Clock tick rate.
'Setup timer1 to fire an interrupt 6 times a second.
'Mode 4
'Clk/256
Tccr1a=0
tccr1b=&b0000_1100
ocr1a=13020 '~6 Hz   -0.001% error.
on OC1A isr_Tick
enable OC1A

'Screen refresh rate.
'setup timer0 for 77 interrupts per second.
'Mode 2
'Clk/1024
tccr0a=&b0000_0010
tccr0b=&b0000_0101
ocr0a=255
on OC0A isr_DrawScreen
enable  OC0A

Enable Interrupts

do
   'These three routines calculate the new
   'hour, minute & second hand positions.
   gosub SecXY
   gosub MinXY
   gosub HourXY
loop

User_Input:
  strCmnd=left(rfm_Msg,1)
  strArg=mid(rfm_Msg,2)

 Select case strCmnd
 case "S"
    'Command to set the time.
    'Command format is: Shh:mm:ss
    'make sure strArg is no more then 8 chars long.
    strArg=left(strArg,8)
    SetTime strArg
 case "s"
    'Command to change the way seconds are displayed.
    'Format is:
    's0 - No seconds are displayed.
    's1 - Second hand only.
    's2 - Dial enhancement only.
    's3 - Second hand & Dial enhancement.
    secFlg=val(strArg)
 case "h"
    'Command to toggle hour dial enhancements.
    'Format is: h
    toggle HourFlg
 case else
    'Any other user input returns program version
    'and clock time hh:mm:ss.
    rfm_Tx vers
    waitms 10
    rfm_Msg=str(hour)+":"+str(Minute)+":"+str(Second)
    rfm_Tx rfm_Msg
 end select
return

'draw screen about 77 times a second.
isr_DrawScreen:
   'set TP
   set z  'brighten the crt.
   'Draw the dial from data points in flash.
   'pause at ever fifth point and the current Seconds point.
   'making those points brighter.
   restore Dial
   read l
   decr l
   for n=0 to l
      read X
      read Y
      gosub  Write_DAC_XY
      if HourFlg=1 then
          w1=n mod 5
          if w1=0 then waitus 250
      endif

      if secFlg.1=1 then
          'This line make the dial points flash as the second hand sweeps past.
          'if n=second then waitus 400

          'This version make the points flash with a slow decay.
          'But on my scope it also causes the dial to distort slightly.
          if n=second then
             w2=SecDeg mod 6
             if w2=0 then
                SecDecay=350
             else
                if SecDecay>8 then SecDecay=SecDecay-8
             endif
             waitus SecDecay
          endif
      endif
   next

   'draw 1
   restore One
   read l
   for n=1 to l
      read X
      read Y
      x=x+123
      y=y+236
      gosub  Write_DAC_XY
   next

   'draw 2
   restore Two
   read l
   for n=1 to l
      read X
      read Y
      x=x+128
      y=y+236
      gosub  Write_DAC_XY
   next

   'draw 3
   restore Three
   read l
   for n=1 to l
      read X
      read Y
      x=x+243
      y=y+122
      gosub  Write_DAC_XY
   next

   'draw 6
   restore Six
   read l
   for n=1 to l
      read X
      read Y
      x=x+126
      y=y+6
      gosub  Write_DAC_XY
   next

   'draw 9
   restore Nine
   read l
   for n=1 to l
      read X
      read Y
      x=x+8
      y=y+122
      gosub  Write_DAC_XY
   next

   'draw the center circle.
   restore Center
   read l
   for n=1 to l
      read X
      read Y
      gosub  Write_DAC_XY
   next

   set TP

   'drawing the seond hand can be turned off.
   if secFlg.0=1 then
     'draw the second hand.
     for n=1 to SecLen
        x=SecHandX(n)
        y=SecHandY(n)
        gosub  Write_DAC_XY
     next
   endif

   'Draw the minute hand.
   for n=1 to MinLen
      x=MinHandX(n)
      y=MinHandY(n)
      gosub  Write_DAC_XY
   next

   'Draw the hour hand.
   for n=1 to HrLen
      x=HrHandX(n)
      y=HrHandY(n)
      gosub  Write_DAC_XY
   next

   'dim the crt.
   reset z
   'stop at the center.
   X=128
   Y=128
   gosub  Write_DAC_XY
   reset TP
return


'6 ticks/second
'360 ticks/minute
isr_Tick:
   incr SecDeg
   if SecDeg=360 then SecDeg=0
   second=SecDeg/6

   'Advance the minute hand one degree
   'for every 60 degrees of the second hand.
   w1=SecDeg mod 60
   if w1=0 then
      incr MinDeg
      if MinDeg=360 then MinDeg=0

      'calculate the minute from the hand postion.
      Minute=MinDeg/6

      'Advance the hour hand one degree
      'for every 12 degrees of the minute hand.
      w2=MinDeg mod 12
      if w2=0 then
         incr HrDeg
         if HrDeg=360 then HrDeg=0

         'calculate the hour from the hand postion.
         Hour=HrDeg/30
         if Hour=0 then Hour=12
      endif

   endif
return

Write_DAC_XY:
   'write X to DAC
   set DAC_AB
   DB0to5 = x and &b0011_1111
   DB6 = x.6
   DB7 = x.7
   reset  DAC_WR
   set DAC_WR

   'write Y to DAC
   reset DAC_AB
   DB0to5 = y and &b0011_1111
   DB6 = y.6
   DB7 = y.7
   reset  DAC_WR
   set DAC_WR
   reset LDAC
   set LDAC
return

dim hms(3) as string*4
sub SetTime(t as string*8)
   local H as word
   local M as word
   local S as word
   local b as word
   'local hms(3) as string*2
   local p as byte

   hms(1)="":hms(2)="":hms(3)=""

   p=split(t,hms(1),":")

   H=val(hms(1))
   if H>=1 and H<=12 then
   else
      exit sub
   endif

   M=val(hms(2))
   if M>=0 and M<=59 then
   else
      exit sub
   endif

   S=val(hms(3))
   if S>=0 and S<=59 then
   else
      exit sub
   endif

   'set hour, minute & second.
   Hour=H
   Minute=M
   Second=S
   'calculate new hand positions.
   SecDeg=S*6
   MinDeg=M*6
   b=SecDeg / 60
   MinDeg=MinDeg+b
   HrDeg=H*30
   b=MinDeg /12
   HrDeg=HrDeg+b

end sub

SecXY:
'equations to rotate an xy point around some xy_origin:
'x = (((x - x_origin) * cos(angle)) + ((y - y_origin) * sin(angle))) + x_origin
'y = (((y - y_origin) * cos(angle)) - ((x - x_origin) * sin(angle))) + y_origin

'--------------------- Second hand calculations ---------------------------------------------
'SecDeg increments  from 0 to 359 deg. in isr_Tick.
'SecDeg updates at a rate of 6Hz (one minute = 365 degree's)
'Each time there is a new tick calculate the new xy points for the second hand.
if Tdeg<>SecDeg then
    Tdeg=SecDeg
    'Calculate then sin and cos for the new Angle.
    s1=Tdeg   'convert Angle to a single.
    s1=deg2rad(s1)  'convert  degree's to radians.
    Sine=sin(s1)
    Cosine=cos(s1)

    'The second hand is just a line of dots on the y axis. Starting at x=0,y=SecYstrt
    'It is created here then rotated to the angle SecDeg.
    'i represents -->  (y - y_orgin)
    for i= SecYstrt to SecYend
         i2=i+SecIoffst
           '-------------------- New X values for angle SecDeg -------------------------------
         'x = (((x - x_origin) * cos(angle)) + ((y - y_origin) * sin(angle))) + x_origin
         'x = (        0            * Cosine(A)  ) + (      s2          *   Sine(A)    ) + 128

         'subtract the x origin(128) from x also 128.
         's1=128-128     's1 = zero , So comment out.

         'cos of x.
         's1=s1*Cosine  's1 = zero , So comment out.

         'i is the y coordinate of the second hand.
         'convert to single and multiply by the sin SecDeg.
         s2=i
         s2=s2*sine

         's2=s2+s1         's1 = 0 , So comment out.

         'add offset bak to x=128
         s2=s2+128

         'store it as a byte.
         SecHandX(i2)=round(s2)
         '------------------------------------------------------------------------------------

         '---------- New Y values.  See comments above for new x value. ----------------------
         'y = (((y - y_origin) * cos(angle)) - ((x - x_origin) * sin(angle))) + y_origin
         'y = (        s1          * Cosine(A)  ) - (       0           *   Sine(A)    ) + 128
         s1=i
         s1=s1*cosine
         's2=0
         's2=s2*sine
         's1=s1-s2
         s1=s1+128
         SecHandY(i2)=round(s1)
         '-------------------------------------------------------------------------------------
    next
endif
return

MinXY:
    'Minute hand calculation.
    'See second hand code for comments.
    if Mdeg<>MinDeg then
        Mdeg=MinDeg
        s1=Mdeg
        s1=deg2rad(s1)
        Sine=sin(s1)
        Cosine=cos(s1)
        for i= 1 to MinLen
            'X
            s2=i
            s2=s2*sine
            s2=s2+128
            MinHandX(i)=round(s2)
            'Y
            s1=i
            s1=s1*cosine
            s1=s1+128
            MinHandY(i)=round(s1)
        next
    endif
return

HourXY:
'Hour hand calculation.
'See second hand code for comments.
if Hdeg<>HrDeg then
    Hdeg=HrDeg
    s1=Hdeg
    s1=deg2rad(s1)
    Sine=sin(s1)
    Cosine=cos(s1)
    for i= 1 to HrLen
        'X
        s2=i
        s2=s2*sine
        s2=s2+128
        HrHandX(i)=round(s2)
        'Y
        s1=i
        s1=s1*cosine
        s1=s1+128
        HrHandY(i)=round(s1)
    next
endif
return

'The first byte of each set of data is the number of xy pairs.
'Data is aranged in x,y,x,y,x,y... pairs.
Dial:
data 60 '60 x,y pairs.
data 128,253,141,252,154,250,167,247,179,242
data 191,236,201,229,212,221,221,212,229,202
data 236,191,242,179,247,167,250,154,252,141
data 253,128,252,115,250,102,247,089,242,077
data 236,066,229,055,221,044,212,035,202,028
data 191,020,179,014,167,009,154,006,141,004
data 128,003,115,004,102,006,089,009,077,014
data 066,020,055,027,044,035,035,044,027,055
data 020,066,014,077,009,089,006,102,004,115
data 003,128,004,141,006,154,009,167,014,179
data 020,191,027,202,035,212,044,221,055,229
data 066,236,077,242,089,247,102,250,115,252

One:
data 7
data 0,0,0,2,0,4,0,6,0,8,0,10,0,12

Two:
data 16
data 0,9,1,11,3,12,5,12,7,11,8,9,8,7,6,5
data 4,4,2,3,0,2,0,0,2,0,4,0,6,0,8,0

Three:
data 12
data 0,1,2,0,4,0,6,2,6,4,5,6,3,6,6,8,6,10,4,11,2,11,0,10

Six:
data 16
data 0,3,1,1,3,0,5,0,7,1,8,3,8,5,6,6,4,7,2,6,0,5,0,8,1,10,3,12,5,12,7,11

Nine:
data 17
data 0,1,2,0,4,0,6,0,8,2,8,4,8,6,8,8,7,10,5,11,3,11,1,10,0,8,1,6,3,5,5,5,7,6

Center:
data 16 '16=circle 36=filled circle.
data 125,128,125,129,126,130,127,131,128,131,129,131,130,130,131,129
data 131,128,131,127,130,126,129,125,128,125,127,125,126,126,125,127
data 126,127,126,128,126,129,127,130,128,130,129,130,130,129,130,128
data 130,127,127,126,128,126,127,126,128,127,127,127,127,128,127,129
data 128,129,129,129,129,128,129,127
 


Last edited by Dave on Mon Dec 03, 2012 10:58 pm; edited 1 time in total
Back to top
View user's profile
albertsm

Administrator



Joined: 09 Apr 2004
Posts: 5922
Location: Holland

blank.gif
PostPosted: Mon Dec 03, 2012 10:31 pm    Post subject: Reply with quote

impressive Dave! i watched the video and it is smooth.
The Write_DAC_XY routine creates the dot right?
It should be reasonable simple to alter an existing graphical lcd lib. you need to pset.
But pset also can erase a dot. you can not really erase a dot. so you would need some screen buffer for the dots.
this makes it bit more complicated. i hope someone can assist you.

_________________
Mark
Back to top
View user's profile Visit poster's website
Dave

Bascom Member



Joined: 05 Feb 2005
Posts: 314
Location: OR

usa.gif
PostPosted: Mon Dec 03, 2012 10:56 pm    Post subject: Reply with quote

Mark
Yes, the DAC creates the dot and the time till the next dot determines the brightness. The whole screen must be redrawn 50 or so times a second, any less and the screen will flicker. The isr_DrawScreen: routine refreshes at 77Hz and uses about 60% of the cpu. The rest of the time is used calculating the new hand angles. I currently calculate the new position for every dot in the hands. It might be faster to calculate just the two end points and use a fast line draw routine from a graphics lib. All that would only help hands that are straight lines however. I'll be asking for help when I know more about what the questions are.

Thanks for commenting,
Dave
Back to top
View user's profile
bzijlstra

Bascom Ambassador



Joined: 30 Dec 2004
Posts: 1179
Location: Tilburg - Netherlands

netherlands.gif
PostPosted: Mon Dec 03, 2012 11:00 pm    Post subject: Great!!! Reply with quote

Great work, thanks for sharing!!!

Have fun
Ben Zijlstra
Back to top
View user's profile Visit poster's website
Dave

Bascom Member



Joined: 05 Feb 2005
Posts: 314
Location: OR

usa.gif
PostPosted: Tue Dec 04, 2012 4:53 am    Post subject: Reply with quote

Thanks Ben,
I appreciate those kind words.
Back to top
View user's profile
hgrueneis

Bascom Member



Joined: 04 Apr 2009
Posts: 902
Location: A-4786 Brunnenthal

austria.gif
PostPosted: Tue Dec 04, 2012 5:29 pm    Post subject: Reply with quote

Cool and great is not enough.
The best use and application I have ever seen for a scope.
Thank you for posting and sharing.
How many cups of coffee was that?
Thanks again
Hubert
Back to top
View user's profile
Dave

Bascom Member



Joined: 05 Feb 2005
Posts: 314
Location: OR

usa.gif
PostPosted: Tue Dec 04, 2012 8:20 pm    Post subject: Reply with quote

Thanks Hubert,
days=6
coffee=2
cups=days*coffee

I've even stated dreaming in code. I may need professional help. Confused
Back to top
View user's profile
Dave

Bascom Member



Joined: 05 Feb 2005
Posts: 314
Location: OR

usa.gif
PostPosted: Fri Dec 21, 2012 11:31 pm    Post subject: Reply with quote

The latest progress:
Back to top
View user's profile
Dave

Bascom Member



Joined: 05 Feb 2005
Posts: 314
Location: OR

usa.gif
PostPosted: Fri Dec 21, 2012 11:49 pm    Post subject: Reply with quote

To create graphics I used a free icon editor called "Greenfish Icon Editor Pro".

Make a graphic using just black pixels and save as XPM file.

Open the XPM file with xpm2data.exe and press the "Convert XPM file" button.
A inc file is created and the file path is put in the windows clipboard. Paste the
new file path into the bascom source.

The converter is written in Real Studio if anyone would like the source send me an email,
I'm happy to share.

Dave
Back to top
View user's profile
Dave

Bascom Member



Joined: 05 Feb 2005
Posts: 314
Location: OR

usa.gif
PostPosted: Sun Dec 23, 2012 1:48 am    Post subject: Reply with quote

In the previous post I wanted to attach one more image but could not. For completeness here it is.

The data is length and x,y points for each pixel to draw an graphic image.


Dave
Back to top
View user's profile
albertsm

Administrator



Joined: 09 Apr 2004
Posts: 5922
Location: Holland

blank.gif
PostPosted: Mon Dec 24, 2012 1:42 pm    Post subject: Reply with quote

Dave,

you extended the looks of the clock a great deal with this added digital time date info. By now i am sure you only dream in dots.
with some effort the code could be used to display the info on a TV as well. This makes a pretty unique clock, especial when you have an antique big scope.
And with so little electronic parts.
Thanks for uploading the update and for your offer to share the converter tool. Please send me a copy(zipped).

_________________
Mark
Back to top
View user's profile Visit poster's website
Dave

Bascom Member



Joined: 05 Feb 2005
Posts: 314
Location: OR

usa.gif
PostPosted: Mon Dec 24, 2012 5:29 pm    Post subject: Reply with quote

Mark,
I'm happy to send you the source.

Do I send it to support or what?

Do you have Real Studio?
Dave
Back to top
View user's profile
Dave

Bascom Member



Joined: 05 Feb 2005
Posts: 314
Location: OR

usa.gif
PostPosted: Tue Dec 25, 2012 1:16 am    Post subject: Reply with quote

Mark,

The RealStudio project file is not a txt file type. That's why you need to have RealStudio. If you want use with some other compiler it would be easier to start over. The xpm file is very easy to take apart. Also I could cut and past the part the the code that does the translation and send that if you like.

haha No - not dreaming in pixels. That's the point of the tools above. A font of any size can be made in about one minute (just one char. that is).

This work is very rough and it can only handle one color. But the xpm file format does encode colors so if someone needed them this is a good why to get there.

Dave
Back to top
View user's profile
techknight

Bascom Member



Joined: 21 Apr 2008
Posts: 231

usa.gif
PostPosted: Fri Jan 10, 2014 1:50 am    Post subject: Reply with quote

I know this is an old thread, but how hard would it be to make it work with a DS1307?
Back to top
View user's profile
Display posts from previous:   
Post new topic   Reply to topic    www.mcselec.com Forum Index -> BASCOM Project Blog All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum