Rev 2099 |
Go to most recent revision |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/****************************************************************************
* Copyright (C) 2009-2016 by Claas Anders "CaScAdE" Rathje *
* admiralcascade@gmail.com *
* Project-URL: http://www.mylifesucks.de/oss/c-osd/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
****************************************************************************/
#include "main.h"
#include <avr/io.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <string.h>
#include "max7456_software_spi.h"
#include "config.h"
#include "buttons.h"
#include "usart1.h"
#include "osd_helpers.h"
#if !(ALLCHARSDEBUG|(WRITECHARS != -1))
// EEPROM bytes
uint8_t EEMEM ee_checkbyte1
= CHECKBYTE1
;
uint8_t EEMEM ee_checkbyte2
= CHECKBYTE2
;
uint8_t EEMEM ee_COSD_FLAGS_MODES
= 0;
uint8_t EEMEM ee_COSD_FLAGS_CONFIG
= 0;
uint8_t EEMEM ee_COSD_DISPLAYMODE
= 0;
uint8_t EEMEM ee_COSD_SCOPE
[12] = {
5, 5, 0,
25, 5, 0,
5, 10, 0,
25, 10, 0
};
// video modes
const char VM_PAL
[] PROGMEM
= "PAL ";
const char VM_NTSC
[] PROGMEM
= "NTSC";
#if FCONLY
const displaymode_t
* mode
= fcdisplaymodes
;
#else
const displaymode_t
* mode
= ncdisplaymodes
;
#endif
/**
* read data saved in eeprom, print out message if <verbose> is set
*/
void get_eeprom
(uint8_t verbose
) {
if (eeprom_read_byte
(&ee_checkbyte1
) == CHECKBYTE1
&& eeprom_read_byte
(&ee_checkbyte2
) == CHECKBYTE2
) {
if (verbose
) write_ascii_string_pgm
(2, 6, PSTR
("Loading from EEPROM")); // Loading data
COSD_FLAGS_MODES
= eeprom_read_byte
(&ee_COSD_FLAGS_MODES
);
COSD_FLAGS_CONFIG
= eeprom_read_byte
(&ee_COSD_FLAGS_CONFIG
);
COSD_DISPLAYMODE
= eeprom_read_byte
(&ee_COSD_DISPLAYMODE
);
//if (verbose) write_ndigit_number_u(23, 11, COSD_DISPLAYMODE, 2, 0);
for (int i
= 0; i
< 12; i
++) {
scope
[i
] = eeprom_read_byte
(&ee_COSD_SCOPE
[i
]);
}
} else {
if (verbose
) write_ascii_string_pgm
(2, 6, PSTR
("No Data in EEPROM")); // Loading data
}
}
/**
* save data to eeprom
*/
void save_eeprom
() {
eeprom_write_byte
(&ee_checkbyte1
, CHECKBYTE1
);
eeprom_write_byte
(&ee_checkbyte2
, CHECKBYTE2
);
eeprom_write_byte
(&ee_COSD_FLAGS_MODES
, COSD_FLAGS_MODES
);
eeprom_write_byte
(&ee_COSD_FLAGS_CONFIG
, COSD_FLAGS_CONFIG
);
eeprom_write_byte
(&ee_COSD_DISPLAYMODE
, COSD_DISPLAYMODE
);
for (int i
= 0; i
< 12; i
++) {
eeprom_write_byte
(&ee_COSD_SCOPE
[i
], scope
[i
]);
}
}
/**
* auto config some stuff on startup, currently only battery cells
*/
void init_cosd
(uint8_t UBat
) {
clear
();
write_ascii_string_pgm
(2, 1, PSTR
("C-OSD"));
write_ascii_string_pgm
(3, 2, PSTR
("boot"));
draw_logo
(11, 1);
write_ascii_string_pgm
(2, 5, PSTR
(BUILDOSDBUILDDATE
));
get_eeprom
(1);
//write_ascii_string_pgm(23, 2, vm[COSD_FLAGS & COSD_FLAG_NTSC]);
if (COSD_FLAGS_CONFIG
& COSD_FLAG_NTSC
) {
write_ascii_string_pgm
(23, 1, VM_NTSC
);
} else {
write_ascii_string_pgm
(23, 1, VM_PAL
);
}
write_ascii_string_pgm
(2, 7, PSTR
("Setting :"));
write_ascii_string_pgm
(2, 8, PSTR
("Battery:")); // Guessing Number of Cells
write_ascii_string_pgm
(13, 8, PSTR
("Cells")); // Number of Cells
write_ascii_string_pgm
(2, 9, PSTR
("Warn:")); // Warn Voltage
write_ascii_string_pgm
(14, 9, PSTR
("Max:")); // Max Voltage
#if FCONLY
write_ascii_string_pgm
(2, 4, PSTR
("FC only Mode"));
#else
write_ascii_string_pgm
(2, 4, PSTR
("NaviCtrl Mode"));
usart1_EnableTXD
();
usart1_puts_pgm
(PSTR
(REQUEST_UART_TO_FC
));
usart1_DisableTXD
();
#endif
paramset_serial setting
;
//#define NOFCOMMUNICATION
#ifndef NOFCOMMUNICATION
usart1_request_blocking
('Q', PSTR
(REQUEST_CURRENT_SETTING
));
memcpy((char*)(&setting
), (char*)pRxData
, sizeof(paramset_serial
));
if (setting.
param.
Revision != EEPARAM_REVISION
) {
write_ascii_string_pgm
(3, 11, PSTR
("WRONG SETTINGS REVISION"));
write_ascii_string_pgm
(3, 12, PSTR
("OSD: FC:"));
write_ndigit_number_u
(8, 12, EEPARAM_REVISION
, 3, 1);
write_ndigit_number_u
(15, 12, setting.
param.
Revision, 3, 1);
for (uint8_t i
= 0; i
< 120; i
++) {_delay_ms
(1000);}
}
#if FCONLY
#else
if (naviData.
Version != NAVIDATA_VERSION
) {
write_ascii_string_pgm
(3, 11, PSTR
("WRONG NAVIDATA VERSION"));
write_ascii_string_pgm
(3, 12, PSTR
("OSD: FC:"));
write_ndigit_number_u
(8, 12, NAVIDATA_VERSION
, 3, 1);
write_ndigit_number_u
(15, 12, naviData.
Version, 3, 1);
for (uint8_t i
= 0; i
< 120; i
++) {_delay_ms
(1000);}
}
#endif
//setting = *((paramset_serial*)pRxData);
#else
// manual stuff?
memcpy((char*)setting.
param.
Name, "NO FC COMMUN", 12);
setting.
param.
UnterspannungsWarnung = 94;
#endif // #ifndef NOFCOMMUNICATION
//write_ascii_char(4 + 12 * 30, rxd_buffer[2]);
write_ndigit_number_u
(10, 7, setting.
SettingsIndex, 1, 1);
write_ascii_string_len
(13, 7, setting.
param.
Name, 12);
uint8_t cells
= 0;
if (CELL_NUM
== -1) {
#define MAX_CELL_VOLTAGE 43 // max cell volatage for LiPO
if (setting.
param.
UnterspannungsWarnung < 50) {
// up to 6s LiPo, less than 2s is technical impossible
for (cells
= 2; cells
< 7; cells
++) {
if (UBat
< cells
* MAX_CELL_VOLTAGE
) break;
}
min_voltage
= cells
* setting.
param.
UnterspannungsWarnung;
} else {
min_voltage
= setting.
param.
UnterspannungsWarnung;
cells
= min_voltage
/ CELL_VOLT_MIN
;
}
//write_ndigit_number_u(10, 13, setting.param.UnterspannungsWarnung, 3, 1);
} else {
cells
= CELL_NUM
;
min_voltage
= cells
* CELL_VOLT_MIN
;
}
max_voltage
= cells
* CELL_VOLT_MAX
;
write_ndigit_number_u
(11, 8, cells
, 1, 0);
write_ndigit_number_s_10th
(8, 9, min_voltage
, 3, 0);
write_ndigit_number_s_10th
(20, 9, max_voltage
, 3, 0);
// request version from board
#if FCONLY
//usart1_request_mk_data(0, 'v', 0);
write_ascii_string_pgm
(2, 11, PSTR
("FC VERSION: ........"));
usart1_request_blocking
('V', PSTR
(REQUEST_FC_VERSION
));
#else
usart1_request_nc_uart
();
_delay_ms
(200);
usart1_request_nc_uart
();
//usart1_request_mk_data(1, 'v', 0);
write_ascii_string_pgm
(2, 11, PSTR
("NC VERSION: ........"));
usart1_request_blocking
('V', PSTR
(REQUEST_NC_VERSION
));
#endif
str_VersionInfo VersionInfo
;
//VersionInfo = *((str_VersionInfo*)pRxData);
memcpy((char*)(&VersionInfo
), (char*)pRxData
, sizeof(str_VersionInfo
));
write_ndigit_number_u
(14, 11, VersionInfo.
SWMajor, 3, 1);
write_ndigit_number_u
(18, 11, VersionInfo.
SWMinor, 3, 1);
write_ascii_char
(22 + 11 * 30, 'a' + VersionInfo.
SWPatch);
// end version request
#if FCONLY
COSD_DISPLAYMODE
%= (sizeof (fcdisplaymodes
) / sizeof (displaymode_t
));
mode
= fcdisplaymodes
;
mode
+= COSD_DISPLAYMODE
;
osd_fcmode
= (int(*)(void)) pgm_read_word
(&mode
->dfun
);
// re-request data ever 100ms from FC;
//usart1_request_mk_data(0, 'd', 100);
#else
COSD_DISPLAYMODE
%= (sizeof (ncdisplaymodes
) / sizeof (displaymode_t
));
mode
= ncdisplaymodes
;
mode
+= COSD_DISPLAYMODE
;
osd_ncmode
= (int(*)(void)) pgm_read_word
(&mode
->dfun
);
// re-request OSD Data from NC every 100ms
//usart1_request_mk_data(1, 'o', 100);
#endif
_delay_ms
(5000);
clear
();
// update flags to paint display again because of clear
COSD_FLAGS_RUNTIME
&= ~COSD_ICONS_WRITTEN
;
// we got data
COSD_FLAGS_RUNTIME
|= COSD_DATARECEIVED
;
}
/* ##########################################################################
* A simple config menu for the flags
* ##########################################################################*/
/**
* helper function for flag display
*/
void onoff
(uint8_t col
, uint8_t line
, uint8_t onoff
) {
if (onoff
) {
write_ascii_string_pgm
(col
, line
, PSTR
("ON "));
} else {
write_ascii_string_pgm
(col
, line
, PSTR
("OFF"));
}
}
/**
* helper function for menu updating
*/
void config_menu_drawings
(uint8_t chosen
) {
static uint8_t old_y
= 0;
uint8_t x
= MENU_LEFT
, y
= MENU_TOP
, line
= MENU_TOP
;
//************************************************* 13 to 14
if (chosen
> 6 && chosen
< 15) { // right
x
= MENU_MIDDLE
;
y
= chosen
- 7 + MENU_TOP
;
} else if (chosen
< 8) {
y
= chosen
+ MENU_TOP
;
} else {
y
= chosen
- 7 + MENU_TOP
;
}
// clear prevoius _cursor_ and draw current
for (uint8_t myx
= MENU_LEFT
; myx
< 29; myx
++) {
write_char_att_xy
(myx
, old_y
, 0);
if (myx
> x
- 1 && myx
< x
+ 14) {
write_char_att_xy
(myx
, y
, BLACKBG
| INVERT
);
}
};
write_ascii_string_pgm
(MENU_LEFT
, line
, PSTR
("Video"));
if (COSD_FLAGS_CONFIG
& COSD_FLAG_NTSC
) {
write_ascii_string_pgm
(MENU_LEFT
+ 10, line
, VM_NTSC
);
} else {
write_ascii_string_pgm
(MENU_LEFT
+ 10, line
, VM_PAL
);
}
write_ascii_string_pgm
(MENU_LEFT
, ++line
, PSTR
("Full HUD"));
onoff
(MENU_LEFT
+ 10, line
, COSD_FLAGS_MODES
& COSD_FLAG_HUD
);
write_ascii_string_pgm
(MENU_LEFT
, ++line
, PSTR
("Horizon"));
onoff
(MENU_LEFT
+ 10, line
, COSD_FLAGS_MODES
& COSD_FLAG_ARTHORIZON
);
write_ascii_string_pgm
(MENU_LEFT
, ++line
, PSTR
("Aggr.Hor."));
onoff
(MENU_LEFT
+ 10, line
, COSD_FLAGS_MODES
& COSD_FLAG_AGGRHORIZON
);
write_ascii_string_pgm
(MENU_LEFT
, ++line
, PSTR
("Stats"));
onoff
(MENU_LEFT
+ 10, line
, COSD_FLAGS_MODES
& COSD_FLAG_STATS
);
write_ascii_string_pgm
(MENU_LEFT
, ++line
, PSTR
("A by FC"));
onoff
(MENU_LEFT
+ 10, line
, COSD_FLAGS_MODES
& COSD_FLAG_FCCURRENT
);
write_ascii_string_pgm
(MENU_LEFT
, ++line
, PSTR
("GPS Pos"));
onoff
(MENU_LEFT
+ 10, line
, COSD_FLAGS_CONFIG
& COSD_FLAG_SHOW_COORDS
);
// 2nd col
line
= 2;
write_ascii_string_pgm
(MENU_MIDDLE
, line
, PSTR
("V C-Strom"));
onoff
(MENU_MIDDLE
+ 10, line
, COSD_FLAGS_MODES
& COSD_FLAG_STROMVOLT
);
write_ascii_string_pgm
(MENU_MIDDLE
, ++line
, PSTR
("Height by"));
if (COSD_FLAGS_CONFIG
& COSD_FLAG_GPSHEIGHT
) {
write_ascii_string_pgm
(MENU_MIDDLE
+ 10, line
, PSTR
(" GPS"));
} else {
write_ascii_string_pgm
(MENU_MIDDLE
+ 10, line
, PSTR
("BARO"));
}
write_ascii_string_pgm
(MENU_MIDDLE
, ++line
, PSTR
("Feet/mph"));
onoff
(MENU_MIDDLE
+ 10, line
, COSD_FLAGS_CONFIG
& COSD_FLAG_FEET
);
write_ascii_string_pgm
(MENU_MIDDLE
, ++line
, PSTR
("Big Vario"));
onoff
(MENU_MIDDLE
+ 10, line
, COSD_FLAGS_MODES
& COSD_FLAG_BIGVARIO
);
write_ascii_string_pgm
(MENU_MIDDLE
, ++line
, PSTR
("Big Speed"));
onoff
(MENU_MIDDLE
+ 10, line
, COSD_FLAGS_CONFIG
& COSD_FLAG_BIGSPEED
);
write_ascii_string_pgm
(MENU_MIDDLE
, ++line
, PSTR
("Passive"));
onoff
(MENU_MIDDLE
+ 10, line
, COSD_FLAGS_CONFIG
& COSD_FLAG_PASSIVE
);
write_ascii_string_pgm
(MENU_MIDDLE
, ++line
, PSTR
("Cam Scope"));
onoff
(MENU_MIDDLE
+ 10, line
, COSD_FLAGS_CONFIG
& COSD_FLAG_SHOW_SCOPE
);
write_ascii_string_pgm
(MENU_MIDDLE
, ++line
, PSTR
("Move Scope"));
// bottom
write_ascii_string_pgm
(MENU_LEFT
, 10, PSTR
("Reset uptime"));
write_ascii_string_pgm
(MENU_LEFT
, 11, PSTR
("Display Mode"));
write_ascii_string_pgm
(15, 11, (const char *)(pgm_read_word
(&(mode
->desc
))));
write_ascii_string_pgm
(MENU_LEFT
, 12, PSTR
("Save config"));
write_ascii_string_pgm
(MENU_LEFT
, 13, PSTR
("EXIT"));
old_y
= y
;
}
/**
* some sort of clicking response in the menu
*/
void config_menu_doclick
(uint8_t chosen
) {
write_ascii_string_pgm
(MENU_LEFT
, chosen
+ MENU_TOP
- 7, PSTR
("DONE "));
_delay_ms
(500);
config_menu_drawings
(chosen
);
}
/**
* move around the four scope edges
*/
void move_scope
() {
uint8_t mode
= 0;
clear
();
draw_scope
();
_delay_ms
(500);
while (mode
< 12) {
if (s2_pressed
()) { // next
mode
++;
_delay_ms
(500);
} else if (s1_pressed
()) {
if (mode
% 3 == 2) {
scope
[mode
] = (scope
[mode
] + 1) % 2;
} else {
scope
[mode
] = (scope
[mode
] + 1) % ((mode
% 3) % 2 == 0 ? 30 : bottom_line
);
}
clear
();
draw_scope
();
_delay_ms
(100);
}
}
clear
();
}
/**
* a simple config menu tryout
*/
void config_menu
(void) {
// disable interrupts (makes the menu more smoothely)
cli
();
// clear screen
clear
();
uint8_t chosen
= 0;
uint8_t inmenu
= 1;
write_ascii_string_pgm
(6, 1, PSTR
("C-OSD Config Menu"));
// wait a bit before doing stuff so user has chance to release button
_delay_ms
(250);
config_menu_drawings
(chosen
);
while (inmenu
) {
if (s2_pressed
()) {
chosen
= (chosen
+ 1) % 19;
//if (chosen == 12) chosen = 13; // SKIP unused menu space for now
config_menu_drawings
(chosen
);
_delay_ms
(500);
} else if (s1_pressed
()) {
switch (chosen
) {
case 0: // NTSC or PAL
COSD_FLAGS_CONFIG
^= COSD_FLAG_NTSC
;
// Setup Video Mode
if (COSD_FLAGS_CONFIG
& COSD_FLAG_NTSC
) {
// NTSC + enable display immediately (VM0)
spi_send_byte
(0x00, 0b00001000);
bottom_line
= 12;
} else {
// PAL + enable display immediately (VM0)
spi_send_byte
(0x00, 0b01001000);
bottom_line
= 14;
}
break;
case 1: // full HUD
COSD_FLAGS_MODES
^= COSD_FLAG_HUD
;
break;
case 2: // art horizon
COSD_FLAGS_MODES
^= COSD_FLAG_ARTHORIZON
;
break;
case 3: // aggressiva horizon
COSD_FLAGS_MODES
^= COSD_FLAG_AGGRHORIZON
;
break;
case 4: // statistics
COSD_FLAGS_MODES
^= COSD_FLAG_STATS
;
break;
case 5: // current by fc
COSD_FLAGS_MODES
^= COSD_FLAG_FCCURRENT
;
break;
case 6: // GPS coordinates while flying
COSD_FLAGS_CONFIG
^= COSD_FLAG_SHOW_COORDS
;
break;
case 7: // 2nd voltage by c-strom
COSD_FLAGS_MODES
^= COSD_FLAG_STROMVOLT
;
break;
case 8: // GPS or BARO height
COSD_FLAGS_CONFIG
^= COSD_FLAG_GPSHEIGHT
;
break;
case 9: // Feet and mph?
COSD_FLAGS_CONFIG
^= COSD_FLAG_FEET
;
break;
case 10: // big vario
COSD_FLAGS_MODES
^= COSD_FLAG_BIGVARIO
;
break;
case 11: // big Speed
COSD_FLAGS_CONFIG
^= COSD_FLAG_BIGSPEED
;
break;
case 12: // passive
COSD_FLAGS_CONFIG
^= COSD_FLAG_PASSIVE
;
break;
case 13: // scope
COSD_FLAGS_CONFIG
^= COSD_FLAG_SHOW_SCOPE
;
break;
case 14: // move scope
move_scope
();
break;
case 15: // reset uptime
uptime
= 0;
config_menu_doclick
(chosen
);
break;
case 16: // change mode
#if FCONLY
COSD_DISPLAYMODE
= (COSD_DISPLAYMODE
+ 1) % (sizeof (fcdisplaymodes
) / sizeof (displaymode_t
));
mode
= fcdisplaymodes
;
mode
+= COSD_DISPLAYMODE
;
osd_fcmode
= (int(*)(void)) pgm_read_word
(&mode
->dfun
);
#else
COSD_DISPLAYMODE
= (COSD_DISPLAYMODE
+ 1) % (sizeof (ncdisplaymodes
) / sizeof (displaymode_t
));
mode
= ncdisplaymodes
;
mode
+= COSD_DISPLAYMODE
;
osd_ncmode
= (int(*)(void)) pgm_read_word
(&mode
->dfun
);
#endif
break;
case 17: // save
save_eeprom
();
config_menu_doclick
(chosen
);
break;
case 18: // exit
inmenu
= 0;
config_menu_doclick
(chosen
);
break;
}
config_menu_drawings
(chosen
);
_delay_ms
(250);
}
}
// clear screen up again
clear
();
// update flags to paint display again if needed
COSD_FLAGS_RUNTIME
&= ~COSD_ICONS_WRITTEN
;
// enable interrupts again
sei
();
}
#endif