/*
	speaker.c

   Sample program that uses PRT0 to drive the speaker port at the specified 
	frequency.

	Type tone(frequency, milliseconds) within the watch window to drive the
	speaker port at another frequency for the specified number of milliseconds.

	Alternatively, the function up_beep(int millisecond) can be called to
	generate a tone at 640 hertz.
*/

#use "default.h"
#use "cplc.lib"

#if (BOARD_TYPE!=Z104ISA)
#fatal "This program only runs on the Z104 or ZISA boards."
#endif

int beepcount;

void timer0init(unsigned count);    // initialize prt0
void tone(unsigned int frequency, unsigned int millisecond);

main()
{
unsigned int i;

    uplc_init();              // need this if you want to use up_beep();
    for( i = 8000; i>=100; i = i/2)
    {
         tone(i, 1000);             // i hertz for 1 second
         while(beepcount);          // wait for tone to finish
    }
    while(1) runwatch();

}

// Generate a tone at the specified frequency and duration.
void tone( unsigned int frequency, unsigned int millisecond)
{
      unsigned int temp;

      temp = (unsigned int)((30L*sysclock())/ frequency);
                  // compute the timer load value
                  // temp = (1200 * sysclock()) / ( 2 * 20 * frequency)
      beepcount = (frequency/500.0)*millisecond;
                  // compute the duration of the beep in millisecond
                  // beepcount = (2*frequency) * (millisecond/1000)
      timer0init( temp);
}


// Initialize PRT0 for load value to generate the tone
void timer0init(unsigned count)
{
                                    // disable counting and interrupts
    IRES(TCR, 0);
    IRES(TCR, 4);
    IRES(TCR, 6);
    outport(RLDR0L, count);
    outport(RLDR0H, count >> 8);    // set reload reg
    outport(TMDR0L, count);
    outport(TMDR0H, count >> 8);    // set data reg
    ISET(TCR, 0);
    ISET(TCR, 4);                   // enable interrupts
}

// timer0 interrupt service routine

#INT_VEC PRT0_VEC timer0int

#asm root
timer0int::
   push     af
   push     hl
   push     de
   push     bc

   in0      a,(TCR)
   in0      a,(TMDR0L)        ; reset timer


   ld       hl,(beepcount)
   ld       a,l
   or       h
   jr       nz, cycle_out
   in0      a, (TCR)
   res      0, a              ; turn off timer if tone is finished
   res      4, a
   out0     (TCR), a
   jr       the_end              
cycle_out:

   dec      hl
   ld       (beepcount),hl
   ld       bc, SPEAKER       ; least of beep count is sent to speaker
   out      (c),l             ; output to beeper
   
the_end:
   pop      bc
   pop      de
   pop      hl
   pop      af
   ei
   ret

#endasm

