// RS-422 simulator for AIDC Generator Control Unit
// sjm 07 Feb 2018

// Requirements:
// 9600 Baud, 1 start bit, 1 stop bit, 8 bit data, no parity
// Frame repetition rate 500ms
// Frame format: <STX> <B2> <B1> <CHKSUM> < ETX> ..... <STX> <B2> <B1> <CHKSUM> <ETX> .....
// STX = 02, ETX = 03, Checksum does not include STX or ETX
// Byte B1:
// 0 = generator fail
// 1 = GCU fail
// 2 = GLC(G) fail
// 3 = AC BUS (G) de-energized
// 4 = GPU fail
// 5 = GPC fail
// 6 = GLC (T) fail
// 7 = GLC de-energized
// Byte B2:
// 0 = XP (G) fail
// 1 = XP (T) fail
// 2 = Generator on/off (line)
// 3 = Overcurrent/differential protection
// 4 = AC BUS (T) de-energized
// 5-7 = spare
// For each bit 0 = no fail, 1 = fail

#include <xc.h>
#include <stdlib.h>
#include <stdio.h>

// Window - PIC Memory Views - Configuration Bits
#pragma config OSC = HS     // external crystal
#pragma config PWRT = OFF   // power up timer
#pragma config WDT = OFF    // disable watchdog timer
#pragma config PBADEN = OFF // disable analog inputs on reset
#pragma config STVREN = ON  // stack overflow causes reset
#pragma config CP0 = OFF    // not code protected
#pragma config CPD = OFF    // EEPROM not write protected
#pragma config WRT0 = OFF   // not write protected
#pragma config WRTC = OFF   // config bits not write protected
#pragma config EBTR0 = OFF  // no table read protection
#pragma config EBTRB = OFF  // boot block not protected
#pragma config LVP = OFF    // use RB5 as I/O

#define _XTAL_FREQ  20000000
#define DIPSW0  PORTCbits.RC1   // pin 9
#define DIPSW1  PORTCbits.RC0   // pin 8
#define DIPSW2  PORTAbits.RA5   // pin 4
#define DIPSW3  PORTAbits.RA4   // pin 3
#define DIPSW4  PORTAbits.RA3   // pin 2
#define DIPSW5  PORTAbits.RA2   // pin 1
#define DIPSW6  PORTAbits.RA1   // pin 28
#define DIPSW7  PORTAbits.RA0   // pin 27
#define DIPSW8  PORTBbits.RB3   // pin 21
#define DIPSW9  PORTBbits.RB2   // pin 20
#define DIPSW10 PORTBbits.RB1   // pin 19
#define DIPSW11 PORTBbits.RB0   // pin 18
#define DIPSW12 PORTBbits.RB4   // pin 22
#define DIPSW13 PORTBbits.RB5   // pin 23
#define DIPSW14 PORTCbits.RC3   // pin 11
#define DIPSW15 PORTCbits.RC2   // pin 10
#define TERM    PORTCbits.RC5   // pin 13
#define UART_TX PORTCbits.RC6   // pin 14

/************************************************************/
void UART_Write(unsigned char ch)
{
	TXREG = ch;
	while (TXSTAbits.TRMT == 0) {}
}

/************************************************************/
void main(void)
{
    unsigned char ByteB1;
    unsigned char ByteB2;
    unsigned char i;

    // Initialise I/O pins
    TRISA = 0xFF;   // Set RA to be all inputs
    TRISB = 0xFF;   // Set RB to be all inputs
    TRISC = 0x9F;   // Set RC to be all inputs, except for UART Tx and TERM
    ADCON1=0x0F;    // Disable ADC pins
    CMCON=0x07;     // Disable comparators
    TERM = 1;       // Set RS422 termination resistor to 120 ohm (0 to disable)

    // Initialise UART
    // 9600 baud @ 20MHz, SPBRG=520, which means SPBRGH:SPBRG=2*256+8
    // This gives an actual baud = 9596 or a -0.03% error
    SPBRGH = 2;
    SPBRG = 8;
    BAUDCONbits.BRG16 = 1;  // 16 bit baud rate generator

    // We could also use the 8 bit baud rate generator (9615 baud = +0.16% error)
    //SPBRG = 129;
    //BAUDCONbits.BRG16 = 0;  // 8 bit baud rate generator

    TXSTAbits.SYNC = 0;	// async mode
    TXSTAbits.BRGH = 1;	// high speed
    RCSTAbits.SPEN = 1;	// enable serial port on IO pins
    TXSTAbits.TXEN = 1;	// enable transmitter

    while (1)
    {
        ByteB1 = (DIPSW7 << 7) | (DIPSW6 << 6) | (DIPSW5 << 5) | (DIPSW4 << 4) |
                 (DIPSW3 << 3) | (DIPSW2 << 2) | (DIPSW1 << 1) | DIPSW0;

        ByteB2 = (DIPSW15 << 7) | (DIPSW14 << 6) | (DIPSW13 << 5) | (DIPSW12 << 4) |
                 (DIPSW11 << 3) | (DIPSW10 << 2) | (DIPSW9 << 1) | DIPSW8;

        UART_Write(0x02);   // STX
        UART_Write(ByteB2);
        UART_Write(ByteB1);
        UART_Write(ByteB2 + ByteB1);    // Checksum
        UART_Write(0x03);   // ETX

        // delay for a loop period of 500ms - simpler than a timer interrupt
        // values have been adjusted to give 500.014ms
        for (i=16; i>0; i--)
            __delay_ms(30);
        __delay_ms(14);     // 14=499.70ms
        __delay_us(295);
    }
}
