/C-OSD/trunk/CHANGE.LOG |
---|
18,6 → 18,10 |
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
****************************************************************************/ |
20100822-2300 |
*removed debug-leftover in ppm.c (thx OktoMac) |
*made number display-routines more stable when big numbers occur |
20100803-0355 |
*removed constantly requests for the NC Uart in NC mode which |
caused problems when using OSD/MKTool at the same time |
215,7 → 219,7 |
20090418-0100 |
*variometer uses more steps (9 instead of 5) |
*home-arrow is now home-clock using more steps (22,5° resolution) |
*home-arrow is now home-clock using more steps (22,5� resolution) |
+visual battery-gauge according to difference between UBAT_WRN and UBAT_MAX |
20090417-1115 |
/C-OSD/trunk/buttons.c |
---|
18,9 → 18,9 |
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
****************************************************************************/ |
#include "main.h" |
#include <avr/io.h> |
#include <util/delay.h> |
#include "main.h" |
/* ########################################################################## |
* debounce buttons |
/C-OSD/trunk/characters.c |
---|
18,10 → 18,10 |
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
****************************************************************************/ |
#include "main.h" |
#include <avr/io.h> |
#include <avr/pgmspace.h> |
#include <util/delay.h> |
#include "main.h" |
#include "max7456_software_spi.h" |
/C-OSD/trunk/config.c |
---|
18,6 → 18,7 |
* 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> |
25,7 → 26,6 |
#include <util/delay.h> |
#include "max7456_software_spi.h" |
#include "config.h" |
#include "main.h" |
#include "buttons.h" |
#include "usart1.h" |
62,7 → 62,6 |
} |
} |
/** |
* save data to eeprom |
*/ |
87,49 → 86,49 |
#else |
write_ascii_string_pgm(2, 3, PSTR("NaviCtrl Mode")); |
usart1_EnableTXD(); |
usart1_puts_pgm(PSTR(REQUEST_UART_TO_FC)); |
usart1_DisableTXD(); |
usart1_EnableTXD(); |
usart1_puts_pgm(PSTR(REQUEST_UART_TO_FC)); |
usart1_DisableTXD(); |
#endif |
usart1_request_blocking('Q', PSTR(REQUEST_CURRENT_SETTING)); |
usart1_request_blocking('Q', PSTR(REQUEST_CURRENT_SETTING)); |
//write_ascii_char(4 + 12 * 30, rxd_buffer[2]); |
//write_ascii_char(4 + 12 * 30, rxd_buffer[2]); |
paramset_serial setting; |
setting = *((paramset_serial*)pRxData); |
write_ascii_string_pgm(2, 6, PSTR("Setting: ")); |
write_ndigit_number_u(11, 6, setting.SettingsIndex, 1, 1); |
write_ascii_string_len(13, 6, setting.param.Name, 12); |
write_ascii_string_pgm(2, 6, PSTR("Setting: ")); |
write_ndigit_number_u(11, 6, setting.SettingsIndex, 1, 1); |
write_ascii_string_len(13, 6, setting.param.Name, 12); |
uint8_t cells = 0; |
write_ascii_string_pgm(2, 8, PSTR("Battery:")); // Guessing Number of Cells |
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; |
} |
uint8_t cells = 0; |
write_ascii_string_pgm(2, 8, PSTR("Battery:")); // Guessing Number of Cells |
if (CELL_NUM == -1) { |
#define MAX_CELL_VOLTAGE 43 // max cell volatage for LiPO |
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); |
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; |
min_voltage = cells * CELL_VOLT_MIN; |
} |
max_voltage = cells * CELL_VOLT_MAX; |
max_voltage = cells * CELL_VOLT_MAX; |
write_ndigit_number_u(11, 8, cells, 1, 0); |
write_ascii_string_pgm(13, 8, PSTR("Cells")); // 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_ndigit_number_s_10th(8, 9, min_voltage, 3, 0); |
write_ascii_string_pgm(14, 9, PSTR("Max:")); // Max Voltage |
148,12 → 147,12 |
#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)); |
usart1_request_blocking('V', PSTR(REQUEST_FC_VERSION)); |
#else |
usart1_request_nc_uart(); |
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)); |
usart1_request_blocking('V', PSTR(REQUEST_NC_VERSION)); |
#endif |
str_VersionInfo VersionInfo; |
VersionInfo = *((str_VersionInfo*)pRxData); |
/C-OSD/trunk/default/dist.bat |
---|
19,7 → 19,7 |
:: * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
:: ****************************************************************************/ |
set DATE=20100803-0355 |
set DATE=20100822-2300 |
:: date /T |
/C-OSD/trunk/main.c |
---|
25,11 → 25,11 |
* Manuel "KeyOz" Schrape for explaining the MK protocol to me * |
****************************************************************************/ |
#include "main.h" |
#include <avr/io.h> |
#include <avr/interrupt.h> |
#include <util/delay.h> |
#include <avr/pgmspace.h> |
#include "main.h" |
#include "max7456_software_spi.h" |
#ifdef ANTENNATRACKTEST |
#include "usart0.h" |
246,7 → 246,7 |
LED4_OFF |
DDRC &= ~((1 << PC4) | (1 << PC5)); // PC4 input (MODE) | PC5 input (SET) |
PORTC |= ((1 << PC4) | (1 << PC5)); // pullup |
PORTC |= ((1 << PC4) | (1 << PC5)); // pullup |
// reset the MAX7456 to be sure any undefined states do no harm |
MAX_RESET_LOW |
259,8 → 259,8 |
//Pushing NEW chars to the MAX7456 |
#if (WRITECHARS != -1) |
// DISABLE display (VM0) |
spi_send_byte(0x00, 0b00000000); |
// DISABLE display (VM0) |
spi_send_byte(0x00, 0b00000000); |
learn_all_chars_pgm(); |
#else |
// read out config for NTSC/PAL distinguishing |
299,7 → 299,7 |
#ifdef ANTENNATRACKTEST |
usart0_init(); |
usart0_init(); |
#endif |
// keep serial port clean |
338,10 → 338,10 |
// clear serial screen |
//usart1_puts("\x1B[2J\x1B[H"); |
#if !FCONLY |
usart1_request_nc_uart(); |
#endif |
#if !FCONLY |
usart1_request_nc_uart(); |
#endif |
while (1) { |
// in case SPI is ready and there is nothing to send right now |
if (!icnt && spi_ready) { |
403,40 → 403,40 |
} |
#endif |
// ONLY FOR TESTING |
#ifdef ANTENNATRACKTEST |
#include <stdlib.h> |
//#include <float.h> |
//#include <math.h> |
// ONLY FOR TESTING |
#ifdef ANTENNATRACKTEST |
#include <stdlib.h> |
//#include <float.h> |
//#include <math.h> |
//usart0_puts("\x1B[2J\x1B[H"); |
//usart0_puts("\x1B[2J\x1B[H"); |
/* |
naviData.HomePositionDeviation.Distance = 23 * 100; // 23m away (cm * 100) |
naviData.HomePositionDeviation.Bearing = 35; // 35° |
altimeter_offset = 50; // 50m start height |
naviData.CurrentPosition.Altitude = (int32_t) ((int32_t)250 * (int32_t)1000); // 250m height (mm * 1000) |
*/ |
/* |
naviData.HomePositionDeviation.Distance = 23 * 100; // 23m away (cm * 100) |
naviData.HomePositionDeviation.Bearing = 35; // 35� |
altimeter_offset = 50; // 50m start height |
naviData.CurrentPosition.Altitude = (int32_t) ((int32_t)250 * (int32_t)1000); // 250m height (mm * 1000) |
*/ |
static char conv_array[7]; |
// should be float |
int tanheight = (naviData.HomePositionDeviation.Distance * 100) / (naviData.CurrentPosition.Altitude - altimeter_offset); |
// we need math.h and some faster AVR :) |
//tanheight = rad2deg(atan(tanheight)); |
static char conv_array[7]; |
itoa((naviData.HomePositionDeviation.Bearing + 180) % 360, conv_array, 10); |
usart0_puts("Bearing: "); |
usart0_puts(conv_array); |
usart0_puts("\tHeightangle: "); |
itoa(tanheight, conv_array, 10); |
usart0_puts(conv_array); |
usart0_puts("\r\n"); |
#endif |
// should be float |
int tanheight = (naviData.HomePositionDeviation.Distance * 100) / (naviData.CurrentPosition.Altitude - altimeter_offset); |
// we need math.h and some faster AVR :) |
//tanheight = rad2deg(atan(tanheight)); |
itoa((naviData.HomePositionDeviation.Bearing + 180) % 360, conv_array, 10); |
usart0_puts("Bearing: "); |
usart0_puts(conv_array); |
usart0_puts("\tHeightangle: "); |
itoa(tanheight, conv_array, 10); |
usart0_puts(conv_array); |
usart0_puts("\r\n"); |
#endif |
rxd_buffer_locked = 0; |
} |
// handle keypress |
456,7 → 456,7 |
usart1_puts_pgm(PSTR(REQUEST_OSD_DATA)); |
// and disable debug... |
//usart1_request_mk_data(0, 'd', 0); |
//usart1_request_mk_data(0, 'd', 0); |
#endif |
// reset last time counter |
seconds_since_last_data = 0; |
465,15 → 465,15 |
} |
#else // character flashing... |
clear(); |
clear(); |
write_all_chars(); |
LED1_ON |
LED2_ON |
LED3_ON |
LED4_ON |
while(1) { |
while (1) { |
}; |
}; |
#endif |
/C-OSD/trunk/main.h |
---|
21,6 → 21,15 |
#ifndef _MAIN_H |
#define _MAIN_H |
#ifndef MCU |
#define MCU atmega162 |
#endif |
#ifndef __AVR_ATmega162__ |
#define __AVR_ATmega162__ |
#endif |
#include <avr/pgmspace.h> |
#include "mk-data-structs.h" |
45,17 → 54,17 |
#define FCONLY 0 // set to 1 if you do NOT have a NaviCtrl and the OSD is |
#endif // connected to the FC directly |
#define HUD 1 // set to 0 to disable HUD by default |
#define HUD 1 // set to 0 to disable HUD by default |
#define ARTHORIZON 0 // set to 1 to enable roll&nick artificial horizon by default |
#define BIGVARIO 0 // set to 1 to enable the big vario bar on right side |
#define STATS 1 // set to 1 to enable statistics during motor off by default |
#define WARNINGS 1 // set to 1 to display battery+rc warning even if HUD is disabled |
#define BIGVARIO 0 // set to 1 to enable the big vario bar on right side |
#define STATS 1 // set to 1 to enable statistics during motor off by default |
#define WARNINGS 1 // set to 1 to display battery+rc warning even if HUD is disabled |
//#define UBAT_WRN 94 // voltage for blinking warning, like FC settings (deprecated) |
//#define UBAT_MAX 114 // maximal battery voltage for battery-sign (deprecated) |
#define CELL_VOLT_MAX 37 // max voltage per battery cell (37 for LiPo) |
#define CELL_VOLT_MIN 32 // min voltage per battery cell (maybe 32 for LiPo?) |
#define CELL_NUM -1 // -1 for auto, 3 for 3s1p and 4 for 4s1p |
#define CELL_NUM -1 // -1 for auto, 3 for 3s1p and 4 for 4s1p |
#define RCLVL_WRN 100 // make the RC level blink if below this number |
// ### read datasheet before changing stuff below this line :) |
73,13 → 82,13 |
* FLAGS usable during runtime that get saved |
* ##########################################################################*/ |
#define COSD_FLAG_HUD 1 |
#define COSD_FLAG_ARTHORIZON 2 |
#define COSD_FLAG_ARTHORIZON 2 |
#define COSD_FLAG_BIGVARIO 4 |
#define COSD_FLAG_STATS 8 |
#define COSD_FLAG_WARNINGS 16 |
#define COSD_FLAG_STROMVOLT 32 |
#define COSD_FLAG_FCCURRENT 64 |
#define COSD_FLAG_AGGRHORIZON 128 |
#define COSD_FLAG_AGGRHORIZON 128 |
#define COSD_FLAG_NTSC 1 |
/C-OSD/trunk/max7456_software_spi.c |
---|
18,17 → 18,24 |
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
****************************************************************************/ |
#include "main.h" |
#include <avr/io.h> |
#include <util/delay.h> |
#include <avr/pgmspace.h> |
#include <string.h> |
#include <stdlib.h> |
#include "main.h" |
#include "max7456_software_spi.h" |
char conv_array[7]; // general array for number -> char conversation |
int pow(int a, int b) { |
if (b <= 0) return 1; |
int res = 1; |
while (b-- > 0) res *= a; |
return res; |
} |
/* ########################################################################## |
* MAX7456 SPI & Display stuff |
* ##########################################################################*/ |
228,6 → 235,9 |
* <pad> = 1 will cause blank spaced to be filled up with zeros e.g. 007 instead of 7 |
*/ |
void write_ndigit_number_u(uint8_t x, uint8_t y, uint16_t number, int16_t length, uint8_t pad) { |
if (number >= pow(10, length)) { |
number = pow(10, length) - 1; |
} |
itoa(number, conv_array, 10); |
for (uint8_t i = 0; i < length - strlen(conv_array); i++) { |
if (pad) write_char((x++)+(y * 30), 10); |
242,10 → 252,18 |
* <pad> = 1 will cause blank spaced to be filled up with zeros e.g. 007 instead of 7 |
*/ |
void write_ndigit_number_s(uint8_t x, uint8_t y, int16_t number, int16_t length, uint8_t pad) { |
if (number <= -pow(10, length)) { |
number = -pow(10, length) + 1; |
} else if (number >= pow(10, length)) { |
number = pow(10, length) - 1; |
} |
itoa(number, conv_array, 10); |
for (uint8_t i = 0; i < length - strlen(conv_array); i++) { |
if (pad) write_char((x++)+(y * 30), 10); |
else write_ascii_char((x++)+(y * 30), 0); |
if (strlen(conv_array) < length) { |
for (uint8_t i = 0; i < length - strlen(conv_array); i++) { |
if (pad) write_char((x++)+(y * 30), 10); |
else write_ascii_char((x++)+(y * 30), 0); |
} |
} |
write_ascii_string(x, y, conv_array); |
} |
256,6 → 274,9 |
* <pad> = 1 will cause blank spaced to be filled up with zeros e.g. 007 instead of 7 |
*/ |
void write_ndigit_number_u_10th(uint8_t x, uint8_t y, uint16_t number, int16_t length, uint8_t pad) { |
if (number >= pow(10, length)) { |
number = pow(10, length) - 1; |
} |
itoa(number, conv_array, 10); |
uint8_t len = strlen(conv_array); |
for (uint8_t i = 0; i < length - len; i++) { |
283,6 → 304,9 |
* <pad> = 1 will cause blank spaced to be filled up with zeros e.g. 007 instead of 7 |
*/ |
void write_ndigit_number_s_10th(uint8_t x, uint8_t y, int16_t number, int16_t length, uint8_t pad) { |
if (number >= pow(10, length)) { |
number = pow(10, length) - 1; |
} |
itoa(number, conv_array, 10); |
uint8_t len = strlen(conv_array); |
for (uint8_t i = 0; i < length - len; i++) { |
/C-OSD/trunk/osd_helpers.c |
---|
18,8 → 18,8 |
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
****************************************************************************/ |
#include "main.h" |
#include <avr/pgmspace.h> |
#include "main.h" |
#include "osd_helpers.h" |
#include "max7456_software_spi.h" |
80,7 → 80,7 |
// the center is char 19 (north), we add the current heading in 8th |
// which would be 22.5 degrees, but float would bloat up the code |
// and *10 / 225 would take ages... so we take the uncorrect way |
uint8_t front = 19 + (heading / 22); |
uint8_t front = 19 + ((heading % 360) / 22); |
for (uint8_t i = 0; i < 9; i++) { |
write_char_xy(x++, y, pgm_read_byte(&rose[front - 4 + i])); |
} |
/C-OSD/trunk/osd_ncmode_default.c |
---|
110,7 → 110,7 |
if (COSD_FLAGS_CONFIG & COSD_FLAG_FEET) { |
write_ndigit_number_s(23, top_line, naviData.Altimeter / 10 * 32 / 20, 4, 0); // BARO |
} else { |
//cite:killagreg "Faktor 20 bis 21 wäre korrekt." (http://forum.mikrokopter.de/topic-post211192.html#post211192) |
//cite:killagreg "Faktor 20 bis 21 w�re korrekt." (http://forum.mikrokopter.de/topic-post211192.html#post211192) |
if (naviData.Altimeter > 200 || naviData.Altimeter < -200) { |
// above 10m only write full meters |
write_ndigit_number_s(23, top_line, naviData.Altimeter / 20, 4, 0); // BARO |
239,13 → 239,13 |
// pre-bottom line |
if ((COSD_FLAGS_RUNTIME & COSD_FLAG_STROMREC) && !(COSD_FLAGS_MODES & COSD_FLAG_FCCURRENT)) { |
//write_ndigit_number_s(3, bottom_line - 1, ampere, 4, 0); |
write_ndigit_number_u_10th(3, bottom_line - 1, ampere / 10, 3, 0); |
write_ndigit_number_u_10th(2, bottom_line - 1, ampere / 10, 4, 0); |
write_ndigit_number_s(10, bottom_line - 1, ampere_wasted / 10, 4, 0); |
if (COSD_FLAGS_MODES & COSD_FLAG_STROMVOLT) { |
write_ndigit_number_u_10th(17, bottom_line - 1, s_volt, 3, 0); |
} |
} else if (COSD_FLAGS_MODES & COSD_FLAG_FCCURRENT) { |
write_ndigit_number_u_10th(3, bottom_line - 1, naviData.Current, 3, 0); |
write_ndigit_number_u_10th(2, bottom_line - 1, naviData.Current, 4, 0); |
write_ndigit_number_u(10, bottom_line - 1, naviData.UsedCapacity, 4, 0); |
} |
/C-OSD/trunk/ppm.c |
---|
18,10 → 18,10 |
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
****************************************************************************/ |
#include "main.h" |
#include <avr/io.h> |
#include <avr/interrupt.h> |
#include "ppm.h" |
#include "main.h" |
#include "max7456_software_spi.h" // clearing |
#if !(ALLCHARSDEBUG|(WRITECHARS != -1)) |
71,7 → 71,7 |
//write_ndigit_number_u(2, 6, valid_ppm_to_go, 100, 0); // debug |
//write_ndigit_number_u(2, 7, COSD_FLAGS_CONFIG, 100, 0); // debug |
PORTC ^= (1 << PC3); |
uptime = ppm; |
//uptime = ppm; |
} |
#endif |
/C-OSD/trunk/spi.c |
---|
18,10 → 18,10 |
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
****************************************************************************/ |
#include "main.h" |
#include <avr/io.h> |
#include <avr/interrupt.h> |
#include "spi.h" |
#include "main.h" |
#if !(ALLCHARSDEBUG|(WRITECHARS != -1)) |
/C-OSD/trunk/usart0.c |
---|
18,15 → 18,15 |
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
****************************************************************************/ |
#include "main.h" |
#include <avr/io.h> |
#include <avr/interrupt.h> |
#include <util/delay.h> |
#include "main.h" |
#include "usart0.h" |
#ifdef ANTENNATRACKTEST |
#ifdef ANTENNATRACKTEST |
#if !(ALLCHARSDEBUG|(WRITECHARS != -1)) |
91,14 → 91,14 |
ISR(SIG_USART0_RECV) { |
uint8_t c; |
// catch the received byte |
c = UDR0; |
c = UDR0; |
// echo |
UDR0 = c; |
} |
UDR0 = c; |
} |
#endif |
#endif |
#endif // ANTENNATRACKTEST |
/C-OSD/trunk/usart1.c |
---|
18,10 → 18,10 |
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
****************************************************************************/ |
#include "main.h" |
#include <avr/io.h> |
#include <avr/interrupt.h> |
#include <util/delay.h> |
#include "main.h" |
#include "usart1.h" |
#if !(ALLCHARSDEBUG|(WRITECHARS != -1)) |
211,43 → 211,42 |
} |
pRxData = &rxd_buffer[3]; |
RxDataLen = ptrOut - 3; |
} |
} |
/** |
* Request Data through usart1 until a answer is received |
*/ |
void usart1_request_blocking(unsigned char answer, const char* message) { |
rxd_buffer[2] = answer + 1; |
while (rxd_buffer[2] != answer) { |
rxd_buffer_locked = 0; |
usart1_EnableTXD(); |
usart1_puts_pgm(message); |
usart1_DisableTXD(); |
static uint8_t wait = 0; |
wait = 0; |
while (rxd_buffer_locked == 0 && wait < 150) { |
wait++; |
_delay_ms(10); |
} |
} |
Decode64(); |
*/ |
void usart1_request_blocking(unsigned char answer, const char* message) { |
rxd_buffer[2] = answer + 1; |
while (rxd_buffer[2] != answer) { |
rxd_buffer_locked = 0; |
usart1_EnableTXD(); |
usart1_puts_pgm(message); |
usart1_DisableTXD(); |
static uint8_t wait = 0; |
wait = 0; |
while (rxd_buffer_locked == 0 && wait < 150) { |
wait++; |
_delay_ms(10); |
} |
} |
Decode64(); |
} |
/** |
* Request UART Redirect from NC to itself |
*/ |
void usart1_request_nc_uart(void) { |
usart1_EnableTXD(); |
usart1_putc(0x1B); |
usart1_putc(0x1B); |
usart1_putc(0x55); |
usart1_putc(0xAA); |
usart1_putc(0x00); |
usart1_DisableTXD(); |
} |
*/ |
void usart1_request_nc_uart(void) { |
usart1_EnableTXD(); |
usart1_putc(0x1B); |
usart1_putc(0x1B); |
usart1_putc(0x55); |
usart1_putc(0xAA); |
usart1_putc(0x00); |
usart1_DisableTXD(); |
} |
/** |
* request Data through USART in special MK format by adding checksum and |
* encode data in modified Base64 |