19,7 → 19,7 |
* * |
* * |
* Credits to: * |
* Holger Buss & Ingo Busker from mikrokopter.de for the MK project * |
* Holger Buss & Ingo Busker from mikrokopter.de for the MK project + SVN * |
* Gregor "killagreg" Stobrawa for making the MK code readable * |
* Klaus "akku" Buettner for the hardware * |
* Manuel "KeyOz" Schrape for explaining the MK protocol to me * |
33,6 → 33,9 |
#include "max7456_software_spi.h" |
#include "usart1.h" |
#include "osd_helpers.h" |
#include "config.h" |
#include "spi.h" |
#include "buttons.h" |
|
/* TODO: |
* - verifiy correctness of values |
76,10 → 79,6 |
char* stats_item_pointers[] PROGMEM = {stats_item_0, stats_item_1, stats_item_2, |
stats_item_3, stats_item_4, stats_item_5, stats_item_6, stats_item_7}; |
|
// store more fixed strings in progmen |
char ON[] PROGMEM = "ON "; |
char OFF[] PROGMEM = "OFF"; |
|
#endif // ends !(ALLCHARSDEBUG|(WRITECHARS != -1)) |
|
// general PAL|NTSC distingiusch stuff |
91,28 → 90,9 |
uint8_t max_voltage = 0; |
|
// Flags |
uint8_t COSD_FLAGS = 0, COSD_FLAGS2; |
uint8_t COSD_FLAGS = 0, COSD_FLAGS2 = 0; |
|
/* ########################################################################## |
* debounce buttons |
* ##########################################################################*/ |
int s1_pressed() { |
if (S1_PRESSED) { |
_delay_ms(25); |
if (S1_PRESSED) return 1; |
} |
return 0; |
} |
|
int s2_pressed() { |
if (S2_PRESSED) { |
_delay_ms(25); |
if (S2_PRESSED) return 1; |
} |
return 0; |
} |
|
/* ########################################################################## |
* Interrupt handler |
* ##########################################################################*/ |
|
129,74 → 109,7 |
* timer stuff |
* ##########################################################################*/ |
|
|
/* ########################################################################## |
* STROM TEST |
* ##########################################################################*/ |
#define INT0_HIGH PORTD |= (1 << PD2); |
#define INT0_LOW PORTD &= ~(1 << PD2); |
|
void SpiMasterInit(void) { |
volatile char IOReg; |
// set PB4(/SS), PB5(MOSI), PB7(SCK) as output |
DDRB = (1 << PB4) | (1 << PB5) | (1 << PB7); |
PORTB |= (1 << PB4); // pullup SS |
// enable SPI Interrupt and SPI in Master Mode with SCK = CK/128 |
SPCR = (1 << SPIE) | (1 << SPE) | (1 << MSTR) | (1 << SPR0) | (1 << SPR1); |
IOReg = SPSR; // clear SPIF bit in SPSR |
IOReg = SPDR; |
//sei(); // we do it later |
} |
|
volatile size_t icnt = 0; |
volatile unsigned char * iptr; |
volatile unsigned char spi_cmd_buffer[8]; |
volatile uint8_t spi_ready = 1; |
int16_t ampere = 0, max_ampere = 0; |
int32_t ampere_wasted = 0; |
|
/** |
* SPI interrupt handler |
*/ |
ISR(SPI_STC_vect) { |
*iptr++ = SPDR; // safe received byte to buffer |
icnt--; // dec length |
if (icnt) { |
//SPDR = *iptr; // send next byte |
spi_ready = 1; // we _should_ send later because the slave needs more time |
} else { |
SPCR &= ~_BV(SPIE); // deactivate interrupt |
INT0_HIGH // transfer is done, slave does not need to listen |
} |
} |
|
/** |
* check if SPI transfer is still busy |
*/ |
int TransferIsBusy(void) { |
return SPCR & _BV(SPIE); |
} |
|
/** |
* start a new transfer of <data> with length <len> |
*/ |
void StartTransfer(unsigned char *data, size_t len) { |
INT0_LOW // /SS LOW ^= SS HIGH ^= slave should listen |
|
// set up pointer and length for interrupt handler |
iptr = data; |
icnt = len; |
|
SPCR |= _BV(SPIE); // enable spi interrupt |
SPDR = *iptr; // start transfer by first bye |
} |
|
|
/* ########################################################################## |
* / STROM TEST END |
* ##########################################################################*/ |
|
/** |
* timer kicks in every 1000uS ^= 1ms |
*/ |
ISR(TIMER0_OVF_vect) { |
211,199 → 124,6 |
SPDR = *iptr; |
} |
} |
|
/* ########################################################################## |
* A simple config menu for the flags |
* ##########################################################################*/ |
|
/** |
* helper function for menu updating |
*/ |
void config_menu_drawings(uint8_t chosen) { |
// clear prevoius _cursor_ |
write_ascii_string(3, (chosen + 5) % 8, " "); |
// draw current _cursor_ |
write_ascii_string(3, chosen + 5, ">"); |
if (COSD_FLAGS & COSD_FLAG_HUD) { |
write_ascii_string_pgm(23, 5, ON); |
} else { |
write_ascii_string_pgm(23, 5, OFF); |
} |
if (COSD_FLAGS & COSD_FLAG_ARTHORIZON) { |
write_ascii_string_pgm(23, 6, ON); |
} else { |
write_ascii_string_pgm(23, 6, OFF); |
} |
if (COSD_FLAGS & COSD_FLAG_BIGVARIO) { |
write_ascii_string_pgm(23, 7, ON); |
} else { |
write_ascii_string_pgm(23, 7, OFF); |
} |
if (COSD_FLAGS & COSD_FLAG_STATS) { |
write_ascii_string_pgm(23, 8, ON); |
} else { |
write_ascii_string_pgm(23, 8, OFF); |
} |
if (COSD_FLAGS & COSD_FLAG_WARNINGS) { |
write_ascii_string_pgm(23, 9, ON); |
} else { |
write_ascii_string_pgm(23, 9, OFF); |
} |
} |
|
/** |
* some sort of clicking response in the menu |
*/ |
void config_menu_doclick(uint8_t chosen, char** menu) { |
write_ascii_string(4, chosen + 5, "DONE "); |
_delay_ms(1000); |
write_ascii_string(4, chosen + 5, menu[chosen]); |
} |
|
/** |
* a simple config menu tryout |
*/ |
void config_menu(void) { |
// disable interrupts (makes the menu more smoothely) |
cli(); |
|
// clear screen |
clear(); |
|
char* menu[9] = {"Full HUD", |
"Art.Horizon in HUD", |
"Big Vario bar", |
"Statistics", |
"Warnings", // TODO: do it! |
"Reset uptime", |
"Request OSD-data", |
"Disable Debug-data", |
"EXIT"}; |
|
uint8_t inmenu = 1; |
uint8_t chosen = 0; |
write_ascii_string(6, 2, "C-OSD Config Menu"); |
|
// wait a bit before doing stuff so user has chance to release button |
_delay_ms(250); |
|
write_ascii_string(4, 5, menu[0]); |
write_ascii_string(4, 6, menu[1]); |
write_ascii_string(4, 7, menu[2]); |
write_ascii_string(4, 8, menu[3]); |
write_ascii_string(4, 9, menu[4]); |
write_ascii_string(4, 10, menu[5]); |
write_ascii_string(4, 11, menu[6]); |
write_ascii_string(4, 12, menu[7]); |
write_ascii_string(4, 13, menu[8]); |
|
config_menu_drawings(chosen); |
|
while (inmenu) { |
if (s2_pressed()) { |
write_ascii_string(3, chosen + 5, " "); |
chosen = (chosen + 1) % 9; |
write_ascii_string(3, chosen + 5, ">"); |
_delay_ms(500); |
} else if (s1_pressed()) { |
switch (chosen) { |
case 0: // full HUD |
COSD_FLAGS ^= COSD_FLAG_HUD; |
config_menu_drawings(chosen); |
break; |
case 1: // art horizon |
COSD_FLAGS ^= COSD_FLAG_ARTHORIZON; |
config_menu_drawings(chosen); |
break; |
case 2: // big vario |
COSD_FLAGS ^= COSD_FLAG_BIGVARIO; |
config_menu_drawings(chosen); |
break; |
case 3: // statistics |
COSD_FLAGS ^= COSD_FLAG_STATS; |
config_menu_drawings(chosen); |
break; |
case 4: // warnings |
COSD_FLAGS ^= COSD_FLAG_WARNINGS; |
config_menu_drawings(chosen); |
break; |
case 5: // reset uptime |
uptime = 0; |
config_menu_doclick(chosen, menu); |
break; |
case 6: // re-request OSD data |
#if FCONLY |
// request data ever 100ms from FC; |
usart1_request_mk_data(0, 'd', 100); |
#else |
// request OSD Data from NC every 100ms |
usart1_request_mk_data(1, 'o', 100); |
|
// and disable debug... |
usart1_request_mk_data(0, 'd', 0); |
#endif |
config_menu_doclick(chosen, menu); |
break; |
case 7: // disable debug data |
// disable sending of debug data |
// may result in smoother ddata display |
usart1_request_mk_data(0, 'd', 0); |
config_menu_doclick(chosen, menu); |
break; |
case 8: // exit |
inmenu = 0; |
break; |
} |
_delay_ms(250); |
} |
} |
|
// clear screen up again |
clear(); |
|
// update flags to paint display again if needed |
COSD_FLAGS &= ~COSD_ICONS_WRITTEN; |
|
// enable interrupts again |
sei(); |
} |
|
/** |
* auto config some stuff on startup, currently only battery cells |
* TODO: this is testing stuff, strings should go progmem and so on... |
*/ |
void auto_config(uint8_t UBat) { |
clear(); |
write_ascii_string(2, 2, "C-OSD Initialisation"); |
#if FCONLY |
write_ascii_string(2, 3, "FC only Mode"); |
#else |
write_ascii_string(2, 3, "NaviCtrl Mode"); |
#endif |
write_ascii_string(2, 4, BUILDDATE); |
uint8_t cellnum = 0; |
if (CELL_NUM == -1) { |
write_ascii_string(2, 6, "Guessing Number of Cells"); |
do { |
cellnum++; |
} while (UBat > ((cellnum * CELL_VOLT_MAX) + 23)); |
} else { |
cellnum = CELL_NUM; |
} |
min_voltage = cellnum * CELL_VOLT_MIN; |
max_voltage = cellnum * CELL_VOLT_MAX; |
write_ascii_string(2, 7, "Number of Cells:"); |
write_ndigit_number_u(21, 7, cellnum, 1, 0); |
write_ascii_string(2, 8, "Warn Voltage :"); |
write_ndigit_number_s_10th(20, 8, min_voltage, 100, 0); |
write_ascii_string(2, 9, "Max Voltage :"); |
write_ndigit_number_s_10th(20, 9, max_voltage, 100, 0); |
_delay_ms(200); |
clear(); |
// update flags to paint display again because of clear |
COSD_FLAGS &= ~COSD_ICONS_WRITTEN; |
} |
|
#endif // ends !(ALLCHARSDEBUG|(WRITECHARS != -1))#endif // ends !(ALLCHARSDEBUG|(WRITECHARS != -1)) |
|
/* ########################################################################## |
546,8 → 266,6 |
//char arrowdir[8] = {218, 217, 224, 223, 222, 221, 220, 219}; |
#endif |
|
|
|
while (1) { |
// in case SPI is ready and there is nothing to send right now |
if (!icnt && spi_ready) { |
566,7 → 284,7 |
//ampere_wasted = *((int32_t *) &spi_cmd_buffer + 3); |
// if this is the first receival we should print the small A |
if (!(COSD_FLAGS2 & COSD_FLAG_STROMREC)) { |
COSD_FLAGS &= ~COSD_ICONS_WRITTEN; |
COSD_FLAGS2 &= ~COSD_ICONS_WRITTEN; |
// update this flag |
COSD_FLAGS2 |= COSD_FLAG_STROMREC; |
} |
586,7 → 304,6 |
StartTransfer((unsigned char*) spi_cmd_buffer, 7); |
} |
if (rxd_buffer_locked) { |
if (COSD_FLAGS & COSD_FLAG_HUD) { |
#if FCONLY |
if (rxd_buffer[2] == 'D') { // FC Data |
Decode64(); |
596,7 → 313,7 |
if (last_UBat == 255) { |
// fix for min_UBat |
min_UBat = debugData.Analog[9]; |
auto_config(debugData.Analog[9]); |
init_cosd(debugData.Analog[9]); |
} |
#include "osd_fcmode_default.c" |
} |
609,12 → 326,11 |
if (last_UBat == 255) { |
// fix for min_UBat |
min_UBat = naviData.UBat; |
auto_config(naviData.UBat); |
init_cosd(naviData.UBat); |
} |
#include "osd_ncmode_default.c" |
} |
#endif |
} |
rxd_buffer_locked = 0; |
} |
// handle keypress |