blackbox/main.c

Mon, 14 Nov 2011 21:15:11 +0100

author
Malte Bayer <mbayer@neo-soft.org>
date
Mon, 14 Nov 2011 21:15:11 +0100
changeset 2
6c59b4293fa9
parent 0
9b7de464f0ea
child 3
1a0ef40ef458
permissions
-rw-r--r--

finished: rails short circuit check

#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 "driver/rs232.h"
#include "driver/adc.h"

#include "main.h"
#include "lowlevel.h"

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);
}

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) {
        // check for short circuit on the rails
        check_rails_shortcut();

        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;
        }


    } // main loop end
};

mercurial