Browse Source

Added BLE

master
Englebert 4 years ago
parent
commit
bdf06b62d0
  1. 22
      OpenFlightTX.h
  2. 309
      OpenFlightTX.ino

22
OpenFlightTX.h

@ -0,0 +1,22 @@
#ifndef OPENFLIGHTTX_H_
#define OPENFLIGHTTX_H_
void draw_menu(struct menu_state *state);
void to_right(struct menu_state *state);
void to_left(struct menu_state *state);
uint8_t towards_int16(int16_t *current, int16_t dest);
uint8_t towards(struct menu_state *current, struct menu_state *destination);
void median_initialize(void);
uint16_t median_get(uint8_t median_type);
uint16_t throttle_insert(uint16_t val);
uint16_t yaw_insert(uint16_t val);
uint16_t pitch_insert(uint16_t val);
uint16_t roll_insert(uint16_t val);
uint16_t pool_insert(uint8_t pool_type, uint16_t val);
void intro(void);
void read_all_voltage(void);
void battery_management(void);
void bluetooth_gamepad(void);
#endif

309
OpenFlightTX.ino

@ -1,9 +1,17 @@
/*
* Ref:
* Manual - https://www.seeedstudio.com/blog/2019/07/05/u8g2-for-seeeduino-boards/
* Dual OLED - https://github.com/olikraus/u8g2/issues/77
*/
#include <Arduino.h> #include <Arduino.h>
#include <SPI.h> #include <SPI.h>
#include <LoRa.h> #include <LoRa.h>
#include <U8g2lib.h> #include <U8g2lib.h>
#include <Wire.h> #include <Wire.h>
#include <BleGamepad.h>
BleGamepad bleGamepad;
typedef enum { typedef enum {
SCREEN_INTRO = 0, SCREEN_INTRO = 0,
@ -23,8 +31,10 @@ typedef enum {
#define ICON_GAP 4 #define ICON_GAP 4
#define ICON_BGAP 16 #define ICON_BGAP 16
#define ICON_Y 32+ ICON_GAP #define ICON_Y 32+ ICON_GAP
#define ICONX_Y 64+ ICON_GAP
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2_left(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2_right(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
struct menu_entry_type { struct menu_entry_type {
const uint8_t *font; const uint8_t *font;
@ -39,6 +49,8 @@ struct menu_state {
}; };
struct menu_entry_type menu_entry_alpha_list[] = { struct menu_entry_type menu_entry_alpha_list[] = {
{ u8g2_font_open_iconic_all_4x_t, 184, "Main"},
{ u8g2_font_open_iconic_all_4x_t, 94, "Bluetooth"},
{ u8g2_font_open_iconic_all_4x_t, 129, "Configuration"}, { u8g2_font_open_iconic_all_4x_t, 129, "Configuration"},
{ u8g2_font_open_iconic_all_4x_t, 104, "Debug"}, { u8g2_font_open_iconic_all_4x_t, 104, "Debug"},
{ u8g2_font_open_iconic_all_4x_t, 90, "Battery"}, { u8g2_font_open_iconic_all_4x_t, 90, "Battery"},
@ -46,6 +58,16 @@ struct menu_entry_type menu_entry_alpha_list[] = {
{ NULL, 0, NULL } { NULL, 0, NULL }
}; };
struct menu_entry_type menu_entry_alpha_huge_list[] = {
{ u8g2_font_open_iconic_all_8x_t, 184, "Main"},
{ u8g2_font_open_iconic_all_8x_t, 94, "Bluetooth"},
{ u8g2_font_open_iconic_all_8x_t, 129, "Configuration"},
{ u8g2_font_open_iconic_all_8x_t, 104, "Debug"},
{ u8g2_font_open_iconic_all_8x_t, 90, "Battery"},
{ u8g2_font_open_iconic_all_8x_t, 65, "Exit"},
{ NULL, 0, NULL }
};
struct menu_state current_alpha_state = { ICON_BGAP, ICON_BGAP, 0 }; struct menu_state current_alpha_state = { ICON_BGAP, ICON_BGAP, 0 };
struct menu_state destination_alpha_state = { ICON_BGAP, ICON_BGAP, 0 }; struct menu_state destination_alpha_state = { ICON_BGAP, ICON_BGAP, 0 };
@ -55,26 +77,26 @@ void draw_menu(struct menu_state *state) {
x = state->menu_start; x = state->menu_start;
i = 0; i = 0;
while( menu_entry_alpha_list[i].icon > 0 ) { while( menu_entry_alpha_list[i].icon > 0 ) {
if ( x >= -ICON_WIDTH && x < u8g2.getDisplayWidth()) {
u8g2.setFont(menu_entry_alpha_list[i].font);
u8g2.drawGlyph(x, ICON_Y, menu_entry_alpha_list[i].icon );
if ( x >= -ICON_WIDTH && x < u8g2_left.getDisplayWidth()) {
u8g2_left.setFont(menu_entry_alpha_list[i].font);
u8g2_left.drawGlyph(x, ICON_Y, menu_entry_alpha_list[i].icon );
} }
i++; i++;
x += ICON_WIDTH + ICON_GAP; x += ICON_WIDTH + ICON_GAP;
} }
//u8g2.drawFrame(state->frame_position-1, ICON_Y-ICON_HEIGHT-1, ICON_WIDTH+2, ICON_WIDTH+2);
//u8g2.drawFrame(state->frame_position-2, ICON_Y-ICON_HEIGHT-2, ICON_WIDTH+4, ICON_WIDTH+4);
u8g2.drawFrame(state->frame_position-3, ICON_Y-ICON_HEIGHT-3, ICON_WIDTH+6, ICON_WIDTH+6);
//u8g2_left.drawFrame(state->frame_position-1, ICON_Y-ICON_HEIGHT-1, ICON_WIDTH+2, ICON_WIDTH+2);
//u8g2_left.drawFrame(state->frame_position-2, ICON_Y-ICON_HEIGHT-2, ICON_WIDTH+4, ICON_WIDTH+4);
u8g2_left.drawFrame(state->frame_position-3, ICON_Y-ICON_HEIGHT-3, ICON_WIDTH+6, ICON_WIDTH+6);
} }
void to_right(struct menu_state *state) { void to_right(struct menu_state *state) {
if(menu_entry_alpha_list[state->position+1].font != NULL) { if(menu_entry_alpha_list[state->position+1].font != NULL) {
if((int16_t)state->frame_position+ 2*(int16_t)ICON_WIDTH + (int16_t)ICON_BGAP < (int16_t)u8g2.getDisplayWidth()) {
if((int16_t)state->frame_position+ 2*(int16_t)ICON_WIDTH + (int16_t)ICON_BGAP < (int16_t)u8g2_left.getDisplayWidth()) {
state->position++; state->position++;
state->frame_position += ICON_WIDTH + (int16_t)ICON_GAP; state->frame_position += ICON_WIDTH + (int16_t)ICON_GAP;
} else { } else {
state->position++; state->position++;
state->frame_position = (int16_t)u8g2.getDisplayWidth() - (int16_t)ICON_WIDTH - (int16_t)ICON_BGAP;
state->frame_position = (int16_t)u8g2_left.getDisplayWidth() - (int16_t)ICON_WIDTH - (int16_t)ICON_BGAP;
state->menu_start = state->frame_position - state->position*((int16_t)ICON_WIDTH + (int16_t)ICON_GAP); state->menu_start = state->frame_position - state->position*((int16_t)ICON_WIDTH + (int16_t)ICON_GAP);
} }
} }
@ -131,6 +153,12 @@ typedef enum {
MENU_NAVIGATION stick_navigation_position; MENU_NAVIGATION stick_navigation_position;
bool menu_entry_alpha_selected = false; bool menu_entry_alpha_selected = false;
bool require_unlock = false;
bool ble_begin = false;
uint32_t ble_profiling = 0;
uint32_t ble_profiling_raw = 0;
uint32_t last_seconds = 0;
//define the pins used by the transceiver module //define the pins used by the transceiver module
#define SS 5 #define SS 5
@ -145,15 +173,38 @@ int counter = 0;
#define PITCH_PIN 34 #define PITCH_PIN 34
#define ROLL_PIN 35 #define ROLL_PIN 35
uint16_t throttle_raw = 0;
uint16_t yaw_raw = 0;
uint16_t pitch_raw = 0;
uint16_t roll_raw = 0;
#define VBAT_PIN 32
#define VCC_PIN 33
#define SW1_PIN 25
#define SW2_PIN 26
#define SW3_PIN 27
#define SW4_PIN 14
#define SW5_PIN 12
#define SW6_PIN 13
uint16_t throttle_raw = 0;
uint16_t yaw_raw = 0;
uint16_t pitch_raw = 0;
uint16_t roll_raw = 0;
uint16_t vbat_raw = 0;
uint16_t vcc_raw = 0;
uint16_t throttle_value = 0; uint16_t throttle_value = 0;
uint16_t yaw_value = 0;
uint16_t pitch_value = 0;
uint16_t roll_value = 0;
uint16_t yaw_value = 0;
uint16_t pitch_value = 0;
uint16_t roll_value = 0;
uint64_t vbat_value = 0;
bool sw1 = 0;
bool sw2 = 0;
bool sw3 = 0;
bool sw4 = 0;
bool sw5 = 0;
bool sw6 = 0;
#define MEDIAN_TOTAL 11 #define MEDIAN_TOTAL 11
#define MEDIAN_POS MEDIAN_TOTAL/2 #define MEDIAN_POS MEDIAN_TOTAL/2
@ -163,14 +214,17 @@ uint16_t roll_value = 0;
#define YAW 1 #define YAW 1
#define PITCH 2 #define PITCH 2
#define ROLL 3 #define ROLL 3
#define VBAT 4
uint64_t last_update = 0; uint64_t last_update = 0;
uint16_t last_menu_stick_read = 0;
uint64_t last_menu_stick_read = 0;
uint64_t last_menu_item_moved = 0;
uint16_t throttle_pool[MEDIAN_TOTAL]; uint16_t throttle_pool[MEDIAN_TOTAL];
uint16_t yaw_pool[MEDIAN_TOTAL]; uint16_t yaw_pool[MEDIAN_TOTAL];
uint16_t pitch_pool[MEDIAN_TOTAL]; uint16_t pitch_pool[MEDIAN_TOTAL];
uint16_t roll_pool[MEDIAN_TOTAL]; uint16_t roll_pool[MEDIAN_TOTAL];
uint16_t vbat_pool[MEDIAN_TOTAL];
uint16_t tmp_median_store[MEDIAN_TOTAL]; uint16_t tmp_median_store[MEDIAN_TOTAL];
@ -221,6 +275,8 @@ uint16_t median_get(uint8_t median_type) {
median_tmp[0] = pitch_pool[0]; median_tmp[0] = pitch_pool[0];
} else if(median_type == ROLL) { } else if(median_type == ROLL) {
median_tmp[0] = roll_pool[0]; median_tmp[0] = roll_pool[0];
} else if(median_type == VBAT) {
median_tmp[0] = vbat_pool[0];
} }
// Loop insert and sort // Loop insert and sort
@ -235,6 +291,8 @@ uint16_t median_get(uint8_t median_type) {
temp_val = pitch_pool[raw_count]; temp_val = pitch_pool[raw_count];
} else if(median_type == ROLL) { } else if(median_type == ROLL) {
temp_val = roll_pool[raw_count]; temp_val = roll_pool[raw_count];
} else if(median_type == VBAT) {
temp_val = vbat_pool[raw_count];
} }
for(int median_count = 0; median_count < total_insert; median_count++) { for(int median_count = 0; median_count < total_insert; median_count++) {
@ -334,6 +392,8 @@ uint16_t pool_insert(uint8_t pool_type, uint16_t val) {
pitch_pool[i - 1] = pitch_pool[i]; pitch_pool[i - 1] = pitch_pool[i];
} else if(pool_type == ROLL) { } else if(pool_type == ROLL) {
roll_pool[i - 1] = roll_pool[i]; roll_pool[i - 1] = roll_pool[i];
} else if(pool_type == VBAT) {
vbat_pool[i - 1] = vbat_pool[i];
} }
} }
@ -346,6 +406,8 @@ uint16_t pool_insert(uint8_t pool_type, uint16_t val) {
roll_pool[MEDIAN_TOTAL - 1] = val; roll_pool[MEDIAN_TOTAL - 1] = val;
} else if(pool_type == PITCH) { } else if(pool_type == PITCH) {
pitch_pool[MEDIAN_TOTAL - 1] = val; pitch_pool[MEDIAN_TOTAL - 1] = val;
} else if(pool_type == VBAT) {
vbat_pool[MEDIAN_TOTAL - 1] = val;
} }
return median_get(pool_type); return median_get(pool_type);
} }
@ -366,10 +428,20 @@ void read_all_voltage() {
pitch_raw = analogRead(PITCH_PIN); pitch_raw = analogRead(PITCH_PIN);
roll_raw = analogRead(ROLL_PIN); roll_raw = analogRead(ROLL_PIN);
vbat_raw = analogRead(VBAT_PIN);
sw1 = !digitalRead(SW1_PIN);
sw2 = !digitalRead(SW2_PIN);
sw3 = !digitalRead(SW3_PIN);
sw4 = !digitalRead(SW4_PIN);
sw5 = !digitalRead(SW5_PIN);
sw6 = !digitalRead(SW6_PIN);
throttle_value = pool_insert(THROTTLE, throttle_raw); throttle_value = pool_insert(THROTTLE, throttle_raw);
yaw_value = pool_insert(YAW, yaw_raw); yaw_value = pool_insert(YAW, yaw_raw);
pitch_value = pool_insert(PITCH, pitch_raw); pitch_value = pool_insert(PITCH, pitch_raw);
roll_value = pool_insert(ROLL, roll_raw); roll_value = pool_insert(ROLL, roll_raw);
vbat_value = pool_insert(VBAT, vbat_raw);
} }
@ -378,10 +450,23 @@ void setup() {
// PIN Initialization // PIN Initialization
pinMode(BUZZER_PIN, OUTPUT); pinMode(BUZZER_PIN, OUTPUT);
pinMode(SW1_PIN, INPUT_PULLUP);
pinMode(SW2_PIN, INPUT_PULLUP);
pinMode(SW3_PIN, INPUT_PULLUP);
pinMode(SW4_PIN, INPUT_PULLUP);
pinMode(SW5_PIN, INPUT_PULLUP);
pinMode(SW6_PIN, INPUT_PULLUP);
// Display Setup // Display Setup
u8g2.begin();
u8g2.setFont(u8g2_font_6x12_tr);
u8g2_SetI2CAddress(u8g2_right.getU8g2(), 0x3d*2);
u8g2_left.begin();
u8g2_right.begin();
//Serial.println(u8g2_left.u8g2_GetI2CAddress(u8g2_right));
// u8g2_left.setI2CAddress(0x3C);
//u8g2_left.setFont(u8g2_font_6x12_tr);
u8g2_left.setFont(u8g2_font_6x12_tr);
u8g2_right.setFont(u8g2_font_6x12_tr);
median_initialize(); median_initialize();
@ -418,12 +503,33 @@ void setup() {
Serial.println("LoRa Initializing OK!"); Serial.println("LoRa Initializing OK!");
*/ */
u8g2_right.firstPage();
u8g2_right.setFontMode(1);
// u8g2_right.setFont(u8g2_font_helvB10_tr);
u8g2_right.setFont(u8g2_font_VCR_OSD_tr);
u8g2_right.setCursor(0,15);
u8g2_right.print(F("READY"));
u8g2_right.nextPage();
} }
void loop() { void loop() {
// Each seconds tick
if(millis() > last_seconds) {
ble_profiling = ble_profiling_raw;
ble_profiling_raw = 0;
Serial.println(ble_profiling);
last_seconds = millis() + 1000;
}
read_all_voltage(); read_all_voltage();
// Serial.println(throttle_raw + " : " + yaw_raw); // Serial.println(throttle_raw + " : " + yaw_raw);
/*
Serial.print("T ["); Serial.print("T [");
Serial.print(throttle_raw); Serial.print(throttle_raw);
Serial.print("] Y["); Serial.print("] Y[");
@ -433,6 +539,13 @@ void loop() {
Serial.print("] R["); Serial.print("] R[");
Serial.print(roll_value); Serial.print(roll_value);
Serial.println("]"); Serial.println("]");
Serial.print(sw1);
Serial.print(sw2);
Serial.print(sw3);
Serial.print(sw4);
Serial.print(sw5);
Serial.println(sw6);
*/
if(millis() > last_update) { if(millis() > last_update) {
// Determine stick position // Determine stick position
@ -450,7 +563,7 @@ void loop() {
} }
// Next reading... // Next reading...
last_menu_stick_read = millis() + 250;
last_menu_stick_read = millis() + 200;
} else { } else {
stick_navigation_position = MENU_NONE; stick_navigation_position = MENU_NONE;
} }
@ -466,30 +579,59 @@ void loop() {
} else if(stick_navigation_position == MENU_OK) { } else if(stick_navigation_position == MENU_OK) {
menu_entry_alpha_selected = true; menu_entry_alpha_selected = true;
} }
last_menu_item_moved = millis() + 80;
u8g2.firstPage();
u8g2_left.firstPage();
draw_menu(&current_alpha_state); draw_menu(&current_alpha_state);
u8g2.setFont(u8g2_font_helvB10_tr);
u8g2.setCursor((u8g2.getDisplayWidth()-u8g2.getStrWidth(menu_entry_alpha_list[destination_alpha_state.position].name))/2, u8g2.getDisplayHeight()-5);
u8g2.print(menu_entry_alpha_list[destination_alpha_state.position].name);
u8g2.nextPage();
u8g2_left.setFont(u8g2_font_helvB10_tr);
u8g2_left.setCursor((u8g2_left.getDisplayWidth()-u8g2_left.getStrWidth(menu_entry_alpha_list[destination_alpha_state.position].name))/2, u8g2_left.getDisplayHeight()-5);
u8g2_left.print(menu_entry_alpha_list[destination_alpha_state.position].name);
u8g2_left.nextPage();
towards(&current_alpha_state, &destination_alpha_state); towards(&current_alpha_state, &destination_alpha_state);
} else { } else {
if(stick_navigation_position == MENU_BACK) { if(stick_navigation_position == MENU_BACK) {
menu_entry_alpha_selected = false;
if(require_unlock) {
if(sw6) {
menu_entry_alpha_selected = false;
u8g2_right.clearBuffer();
u8g2_right.sendBuffer();
}
} else {
menu_entry_alpha_selected = false;
u8g2_right.clearBuffer();
u8g2_right.sendBuffer();
}
} else { } else {
u8g2.clearBuffer();
u8g2.setFontMode(1);
u8g2.setFont(u8g2_font_helvB10_tr);
u8g2.setCursor(0,15);
u8g2.print(F("Selected:"));
u8g2.setCursor(0,30);
u8g2.print(F(menu_entry_alpha_list[destination_alpha_state.position].name));
u8g2.sendBuffer();
if(menu_entry_alpha_list[destination_alpha_state.position].name == "Battery") {
require_unlock = false;
battery_management();
} else if(menu_entry_alpha_list[destination_alpha_state.position].name == "Bluetooth") {
require_unlock = true;
bluetooth_gamepad();
}
//// u8g2_right.clearBuffer();
// u8g2_right.setFontMode(1);
// u8g2_right.setFont(u8g2_font_helvB10_tr);
// u8g2_right.setCursor(0,15);
// u8g2_right.print(F("Selected:"));
// u8g2_right.setCursor(0,30);
// u8g2_right.print(F(menu_entry_alpha_list[destination_alpha_state.position].name));
//// u8g2_right.firstPage();
// Based on the selection and do the task
//// u8g2_right.setFont(menu_entry_alpha_huge_list[destination_alpha_state.position].font);
//// u8g2_right.drawGlyph(35, ICONX_Y, menu_entry_alpha_huge_list[destination_alpha_state.position].icon);
//// u8g2_right.nextPage();
//u8g2_right.sendBuffer();
} }
} }
last_update = millis() + 10;
last_update = millis() + 1;
} }
/* /*
@ -511,3 +653,100 @@ void loop() {
//} //}
*/ */
} }
void bluetooth_gamepad() {
u8g2_left.clearBuffer();
u8g2_left.firstPage();
u8g2_left.setFont(menu_entry_alpha_huge_list[destination_alpha_state.position].font);
u8g2_left.drawGlyph(40, ICONX_Y, menu_entry_alpha_huge_list[destination_alpha_state.position].icon);
u8g2_left.nextPage();
u8g2_right.clearBuffer();
u8g2_right.firstPage();
u8g2_right.setFontMode(1);
u8g2_right.setFont(u8g2_font_ImpactBits_tr);
static char buf[6];
int throttle = map(throttle_value, 0, 4096, 127, -127); // Throttle
int yaw = map(yaw_value, 0, 4096, -127, 127); // Yaw
int pitch = map(pitch_value, 0, 4096, 127, -127); // Pitch
int roll = map(roll_value, 0, 4096, -127, 127); // Roll
u8g2_right.setCursor(15,15);
u8g2_right.print(F("Bluetooth PAD"));
u8g2_right.setFont(u8g2_font_TimesNewPixel_tr);
u8g2_right.setCursor(0,30);
u8g2_right.print(F("T:"));
strcpy(buf, ltoa(throttle, buf, 10));
u8g2_right.drawStr(15,30,buf);
u8g2_right.setCursor(0,45);
u8g2_right.print(F("Y:"));
strcpy(buf, ltoa(yaw, buf, 10));
u8g2_right.drawStr(15,45,buf);
u8g2_right.setCursor(60,30);
u8g2_right.print(F("P:"));
strcpy(buf, ltoa(pitch, buf, 10));
u8g2_right.drawStr(75,30,buf);
u8g2_right.setCursor(60,45);
u8g2_right.print(F("R:"));
strcpy(buf, ltoa(roll, buf, 10));
u8g2_right.drawStr(75,45,buf);
u8g2_right.setCursor(0,60);
u8g2_right.print(F("Rate:"));
strcpy(buf, ltoa(ble_profiling, buf, 10));
u8g2_right.drawStr(0,40,buf);
u8g2_right.nextPage();
if(!ble_begin) {
bleGamepad.begin();
ble_begin = true;
}
if(bleGamepad.isConnected()) {
ble_profiling_raw++;
// [YAW, THROTTLE, ROLL, PITCH]
bleGamepad.setAxes(yaw, throttle, roll, pitch, 0, 0, DPAD_CENTERED);
}
}
void battery_management() {
u8g2_left.clearBuffer();
u8g2_left.firstPage();
u8g2_left.setFont(menu_entry_alpha_huge_list[destination_alpha_state.position].font);
u8g2_left.drawGlyph(40, ICONX_Y, menu_entry_alpha_huge_list[destination_alpha_state.position].icon);
u8g2_left.nextPage();
u8g2_right.clearBuffer();
u8g2_right.firstPage();
u8g2_right.setFontMode(1);
u8g2_right.setFont(u8g2_font_VCR_OSD_tr);
static char buf[6];
u8g2_right.setCursor(0,15);
u8g2_right.print(F("VBAT:"));
// u8g2_right.drawStr(45, 15, buf);
// strcpy(buf, ltoa(vbat_value, buf, 10));
// u8g2_right.drawStr(0, 30, buf);
float vbat_real_value = vbat_value * .0012142857;
//strcpy(buf, ltoa(vbat_real_value, buf, 10));
dtostrf(vbat_real_value, 3, 2, buf);
u8g2_right.drawStr(0, 45, buf);
u8g2_right.setCursor(48, 45);
u8g2_right.print(F("V"));
u8g2_right.nextPage();
}
Loading…
Cancel
Save