Skip to content

Commit

Permalink
v1.0.0-alpha3
Browse files Browse the repository at this point in the history
  • Loading branch information
wiredopposite committed Jan 9, 2025
1 parent 7cb0105 commit b3bcbff
Show file tree
Hide file tree
Showing 108 changed files with 4,809 additions and 2,411 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ Firmware/.vscode
Firmware/RP2040/build
Firmware/RP2040/.ignore
Firmware/RP2040/src/USBDevice/DeviceDriver/XboxOG/tud_xid/tud_xid_xremote_rom.h
Firmware/RP2040/src/BLEServer/att_delayed_response.h
Firmware/ESP32/main/BLEServer/att_delayed_response.h
Firmware/ESP32/.ignore
Firmware/ESP32/build
Firmware/ESP32/components/btstack
Expand Down
16 changes: 13 additions & 3 deletions Firmware/ESP32/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
cmake_minimum_required(VERSION 3.5)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

set(EXTERNAL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../external)
set(EXTERNAL_CMAKE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../cmake)
set(BTSTACK_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/components/btstack)

include(${EXTERNAL_DIR}/init_submodules.cmake)
include(${EXTERNAL_DIR}/patch_libs.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/../FWDefines.cmake)
include(${EXTERNAL_CMAKE_DIR}/init_submodules.cmake)
include(${EXTERNAL_CMAKE_DIR}/patch_libs.cmake)
include(${EXTERNAL_CMAKE_DIR}/generate_gatt_header.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/integrate_btstack.cmake)

init_git_submodules(${EXTERNAL_DIR})
apply_lib_patches(${EXTERNAL_DIR})
integrate_btstack(${EXTERNAL_DIR})
generate_gatt_header(
${BTSTACK_ROOT}
${CMAKE_CURRENT_SOURCE_DIR}/../RP2040/src/BLEServer/att_delayed_response.gatt
${CMAKE_CURRENT_SOURCE_DIR}/main/BLEServer/att_delayed_response.h
)

set(BLUEPAD32_ROOT ${EXTERNAL_DIR}/bluepad32/src/components/bluepad32)

Expand All @@ -24,4 +34,4 @@ set(EXTRA_COMPONENT_DIRS
)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(OGX-Mini-ESP32)
project("${FW_NAME}-${FW_VERSION}-ESP32")
82 changes: 82 additions & 0 deletions Firmware/ESP32/main/1btstack_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#ifndef _ESP_BTSTACK_CONFIG_H
#define _ESP_BTSTACK_CONFIG_H

// BTstack features that can be enabled
// #define ENABLE_LE_PERIPHERAL
// #define ENABLE_LE_CENTRAL
// #define ENABLE_L2CAP_LE_CREDIT_BASED_FLOW_CONTROL_MODE
// #define ENABLE_LOG_INFO
// #define ENABLE_LOG_ERROR
// #define ENABLE_PRINTF_HEXDUMP
#define ENABLE_SCO_OVER_HCI

// BTstack configuration. buffers, sizes, ...
#define HCI_OUTGOING_PRE_BUFFER_SIZE 4
#define HCI_ACL_PAYLOAD_SIZE (1691 + 4)
#define HCI_ACL_CHUNK_SIZE_ALIGNMENT 4
// #define MAX_NR_AVDTP_CONNECTIONS 1
// #define MAX_NR_AVDTP_STREAM_ENDPOINTS 1
// #define MAX_NR_AVRCP_CONNECTIONS 2
// #define MAX_NR_BNEP_CHANNELS 1
// #define MAX_NR_BNEP_SERVICES 1
// #define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 2
// #define MAX_NR_GATT_CLIENTS 4
// #define MAX_NR_HCI_CONNECTIONS 4
// #define MAX_NR_HID_HOST_CONNECTIONS 4
// #define MAX_NR_HIDS_CLIENTS 4
// #define MAX_NR_HFP_CONNECTIONS 1
// #define MAX_NR_L2CAP_CHANNELS 6
// #define MAX_NR_L2CAP_SERVICES 5
// #define MAX_NR_RFCOMM_CHANNELS 1
// #define MAX_NR_RFCOMM_MULTIPLEXERS 1
// #define MAX_NR_RFCOMM_SERVICES 1
// #define MAX_NR_SERVICE_RECORD_ITEMS 4
// #define MAX_NR_SM_LOOKUP_ENTRIES 3
// #define MAX_NR_WHITELIST_ENTRIES 16
// #define MAX_NR_LE_DEVICE_DB_ENTRIES 16

// Limit number of ACL/SCO Buffer to use by stack to avoid cyw43 shared bus overrun
#define MAX_NR_CONTROLLER_ACL_BUFFERS 6
#define MAX_NR_CONTROLLER_SCO_PACKETS 6

// Enable and configure HCI Controller to Host Flow Control to avoid cyw43 shared bus overrun
#define ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL
#define HCI_HOST_ACL_PACKET_LEN 1024
#define HCI_HOST_ACL_PACKET_NUM 6
#define HCI_HOST_SCO_PACKET_LEN 120
#define HCI_HOST_SCO_PACKET_NUM 6

#ifndef HCI_INCOMING_PRE_BUFFER_SIZE
#define HCI_INCOMING_PRE_BUFFER_SIZE 6
#endif

// Link Key DB and LE Device DB using TLV on top of Flash Sector interface
// #define NVM_NUM_DEVICE_DB_ENTRIES 16
// #define NVM_NUM_LINK_KEYS 16

// We don't give btstack a malloc, so use a fixed-size ATT DB.
// #define MAX_ATT_DB_SIZE 512
#define HAVE_MALLOC

// BTstack HAL configuration
// #define HAVE_EMBEDDED_TIME_MS

// // map btstack_assert onto Pico SDK assert()
// #define HAVE_ASSERT

// // Some USB dongles take longer to respond to HCI reset (e.g. BCM20702A).
#define HCI_RESET_RESEND_TIMEOUT_MS 1000

// #define ENABLE_SOFTWARE_AES128
// #define ENABLE_MICRO_ECC_FOR_LE_SECURE_CONNECTIONS

// #define HAVE_BTSTACK_STDIN

// To get the audio demos working even with HCI dump at 115200, this truncates long ACL packetws
#define HCI_DUMP_STDOUT_MAX_SIZE_ACL 100

#ifdef ENABLE_CLASSIC
#define ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
#endif

#endif // _ESP_BTSTACK_CONFIG_H
264 changes: 264 additions & 0 deletions Firmware/ESP32/main/BLEServer/BLEServer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
#include <cstring>
#include <string>
#include <esp_ota_ops.h>
#include <esp_system.h>

#include "att_server.h"
#include "btstack.h"

#include "Gamepad.h"
#include "BLEServer/BLEServer.h"
#include "BLEServer/att_delayed_response.h"
#include "UserSettings/UserProfile.h"
#include "UserSettings/UserSettings.h"

namespace BLEServer {

static constexpr uint16_t PACKET_LEN_MAX = 18;

#pragma pack(push, 1)
struct SetupPacket
{
uint8_t max_gamepads{1};
uint8_t index{0};
uint8_t device_type{0};
uint8_t profile_id{1};
};
static_assert(sizeof(SetupPacket) == 4, "BLEServer::SetupPacket struct size mismatch");
#pragma pack(pop)

SetupPacket setup_packet_;

namespace Handle
{
static constexpr uint16_t FW_VERSION = ATT_CHARACTERISTIC_12345678_1234_1234_1234_123456789020_01_VALUE_HANDLE;
static constexpr uint16_t FW_NAME = ATT_CHARACTERISTIC_12345678_1234_1234_1234_123456789021_01_VALUE_HANDLE;

static constexpr uint16_t START_UPDATE = ATT_CHARACTERISTIC_12345678_1234_1234_1234_123456789030_01_VALUE_HANDLE;
static constexpr uint16_t COMMIT_UPDATE = ATT_CHARACTERISTIC_12345678_1234_1234_1234_123456789031_01_VALUE_HANDLE;

static constexpr uint16_t SETUP_PACKET = ATT_CHARACTERISTIC_12345678_1234_1234_1234_123456789040_01_VALUE_HANDLE;
static constexpr uint16_t PROFILE_PT1 = ATT_CHARACTERISTIC_12345678_1234_1234_1234_123456789041_01_VALUE_HANDLE;
static constexpr uint16_t PROFILE_PT2 = ATT_CHARACTERISTIC_12345678_1234_1234_1234_123456789042_01_VALUE_HANDLE;
static constexpr uint16_t PROFILE_PT3 = ATT_CHARACTERISTIC_12345678_1234_1234_1234_123456789043_01_VALUE_HANDLE;
}

namespace ADV
{
// Flags general discoverable, BR/EDR not supported
static const uint8_t FLAGS[] = { 0x02, 0x01, 0x06 };
static const uint8_t NAME_TYPE = 0x09;

#pragma pack(push, 1)
struct Data
{
uint8_t flags[sizeof(FLAGS)];
uint8_t name_len;
uint8_t name_type;
uint8_t name[sizeof(FIRMWARE_NAME) - 1];

Data()
{
std::memcpy(flags, FLAGS, sizeof(flags));
name_len = sizeof(FIRMWARE_NAME);
name_type = NAME_TYPE;
std::memcpy(name, FIRMWARE_NAME, sizeof(name));
}
};
static_assert(sizeof(Data) == 5 + sizeof(FIRMWARE_NAME) - 1, "BLEServer::ADV::Data struct size mismatch");
#pragma pack(pop)
}

static int verify_write(const uint16_t buffer_size, const uint16_t expected_size, bool pending_write = false, bool expected_pending_write = false)
{
if (buffer_size != expected_size)
{
return ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH;
}
if (pending_write != expected_pending_write)
{
return ATT_ERROR_WRITE_NOT_PERMITTED;
}
return 0;
}

static uint16_t att_read_callback( hci_con_handle_t connection_handle,
uint16_t att_handle,
uint16_t offset,
uint8_t *buffer,
uint16_t buffer_size)
{
static UserProfile profile;
SetupPacket setup_packet_resp;
std::string fw_version;
std::string fw_name;

switch (att_handle)
{
case Handle::FW_VERSION:
fw_version = FIRMWARE_VERSION;
if (buffer)
{
std::memcpy(buffer, reinterpret_cast<const uint8_t*>(fw_version.c_str()), fw_version.size());
}
return static_cast<uint16_t>(fw_version.size());

case Handle::FW_NAME:
fw_name = FIRMWARE_NAME;
if (buffer)
{
std::memcpy(buffer, reinterpret_cast<const uint8_t*>(fw_name.c_str()), fw_name.size());
}
return static_cast<uint16_t>(fw_name.size());

case Handle::SETUP_PACKET:
if (buffer)
{
//App has already written a setup packet with the index
setup_packet_resp.max_gamepads = static_cast<uint8_t>(MAX_GAMEPADS);
setup_packet_resp.index = setup_packet_.index;
setup_packet_resp.device_type = static_cast<uint8_t>(UserSettings::get_instance().get_current_driver());
setup_packet_resp.profile_id = UserSettings::get_instance().get_active_profile_id(setup_packet_.index);

std::memcpy(buffer, &setup_packet_resp, sizeof(setup_packet_resp));
}
return sizeof(setup_packet_);

case Handle::PROFILE_PT1:
if (buffer)
{
//App has already written the profile id it wants to the setup packet
profile = UserSettings::get_instance().get_profile_by_id(setup_packet_.profile_id);
std::memcpy(buffer, &profile, PACKET_LEN_MAX);
}
return PACKET_LEN_MAX;

case Handle::PROFILE_PT2:
if (buffer)
{
std::memcpy(buffer, reinterpret_cast<uint8_t*>(&profile) + PACKET_LEN_MAX, PACKET_LEN_MAX);
}
return PACKET_LEN_MAX;

case Handle::PROFILE_PT3:
if (buffer)
{
std::memcpy(buffer, reinterpret_cast<uint8_t*>(&profile) + PACKET_LEN_MAX * 2, sizeof(UserProfile) - PACKET_LEN_MAX * 2);
}
return sizeof(UserProfile) - PACKET_LEN_MAX * 2;

default:
break;
}
return 0;
}

static int att_write_callback(hci_con_handle_t connection_handle,
uint16_t att_handle,
uint16_t transaction_mode,
uint16_t offset,
uint8_t *buffer,
uint16_t buffer_size)
{
static UserProfile temp_profile;
static bool pending_write = false;

int ret = 0;

switch (att_handle)
{
case Handle::START_UPDATE:
pending_write = true;
break;

case Handle::SETUP_PACKET:
if ((ret = verify_write(buffer_size, sizeof(SetupPacket))) != 0)
{
break;
}

std::memcpy(&setup_packet_, buffer, buffer_size);
if (setup_packet_.index >= MAX_GAMEPADS)
{
setup_packet_.index = 0;
ret = ATT_ERROR_OUT_OF_RANGE;
}
if (setup_packet_.profile_id > UserSettings::MAX_PROFILES)
{
setup_packet_.profile_id = 1;
ret = ATT_ERROR_OUT_OF_RANGE;
}
if (ret)
{
break;
}

if (pending_write)
{
//App wants to store a new device driver type
UserSettings::get_instance().store_driver_type(static_cast<DeviceDriverType>(setup_packet_.device_type));
}
break;

case Handle::PROFILE_PT1:
if ((ret = verify_write(buffer_size, PACKET_LEN_MAX, pending_write, true)) != 0)
{
break;
}
std::memcpy(&temp_profile, buffer, buffer_size);
break;

case Handle::PROFILE_PT2:
if ((ret = verify_write(buffer_size, PACKET_LEN_MAX, pending_write, true)) != 0)
{
break;
}
std::memcpy(reinterpret_cast<uint8_t*>(&temp_profile) + PACKET_LEN_MAX, buffer, buffer_size);
break;

case Handle::PROFILE_PT3:
if ((ret = verify_write(buffer_size, sizeof(UserProfile) - PACKET_LEN_MAX * 2, pending_write, true)) != 0)
{
break;
}
std::memcpy(reinterpret_cast<uint8_t*>(&temp_profile) + PACKET_LEN_MAX * 2, buffer, buffer_size);
break;

case Handle::COMMIT_UPDATE:
if ((ret = verify_write(0, 0, pending_write, true)) != 0)
{
break;
}
UserSettings::get_instance().store_profile(setup_packet_.index, temp_profile);
pending_write = false;
break;

default:
break;
}
return ret;
}

void init_server()
{
UserSettings::get_instance().initialize_flash();

// setup ATT server
att_server_init(profile_data, att_read_callback, att_write_callback);

// setup advertisements
uint16_t adv_int_min = 0x0030;
uint16_t adv_int_max = 0x0030;
uint8_t adv_type = 0;

bd_addr_t null_addr;
std::memset(null_addr, 0, sizeof(null_addr));

static ADV::Data adv_data = ADV::Data();

gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00);
gap_advertisements_set_data(static_cast<uint8_t>(sizeof(adv_data)), reinterpret_cast<uint8_t*>(&adv_data));
gap_advertisements_enable(1);
}

} // namespace BLEServer
Loading

0 comments on commit b3bcbff

Please sign in to comment.