#include <avr/io.h>
 
#include <avr/interrupt.h>
 
 
 
#include "mytypes.h"
 
#include "rs232.h"
 
#include "pins.h"
 
 
 
//if want Log than comment next string
 
#undef LOGENABLE
 
 
 
#define BAUD115200 115200
 
#define BAUD256000 256000
 
#define UBRR115200 (((F_CPU/16)/BAUD115200)-1)
 
#define UBRR256000 (((F_CPU/16)/BAUD256000)-1)
 
 
 
//Registers for 16550 emulation:
 
 
 
//Divisor Latch LSB
 
static UBYTE rs232_DLL;
 
//Divisor Latch MSB
 
static UBYTE rs232_DLM;
 
//Interrupt Enable
 
static UBYTE rs232_IER;
 
//Interrupt Identification
 
static UBYTE rs232_ISR;
 
//FIFO Control
 
static UBYTE rs232_FCR;
 
//Line Control
 
static UBYTE rs232_LCR;
 
//Modem Control
 
static UBYTE rs232_MCR;
 
//Line Status
 
static UBYTE rs232_LSR;
 
//Modem Status
 
static UBYTE rs232_MSR;
 
//Scratch Pad
 
static UBYTE rs232_SCR;
 
//Fifo In
 
static UBYTE rs232_FI[16];
 
static UBYTE rs232_FI_start;
 
static UBYTE rs232_FI_end;
 
//Fifo Out
 
static UBYTE rs232_FO[16];
 
static UBYTE rs232_FO_start;
 
static UBYTE rs232_FO_end;
 
 
 
void rs232_init(void)
 
{
 
        // Set baud rate
 
        UBRR1H = (UBYTE)(UBRR115200>>8);
 
        UBRR1L = (UBYTE)UBRR115200;
 
        // Clear reg
 
        UCSR1A = 0;
 
        // Enable receiver and transmitter
 
        UCSR1B = _BV(RXEN)|_BV(TXEN);
 
        // Set frame format: 8data, 1stop bit
 
        UCSR1C = _BV(USBS)|_BV(UCSZ0)|_BV(UCSZ1);
 
 
 
        //Set default values:
 
        rs232_DLM = 0;
 
        rs232_DLL = 0x01;
 
        rs232_IER = 0;
 
        rs232_FCR = 0x01; //FIFO always enable
 
        rs232_ISR = 0x01;
 
        rs232_LCR = 0;
 
        rs232_MCR = 0;
 
        rs232_LSR = 0x60;
 
        rs232_MSR = 0xA0; //DSR=CD=1, RI=0
 
        rs232_SCR = 0xFF;
 
        rs232_FI_start = rs232_FI_end = 0;
 
        rs232_FO_start = rs232_FO_end = 0;
 
}
 
 
 
void rs232_transmit( UBYTE data )
 
{
 
        // Wait for empty transmit buffer
 
        while ( !( UCSR1A & (1<<UDRE)) );
 
        // Put data into buffer, sends the data
 
        UDR1 = data;
 
}
 
 
 
//#ifdef LOGENABLE
 
void to_log(char* ptr)
 
{
 
        while( (*ptr)!=0 )
 
        {
 
                rs232_transmit(*ptr);
 
                ptr++;
 
        }
 
}
 
//#endif
 
 
 
 
 
//after DLL or DLM changing
 
void rs232_set_baud(void)
 
{
 
        if ( rs232_DLM | rs232_DLL )
 
        {
 
                if( (rs232_DLM&0x80)!=0 )
 
                {
 
                        //AVR mode - direct load UBRR
 
                        UBRR1H = 0x7F&rs232_DLM;
 
                        UBRR1L = rs232_DLL;
 
                }
 
                else
 
                {
 
                        //default mode - like 16550
 
                        ULONG i = BAUD115200/ ((((UWORD)rs232_DLM)<<8) + rs232_DLL);
 
                        UWORD rate = ((F_CPU/16)/i)-1;
 
                        // Set baud rate
 
                        UBRR1H = (UBYTE)(rate>>8);
 
                        UBRR1L = (UBYTE)rate;
 
                }
 
        }
 
        else
 
        {
 
                // If( ( rs232_DLM==0 ) && ( rs232_DLL==0 ) )
 
                // set rate to 256000 baud
 
                UBRR1H = (UBYTE)(UBRR256000>>8);
 
                UBRR1L = (UBYTE)UBRR256000;
 
        }
 
}
 
 
 
//after LCR changing
 
void rs232_set_format(void)
 
{
 
        //set word length and stopbits
 
        UBYTE format = ((rs232_LCR&0x07)<<1);
 
 
 
        //set parity (only "No parity","Odd","Even" supported)
 
        switch( rs232_LCR&0x38 )
 
        {
 
                case 0x08:
 
                        //odd parity
 
                        format |= _BV(UPM0)|_BV(UPM1);
 
                        break;
 
                case 0x18:
 
                        //even parity
 
                        format |= _BV(UPM1);
 
                        break;
 
                //default - parity not used
 
        }
 
 
 
        UCSR1C = format;
 
}
 
 
 
void rs232_zx_write(UBYTE index, UBYTE data)
 
{
 
#ifdef LOGENABLE
 
        char log_write[] = "A..D..W\r\n";
 
        log_write[1] = ((index >> 4) <= 9 )?'0'+(index >> 4):'A'+((index >> 4)-10);
 
        log_write[2] = ((index & 0x0F) <= 9 )?'0'+(index & 0x0F):'A'+(index & 0x0F)-10;
 
        log_write[4] = ((data >> 4) <= 9 )?'0'+(data >> 4):'A'+((data >> 4)-10);
 
        log_write[5] = ((data & 0x0F) <= 9 )?'0'+(data & 0x0F):'A'+((data & 0x0F)-10);
 
        to_log(log_write);
 
#endif
 
        switch( index )
 
        {
 
        case 0:
 
                if ( rs232_LCR & 0x80 )
 
                {
 
                        rs232_DLL = data;
 
                        rs232_set_baud();
 
                }
 
                else
 
                {
 
                        //place byte to fifo out
 
                        if ( ( rs232_FO_end != rs232_FO_start ) ||
 
                             ( rs232_LSR&0x20 ) )
 
                        {
 
                                rs232_FO[rs232_FO_end] = data;
 
                                rs232_FO_end = (rs232_FO_end + 1) & 0x0F;
 
 
 
                                //clear fifo empty flag
 
                                rs232_LSR &= ~(0x60);
 
                        }
 
                        else
 
                        {
 
                                //fifo overload
 
                        }
 
                }
 
                break;
 
 
 
        case 1:
 
                if ( rs232_LCR & 0x80 )
 
                {
 
                        //write to DLM
 
                        rs232_DLM = data;
 
                        rs232_set_baud();
 
                }
 
                else
 
                {
 
                        //bit 7-4 not used and set to '0'
 
                        rs232_IER = data & 0x0F;
 
                }
 
                break;
 
 
 
        case 2:
 
                if( data&1 )
 
                {
 
                        //FIFO always enable
 
                        if( data&(1<<1) )
 
                        {
 
                                //receive FIFO reset
 
                                rs232_FI_start = rs232_FI_end = 0;
 
                                //set empty FIFO flag and clear overrun flag
 
                                rs232_LSR &= ~(0x03);
 
                        }
 
                        if( data&(1<<2) )
 
                        {
 
                                //tramsmit FIFO reset
 
                                rs232_FO_start = rs232_FO_end = 0;
 
                                //set fifo is empty flag
 
                                rs232_LSR |= 0x60;
 
                        }
 
                        rs232_FCR = data&0xC9;
 
                }
 
                break;
 
 
 
        case 3:
 
                rs232_LCR = data;
 
                rs232_set_format();
 
                break;
 
 
 
        case 4:
 
                //bit 7-5 not used and set to '0'
 
                rs232_MCR = data & 0x1F;
 
                if ( data&(1<<1) )
 
                {
 
                        //clear RTS
 
                        RS232RTS_PORT &= ~(_BV(RS232RTS));
 
                }
 
                else
 
                {
 
                        //set RTS
 
                        RS232RTS_PORT |= _BV(RS232RTS);
 
                }
 
                break;
 
 
 
        case 5:
 
                //rs232_LSR = data;
 
                break;
 
 
 
        case 6:
 
                //rs232_MSR = data;
 
                break;
 
 
 
        case 7:
 
                rs232_SCR = data;
 
                break;
 
        }
 
}
 
 
 
UBYTE rs232_zx_read(UBYTE index)
 
{
 
        UBYTE data = 0;
 
        switch( index )
 
        {
 
        case 0:
 
                if ( rs232_LCR & 0x80 )
 
                {
 
                        data = rs232_DLL;
 
                }
 
                else
 
                {
 
                        //get byte from fifo in
 
                        if ( rs232_LSR&0x01 )
 
                        {
 
                                data = rs232_FI[rs232_FI_start];
 
                                rs232_FI_start = ( rs232_FI_start + 1 ) & 0x0F;
 
 
 
                                if( rs232_FI_start == rs232_FI_end )
 
                                {
 
                                        //set empty FIFO flag
 
                                        rs232_LSR &= ~(0x01);
 
                                }
 
                        }
 
                }
 
                break;
 
 
 
        case 1:
 
                if ( rs232_LCR & 0x80 )
 
                {
 
                        data = rs232_DLM;
 
                }
 
                else
 
                {
 
                        data = rs232_IER;
 
                }
 
                break;
 
 
 
        case 2:
 
                data = rs232_ISR;
 
                break;
 
 
 
        case 3:
 
                data = rs232_LCR;
 
                break;
 
 
 
        case 4:
 
                data = rs232_MCR;
 
                break;
 
 
 
        case 5:
 
                data = rs232_LSR;
 
                break;
 
 
 
        case 6:
 
                //DSR=CD=1
 
                data = rs232_MSR;
 
                //clear flags
 
                rs232_MSR &= 0xF0;
 
                break;
 
 
 
        case 7:
 
                data = rs232_SCR;
 
                break;
 
        }
 
#ifdef LOGENABLE
 
        static UBYTE last = 0;
 
        if ( last!=index )
 
        {
 
                char log_read[] = "A..D..R\r\n";
 
                log_read[1] = ((index >> 4) <= 9 )?'0'+(index >> 4):'A'+((index >> 4)-10);
 
                log_read[2] = ((index & 0x0F) <= 9 )?'0'+(index & 0x0F):'A'+(index & 0x0F)-10;
 
                log_read[4] = ((data >> 4) <= 9 )?'0'+(data >> 4):'A'+((data >> 4)-10);
 
                log_read[5] = ((data & 0x0F) <= 9 )?'0'+(data & 0x0F):'A'+((data & 0x0F)-10);
 
                to_log(log_read);
 
                last = index;
 
        }
 
#endif
 
        return data;
 
}
 
 
 
void rs232_task(void)
 
{
 
        //send data
 
        if( (rs232_LSR&0x20)==0 )
 
        {
 
                if ( UCSR1A&_BV(UDRE) )
 
                {
 
                        UDR1 = rs232_FO[rs232_FO_start];
 
                        rs232_FO_start = (rs232_FO_start+1)&0x0F;
 
 
 
                        if( rs232_FO_start == rs232_FO_end )
 
                        {
 
                                //set fifo is empty flag
 
                                rs232_LSR |= 0x60;
 
                        }
 
                }
 
        }
 
 
 
        //receive data
 
        if( UCSR1A&_BV(RXC) )
 
        {
 
                BYTE b = UDR1;
 
                if( (rs232_FI_end == rs232_FI_start) &&
 
                    (rs232_LSR&0x01) )
 
                {
 
                        //set overrun flag
 
                        rs232_LSR|=0x02;
 
                }
 
                else
 
                {
 
                        //receive data
 
                        rs232_FI[rs232_FI_end] = b;
 
                        rs232_FI_end = (rs232_FI_end+1)&0x0F;
 
                        //set data received flag
 
                        rs232_LSR |= 0x01;
 
                }
 
        }
 
 
 
        //statuses
 
        if( UCSR1A&_BV(FE) )
 
        {
 
                //frame error
 
                rs232_LSR |= 0x08;
 
        }
 
        else
 
        {
 
                rs232_LSR &= ~(0x08);
 
        }
 
 
 
        if( UCSR1A&_BV(UPE) )
 
        {
 
                //parity error
 
                rs232_LSR |= 0x04;
 
        }
 
        else
 
        {
 
                rs232_LSR &= ~(0x04);
 
        }
 
 
 
        if( RS232CTS_PIN&_BV(RS232CTS) )
 
        {
 
                //CTS clear
 
                if( (rs232_MSR&0x10)!=0 )
 
                {
 
#ifdef LOGENABLE
 
                        to_log("CTS\r\n");
 
#endif
 
                        //CTS changed - set flag
 
                        rs232_MSR |= 0x01;
 
                }
 
                rs232_MSR &= ~(0x10);
 
        }
 
        else
 
        {
 
                //CTS set
 
                if( (rs232_MSR&0x10)==0 )
 
                {
 
#ifdef LOGENABLE
 
                        to_log("CTS\r\n");
 
#endif
 
                        //CTS changed - set flag
 
                        rs232_MSR |= 0x01;
 
                }
 
                rs232_MSR |= 0x10;
 
        }
 
}