blackbox/main.c

Mon, 14 Nov 2011 20:31:32 +0100

author
Malte Bayer <mbayer@neo-soft.org>
date
Mon, 14 Nov 2011 20:31:32 +0100
changeset 0
9b7de464f0ea
child 2
6c59b4293fa9
permissions
-rw-r--r--

initial commit - controller1 working

#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/eeprom.h>
#include <stdlib.h>
#include <stdint.h>
#include <avr/pgmspace.h>
#include <util/delay.h>

#include "main.h"

#include "driver/rs232.h"
#include "driver/adc.h"

#include "lowlevel.h"

//#include "driver/manchester.h"

/*
// Hardware config
#define LAP_COUNTER_PORT        PORTB
#define LAP_COUNTER             PB2

#define MODUL_PORT              PORTD
#define MODUL_ST4               PD5
#define MODUL_ST6               PD6

#define I2C_PORT                PORTC
#define I2C_SDA                 PC0
#define I2C_SCL                 PC1


#define SW_PACECAR_PORT         PORTC
#define SW_START_PORT           PORTB
#define SW_TANK_PORT            PORTB
#define SW_PACECAR              PC6
#define SW_TANK                 PB0
#define SW_START                PB1

#define SPEAKER_PORT            PORTD
#define SPEAKER                 PD7

*/


void init_hardware(void) {
    RS232_init(); // initialize RS485 interface
    RS232_puts_p(PSTR("CARRERA beta loading\n"));

    initADC();

    // set LED output
    DDR(LED1_PORT) |= _BV(LED1);
    DDR(LED2_PORT) |= _BV(LED2);
    DDR(LED3_PORT) |= _BV(LED3);
    DDR(LED4_PORT) |= _BV(LED4);
    DDR(LED5_PORT) |= _BV(LED5);

    // set Controller Input Pull-UPs
    CONTROLLER_PORT |= (_BV(CONTROLLER1_SW) | _BV(CONTROLLER2_SW) | _BV(CONTROLLER3_SW) | _BV(CONTROLLER4_SW));

    // switch pull-ups
    SW_FUEL_PORT |= _BV(SW_FUEL);

    //RAIL_DETECT_PORT |= _BV(RAIL_DETECT); // enable internal pull-up
    DDR(RAIL_POWER_PORT) |= _BV(RAIL_POWER);


    LED(1, 1); _delay_ms(50);
    LED(2, 1); _delay_ms(50);
    LED(3, 1); _delay_ms(50);
    LED(4, 1); _delay_ms(50);
    LED(5, 1); _delay_ms(50);
    LED(1, 0); _delay_ms(50);
    LED(2, 0); _delay_ms(50);
    LED(3, 0); _delay_ms(50);
    LED(4, 0); _delay_ms(50);
    LED(5, 0); _delay_ms(50);

    //TCCR0 = (1<<CS01); //divide by 8


    // setup data bit timer
    TCCR2 = (1<<CS21); //divide by 8
    TCCR2 |= (1<<WGM21); // set compare match
    OCR2 = TIMER2_50US;
    TIMSK |= 1<<OCIE2; //enable timer2 interrupt

    // setup data packet timer
    //TCCR1A = (1<<COM1A1);
    TCCR1B = (1<<CS11); //divide by 8
    TCCR1B |= (1<<WGM12); // set compare match
    //TCCR1B = (1<<CS11) | (1<<CS10); //divide by 64
    //TCNT1 = TIMER_7500NS;
    OCR1A = TIMER1_7500NS;
    TIMSK |= 1<<OCIE1A; //enable timer1 interrupt

    RS232_puts_p(PSTR("INIT OK\n"));

}



volatile uint8_t datalen = 0;
char data[10]; // 8 bytes data buffer + string termination

static char buffer[RS232_BUFSIZE+1];
static uint8_t buffer_len;


// USART0 RX interrupt
ISR ( USART_RXC_vect ) {
    char c = UDR;

    // check for buffer overflow
    if (buffer_len==sizeof(buffer)) {
        buffer_len=0;
        if (c == 27) {
            // escape sequence, store to empty buffer
            buffer[buffer_len++] = c;
        }
    }  else {
        // collect characters until end of line
        if (c == 27) {
            // escape sequence, clear buffer
            buffer_len = 0;
            buffer[buffer_len++] = c;
        } else if ( (c==0xff) && (buffer_len > 3) ) {
            buffer[buffer_len]=0;

            // packet end received, parse the received packet

            // wait for the next packet
            buffer_len=0;
        } else {
            buffer[buffer_len++]=c;
        }
    }
}


volatile uint16_t transmit_buffer;
volatile uint16_t transmit_buffer_queue;
volatile uint8_t  transmit_len;
volatile uint8_t  transmit_len_next;
volatile uint8_t  transmit_len_queue;
ISR ( TIMER2_COMP_vect ) {
    //OCR2 = TIMER2_50US; // make sure that timer2 is 50µs !!!
    // data packet timer 100µs pro bit...
    if (transmit_len >= 0xFE) {
        if (transmit_len != 0xFF) {
            RAIL_POWER_PORT |= _BV(RAIL_POWER); // end of transmission
            transmit_len = 0xFF;
            transmit_buffer = transmit_buffer_queue;
            transmit_buffer_queue = 0;
            transmit_len_next = transmit_len_queue;
        }
    } else {
        uint16_t bit = (1<<(transmit_len & 0b01111111));
        uint16_t clock;
        if ((transmit_len & 0b10000000) == 0) clock = 0; else clock = 0xffff;
        if ( ((transmit_buffer ^ clock) & bit) != 0 )
            RAIL_POWER_PORT |= _BV(RAIL_POWER); else
            RAIL_POWER_PORT &= ~_BV(RAIL_POWER);
        if ( (transmit_len & 0b10000000) == 0 ) {
            // block 0
            //if (transmit_len == 0) transmit_len = 0xFF; else transmit_len |= 0b10000000; // set clock
            transmit_len |= 0b10000000; // set clock
        } else {
            // block 1, output the current bit
            transmit_len &= 0b01111111; // reset clock
            //if (transmit_len != 0) transmit_len--; // next bit
            if (transmit_len == 0) transmit_len = 0xFE; else transmit_len--; // next bit
        }
    }
}

int insert_queue(uint16_t tmp, uint8_t len) {
    if (transmit_buffer_queue == 0) {
        transmit_buffer_queue = tmp;
        transmit_len_queue = len;
        return 1;
    }
    return 0;
}


int do_controller(uint8_t controller) {
    // read controller X speed & encode controller data packet
    uint16_t tmp;
    switch (controller) {
        case 0: tmp = getADC(CONTROLLER1_SPEED) / CONTROLLER_DIVISOR; break;
        case 1: tmp = getADC(CONTROLLER2_SPEED) / CONTROLLER_DIVISOR; break;
        case 2: tmp = getADC(CONTROLLER3_SPEED) / CONTROLLER_DIVISOR; break;
        case 3: tmp = getADC(CONTROLLER4_SPEED) / CONTROLLER_DIVISOR; break;
        case 4: tmp = 0; break; // todo regler 5
        case 5: tmp = 0; break; // todo regler 6
    }
    tmp =  0b1000000000 | (controller << 6) | ((tmp & 0xF) << 1);
    if ( (PIN(SW_FUEL_PORT) & _BV(SW_FUEL)) != 0) tmp |= 1; // benzinstand aktiv - tankmodusschalter
    if ( (PIN(CONTROLLER_PORT) & _BV(CONTROLLER1_SW)) != 0) {
        tmp |= (1<<5);
        LED(controller+1, 0);
    } else LED(controller+1, 1);

    return insert_queue(tmp, 9);
}

unsigned char mirror( unsigned char n ) {
    // mirror all 8 bits
    n = ((n >> 1) & 0x55) | ((n << 1) & 0xaa);
    n = ((n >> 2) & 0x33) | ((n << 2) & 0xcc);
    n = ((n >> 4) & 0x0f) | ((n << 4) & 0xf0);
    return n;
}


int do_program(uint8_t controller, uint8_t command, uint8_t parameter) {
    // send program data packet
    uint16_t tmp;
    tmp = 0b1000000000000 | (mirror(parameter) << 4) | mirror(command)| (mirror(controller) >> 5);

    return insert_queue(tmp, 12);
}

int do_active(void) {
    // send controller active data packet
    uint16_t tmp = 0b10000000;
    if ((getADC(CONTROLLER1_SPEED) / CONTROLLER_DIVISOR) > 0) tmp |= 0b11000001;
    if ((getADC(CONTROLLER2_SPEED) / CONTROLLER_DIVISOR) > 0) tmp |= 0b10100001;
    if ((getADC(CONTROLLER3_SPEED) / CONTROLLER_DIVISOR) > 0) tmp |= 0b10010001;
    if ((getADC(CONTROLLER4_SPEED) / CONTROLLER_DIVISOR) > 0) tmp |= 0b10001001;
    // todo: regler 5 und 6

    return insert_queue(tmp, 7);
}

int do_pace_ghost(void) {
    // send ghost and pacecar data packet
    // todo: at the moment, both disabled!
    uint16_t tmp = 0b1111100000;
    if ( (PIN(SW_FUEL_PORT) & _BV(SW_FUEL)) != 0) tmp |= 1; // benzinstand aktiv - tankmodusschalter
    // todo: PC, NH, TK, (KFR, FR)

    return insert_queue(tmp, 9);
}

/*
TODO: DIE TIMER1 ISR DARF DIE ADC NICHT ABFRAGEN, NICHTMAL PAKETE BAUEN, NUR TRIGGERN
DIE PAKETE MÜSSEN IN DER MAIN UNIT GEBAUT WERDEN UND IN EINE QUEUE GESCHOBEN WERDEN
EINES VORBAUEN IN Q+1, DIE TIMER2 ISR MUSS DANN Q = Q+1 und Q+1 = 0 SETZEN, ERST DANN DARF
NEUES PAKET IN Q+1 EINGEFÜGT WERDEN
*/


ISR ( TIMER1_COMPA_vect ) {
    //OCR2 = 0xFF; // make sure that timer2 is synced to timer1, give enough cycles to prepare
    LED(4,2);
    // trigger packet transfer:
    transmit_len = transmit_len_next;
    
    // here is some more time to do something else...
}


int main(void)
{

    unsigned char s[30];
    uint16_t tmp;
    uint8_t  packet_index = 1;


    init_hardware();

    itoa(TIMER2_50US, s, 10);
    RS232_puts(s);

    // switch on rails power
    RAIL_POWER_PORT |= _BV(RAIL_POWER);

    while (1) {
        //RS232_putc(PIN(RAIL_DETECT_PORT));

        // check for short circuit on the rails
        if ((PIN(RAIL_DETECT_PORT) & _BV(RAIL_DETECT)) == 0) {
            _delay_ms(1);
            if ((PIN(RAIL_DETECT_PORT) & _BV(RAIL_DETECT)) == 0) {
                cli(); // disable ALL Interrupts
                RAIL_POWER_PORT &= ~_BV(RAIL_POWER); // disable rails power
                RS232_puts_p(PSTR("!!! SHORT CIRCUIT ON RAILS, POWERED OFF !!!\n"));
                while (1) {
                    LED(1, 0);
                    _delay_ms(100);
                    LED(1, 1);
                    _delay_ms(100);
                }
            }
        }




    switch (packet_index) {
        case 1:
            if (do_program(7, 19, 0)) packet_index++; // reset
            //do_program(7, 16, 3); // led an startampel
            //do_program(0, 4, 0); //
            break;
        case 2:
            if (do_pace_ghost()) packet_index++;
            break;
        case 3:
            if (do_active()) packet_index++;
            break;
        case 4:
            if (do_controller(0)) packet_index++;
            break;
        case 5:
            if (do_controller(4)) packet_index++;
            break;
        case 6:
            if (do_controller(1)) packet_index++;
            break;
        case 7:
            if (do_controller(5)) packet_index++;
            break;
        case 8:
            if (do_controller(2)) packet_index++;
            break;
        case 9:
            if (do_active()) packet_index++;
            break;
        case 10:
            if (do_controller(3)) packet_index = 1;
            // last packet, so reset packet index
            break;
    }




/*
        do_controller(0);
        itoa (transmit_len_queue, s, 10);
        RS232_puts(s);
        RS232_putc(' ');
        itoa (transmit_buffer_queue, s, 2);
        RS232_puts(s);
        
        RS232_putc('\n');
*/
/*
        itoa (tmp, s, 2);
        RS232_puts(s);
        RS232_putc('\n');
*/


    } // main loop end
};

mercurial