mirror of
https://github.com/meshtastic/firmware.git
synced 2025-04-25 09:42:35 +00:00
Merge branch 'develop' into master
This commit is contained in:
commit
bf8d8886fd
1
.gitmodules
vendored
1
.gitmodules
vendored
@ -1,3 +1,4 @@
|
||||
[submodule "protobufs"]
|
||||
path = protobufs
|
||||
url = https://github.com/meshtastic/protobufs.git
|
||||
branch = develop
|
||||
|
@ -59,8 +59,8 @@ lib_deps =
|
||||
check_tool = cppcheck
|
||||
check_skip_packages = yes
|
||||
check_flags =
|
||||
--common-flag
|
||||
cppcheck: --enable=--inline-suppr
|
||||
-DAPP_VERSION=1.0.0
|
||||
--suppressions-list=suppressions.txt
|
||||
|
||||
; Common settings for conventional (non Portduino) Arduino targets
|
||||
[arduino_base]
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 6b46e42a656dd3aab74c373e79b70e699eeac834
|
||||
Subproject commit 2954e5b0228c85902c841bfb0f18add43980a2e2
|
@ -50,8 +50,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using namespace meshtastic; /** @todo remove */
|
||||
|
||||
extern bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct);
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
|
||||
@ -67,6 +65,8 @@ namespace graphics
|
||||
static FrameCallback normalFrames[MAX_NUM_NODES + NUM_EXTRA_FRAMES];
|
||||
static uint32_t targetFramerate = IDLE_FRAMERATE;
|
||||
static char btPIN[16] = "888888";
|
||||
|
||||
uint32_t logo_timeout = 5000; // 4 seconds for EACH logo
|
||||
|
||||
// This image definition is here instead of images.h because it's modified dynamically by the drawBattery function
|
||||
uint8_t imgBattery[16] = {0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xE7, 0x3C};
|
||||
@ -944,6 +944,9 @@ void Screen::setup()
|
||||
// Set the utf8 conversion function
|
||||
dispdev.setFontTableLookupFunction(customFontTableLookup);
|
||||
|
||||
if (strlen(oemStore.oem_text) > 0)
|
||||
logo_timeout *= 2;
|
||||
|
||||
// Add frames.
|
||||
static FrameCallback bootFrames[] = {drawBootScreen};
|
||||
static const int bootFrameCount = sizeof(bootFrames) / sizeof(bootFrames[0]);
|
||||
@ -1012,26 +1015,28 @@ int32_t Screen::runOnce()
|
||||
return RUN_SAME;
|
||||
}
|
||||
|
||||
// Show boot screen for first 5 seconds, then switch to normal operation.
|
||||
// Show boot screen for first logo_timeout seconds, then switch to normal operation.
|
||||
// serialSinceMsec adjusts for additional serial wait time during nRF52 bootup
|
||||
static bool showingBootScreen = true;
|
||||
if (showingBootScreen && (millis() > (5000 + serialSinceMsec))) {
|
||||
if (showingBootScreen && (millis() > (logo_timeout + serialSinceMsec))) {
|
||||
DEBUG_MSG("Done with boot screen...\n");
|
||||
stopBootScreen();
|
||||
showingBootScreen = false;
|
||||
}
|
||||
|
||||
// If we have an OEM Boot screen, toggle after 2,5 seconds
|
||||
// If we have an OEM Boot screen, toggle after logo_timeout seconds
|
||||
if (strlen(oemStore.oem_text) > 0) {
|
||||
static bool showingOEMBootScreen = true;
|
||||
if (showingOEMBootScreen && (millis() > (2500 + serialSinceMsec))) {
|
||||
if (showingOEMBootScreen && (millis() > ((logo_timeout / 2) + serialSinceMsec))) {
|
||||
DEBUG_MSG("Switch to OEM screen...\n");
|
||||
// Change frames.
|
||||
static FrameCallback bootOEMFrames[] = {drawOEMBootScreen};
|
||||
static const int bootOEMFrameCount = sizeof(bootOEMFrames) / sizeof(bootOEMFrames[0]);
|
||||
ui.setFrames(bootOEMFrames, bootOEMFrameCount);
|
||||
ui.update();
|
||||
#ifndef USE_EINK
|
||||
ui.update();
|
||||
#endif
|
||||
showingOEMBootScreen = false;
|
||||
}
|
||||
}
|
||||
|
@ -416,7 +416,7 @@ void RadioInterface::applyModemConfig()
|
||||
power = loraConfig.tx_power;
|
||||
assert(myRegion); // Should have been found in init
|
||||
|
||||
if ((power == 0) || (power > myRegion->powerLimit))
|
||||
if ((power == 0) || ((power > myRegion->powerLimit) && !devicestate.owner.is_licensed))
|
||||
power = myRegion->powerLimit;
|
||||
|
||||
if (power == 0)
|
||||
@ -460,7 +460,7 @@ void RadioInterface::limitPower()
|
||||
if (myRegion->powerLimit)
|
||||
maxPower = myRegion->powerLimit;
|
||||
|
||||
if (power > maxPower) {
|
||||
if ((power > maxPower) && !devicestate.owner.is_licensed) {
|
||||
DEBUG_MSG("Lowering transmit power because of regulatory limits\n");
|
||||
power = maxPower;
|
||||
}
|
||||
|
@ -32,7 +32,8 @@ typedef enum _AdminMessage_ModuleConfigType {
|
||||
AdminMessage_ModuleConfigType_STOREFORWARD_CONFIG = 3,
|
||||
AdminMessage_ModuleConfigType_RANGETEST_CONFIG = 4,
|
||||
AdminMessage_ModuleConfigType_TELEMETRY_CONFIG = 5,
|
||||
AdminMessage_ModuleConfigType_CANNEDMSG_CONFIG = 6
|
||||
AdminMessage_ModuleConfigType_CANNEDMSG_CONFIG = 6,
|
||||
AdminMessage_ModuleConfigType_AUDIO_CONFIG = 7
|
||||
} AdminMessage_ModuleConfigType;
|
||||
|
||||
/* Struct definitions */
|
||||
@ -116,8 +117,8 @@ typedef struct _AdminMessage {
|
||||
#define _AdminMessage_ConfigType_ARRAYSIZE ((AdminMessage_ConfigType)(AdminMessage_ConfigType_BLUETOOTH_CONFIG+1))
|
||||
|
||||
#define _AdminMessage_ModuleConfigType_MIN AdminMessage_ModuleConfigType_MQTT_CONFIG
|
||||
#define _AdminMessage_ModuleConfigType_MAX AdminMessage_ModuleConfigType_CANNEDMSG_CONFIG
|
||||
#define _AdminMessage_ModuleConfigType_ARRAYSIZE ((AdminMessage_ModuleConfigType)(AdminMessage_ModuleConfigType_CANNEDMSG_CONFIG+1))
|
||||
#define _AdminMessage_ModuleConfigType_MAX AdminMessage_ModuleConfigType_AUDIO_CONFIG
|
||||
#define _AdminMessage_ModuleConfigType_ARRAYSIZE ((AdminMessage_ModuleConfigType)(AdminMessage_ModuleConfigType_AUDIO_CONFIG+1))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -43,4 +43,3 @@ PB_BIND(Config_BluetoothConfig, Config_BluetoothConfig, AUTO)
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -31,12 +31,6 @@ typedef enum _Config_PositionConfig_PositionFlags {
|
||||
Config_PositionConfig_PositionFlags_SPEED = 512
|
||||
} Config_PositionConfig_PositionFlags;
|
||||
|
||||
typedef enum _Config_NetworkConfig_WiFiMode {
|
||||
Config_NetworkConfig_WiFiMode_CLIENT = 0,
|
||||
Config_NetworkConfig_WiFiMode_ACCESS_POINT = 1,
|
||||
Config_NetworkConfig_WiFiMode_ACCESS_POINT_HIDDEN = 2
|
||||
} Config_NetworkConfig_WiFiMode;
|
||||
|
||||
typedef enum _Config_NetworkConfig_EthMode {
|
||||
Config_NetworkConfig_EthMode_DHCP = 0,
|
||||
Config_NetworkConfig_EthMode_STATIC = 1
|
||||
@ -164,6 +158,7 @@ typedef struct _Config_PowerConfig {
|
||||
|
||||
typedef struct _Config_NetworkConfig {
|
||||
bool wifi_enabled;
|
||||
Config_NetworkConfig_EthMode wifi_mode;
|
||||
char wifi_ssid[33];
|
||||
char wifi_psk[64];
|
||||
char ntp_server[33];
|
||||
@ -196,10 +191,6 @@ typedef struct _Config {
|
||||
#define _Config_PositionConfig_PositionFlags_MAX Config_PositionConfig_PositionFlags_SPEED
|
||||
#define _Config_PositionConfig_PositionFlags_ARRAYSIZE ((Config_PositionConfig_PositionFlags)(Config_PositionConfig_PositionFlags_SPEED+1))
|
||||
|
||||
#define _Config_NetworkConfig_WiFiMode_MIN Config_NetworkConfig_WiFiMode_CLIENT
|
||||
#define _Config_NetworkConfig_WiFiMode_MAX Config_NetworkConfig_WiFiMode_ACCESS_POINT_HIDDEN
|
||||
#define _Config_NetworkConfig_WiFiMode_ARRAYSIZE ((Config_NetworkConfig_WiFiMode)(Config_NetworkConfig_WiFiMode_ACCESS_POINT_HIDDEN+1))
|
||||
|
||||
#define _Config_NetworkConfig_EthMode_MIN Config_NetworkConfig_EthMode_DHCP
|
||||
#define _Config_NetworkConfig_EthMode_MAX Config_NetworkConfig_EthMode_STATIC
|
||||
#define _Config_NetworkConfig_EthMode_ARRAYSIZE ((Config_NetworkConfig_EthMode)(Config_NetworkConfig_EthMode_STATIC+1))
|
||||
@ -238,7 +229,7 @@ extern "C" {
|
||||
#define Config_DeviceConfig_init_default {_Config_DeviceConfig_Role_MIN, 0, 0}
|
||||
#define Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_NetworkConfig_init_default {0, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_default}
|
||||
#define Config_NetworkConfig_init_default {0, _Config_NetworkConfig_EthMode_MIN, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_default}
|
||||
#define Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0}
|
||||
#define Config_DisplayConfig_init_default {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _Config_DisplayConfig_DisplayUnits_MIN, _Config_DisplayConfig_OledType_MIN}
|
||||
#define Config_LoRaConfig_init_default {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, {0, 0, 0}}
|
||||
@ -247,7 +238,7 @@ extern "C" {
|
||||
#define Config_DeviceConfig_init_zero {_Config_DeviceConfig_Role_MIN, 0, 0}
|
||||
#define Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_NetworkConfig_init_zero {0, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_zero}
|
||||
#define Config_NetworkConfig_init_zero {0, _Config_NetworkConfig_EthMode_MIN, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_zero}
|
||||
#define Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0}
|
||||
#define Config_DisplayConfig_init_zero {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _Config_DisplayConfig_DisplayUnits_MIN, _Config_DisplayConfig_OledType_MIN}
|
||||
#define Config_LoRaConfig_init_zero {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, {0, 0, 0}}
|
||||
@ -299,6 +290,7 @@ extern "C" {
|
||||
#define Config_PowerConfig_ls_secs_tag 7
|
||||
#define Config_PowerConfig_min_wake_secs_tag 8
|
||||
#define Config_NetworkConfig_wifi_enabled_tag 1
|
||||
#define Config_NetworkConfig_wifi_mode_tag 2
|
||||
#define Config_NetworkConfig_wifi_ssid_tag 3
|
||||
#define Config_NetworkConfig_wifi_psk_tag 4
|
||||
#define Config_NetworkConfig_ntp_server_tag 5
|
||||
@ -364,6 +356,7 @@ X(a, STATIC, SINGULAR, UINT32, min_wake_secs, 8)
|
||||
|
||||
#define Config_NetworkConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, wifi_enabled, 1) \
|
||||
X(a, STATIC, SINGULAR, UENUM, wifi_mode, 2) \
|
||||
X(a, STATIC, SINGULAR, STRING, wifi_ssid, 3) \
|
||||
X(a, STATIC, SINGULAR, STRING, wifi_psk, 4) \
|
||||
X(a, STATIC, SINGULAR, STRING, ntp_server, 5) \
|
||||
@ -443,10 +436,10 @@ extern const pb_msgdesc_t Config_BluetoothConfig_msg;
|
||||
#define Config_DisplayConfig_size 22
|
||||
#define Config_LoRaConfig_size 68
|
||||
#define Config_NetworkConfig_IpV4Config_size 20
|
||||
#define Config_NetworkConfig_size 161
|
||||
#define Config_NetworkConfig_size 163
|
||||
#define Config_PositionConfig_size 30
|
||||
#define Config_PowerConfig_size 43
|
||||
#define Config_size 164
|
||||
#define Config_size 166
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
@ -66,6 +66,9 @@ typedef struct _LocalModuleConfig {
|
||||
incompatible changes This integer is set at build time and is private to
|
||||
NodeDB.cpp in the device code. */
|
||||
uint32_t version;
|
||||
/* The part of the config that is specific to the Audio module */
|
||||
bool has_audio;
|
||||
ModuleConfig_AudioConfig audio;
|
||||
} LocalModuleConfig;
|
||||
|
||||
|
||||
@ -75,9 +78,9 @@ extern "C" {
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define LocalConfig_init_default {false, Config_DeviceConfig_init_default, false, Config_PositionConfig_init_default, false, Config_PowerConfig_init_default, false, Config_NetworkConfig_init_default, false, Config_DisplayConfig_init_default, false, Config_LoRaConfig_init_default, false, Config_BluetoothConfig_init_default, 0}
|
||||
#define LocalModuleConfig_init_default {false, ModuleConfig_MQTTConfig_init_default, false, ModuleConfig_SerialConfig_init_default, false, ModuleConfig_ExternalNotificationConfig_init_default, false, ModuleConfig_StoreForwardConfig_init_default, false, ModuleConfig_RangeTestConfig_init_default, false, ModuleConfig_TelemetryConfig_init_default, false, ModuleConfig_CannedMessageConfig_init_default, 0}
|
||||
#define LocalModuleConfig_init_default {false, ModuleConfig_MQTTConfig_init_default, false, ModuleConfig_SerialConfig_init_default, false, ModuleConfig_ExternalNotificationConfig_init_default, false, ModuleConfig_StoreForwardConfig_init_default, false, ModuleConfig_RangeTestConfig_init_default, false, ModuleConfig_TelemetryConfig_init_default, false, ModuleConfig_CannedMessageConfig_init_default, 0, false, ModuleConfig_AudioConfig_init_default}
|
||||
#define LocalConfig_init_zero {false, Config_DeviceConfig_init_zero, false, Config_PositionConfig_init_zero, false, Config_PowerConfig_init_zero, false, Config_NetworkConfig_init_zero, false, Config_DisplayConfig_init_zero, false, Config_LoRaConfig_init_zero, false, Config_BluetoothConfig_init_zero, 0}
|
||||
#define LocalModuleConfig_init_zero {false, ModuleConfig_MQTTConfig_init_zero, false, ModuleConfig_SerialConfig_init_zero, false, ModuleConfig_ExternalNotificationConfig_init_zero, false, ModuleConfig_StoreForwardConfig_init_zero, false, ModuleConfig_RangeTestConfig_init_zero, false, ModuleConfig_TelemetryConfig_init_zero, false, ModuleConfig_CannedMessageConfig_init_zero, 0}
|
||||
#define LocalModuleConfig_init_zero {false, ModuleConfig_MQTTConfig_init_zero, false, ModuleConfig_SerialConfig_init_zero, false, ModuleConfig_ExternalNotificationConfig_init_zero, false, ModuleConfig_StoreForwardConfig_init_zero, false, ModuleConfig_RangeTestConfig_init_zero, false, ModuleConfig_TelemetryConfig_init_zero, false, ModuleConfig_CannedMessageConfig_init_zero, 0, false, ModuleConfig_AudioConfig_init_zero}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define LocalConfig_device_tag 1
|
||||
@ -96,6 +99,7 @@ extern "C" {
|
||||
#define LocalModuleConfig_telemetry_tag 6
|
||||
#define LocalModuleConfig_canned_message_tag 7
|
||||
#define LocalModuleConfig_version_tag 8
|
||||
#define LocalModuleConfig_audio_tag 9
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define LocalConfig_FIELDLIST(X, a) \
|
||||
@ -125,7 +129,8 @@ X(a, STATIC, OPTIONAL, MESSAGE, store_forward, 4) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, range_test, 5) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, telemetry, 6) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, canned_message, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, version, 8)
|
||||
X(a, STATIC, SINGULAR, UINT32, version, 8) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, audio, 9)
|
||||
#define LocalModuleConfig_CALLBACK NULL
|
||||
#define LocalModuleConfig_DEFAULT NULL
|
||||
#define LocalModuleConfig_mqtt_MSGTYPE ModuleConfig_MQTTConfig
|
||||
@ -135,6 +140,7 @@ X(a, STATIC, SINGULAR, UINT32, version, 8)
|
||||
#define LocalModuleConfig_range_test_MSGTYPE ModuleConfig_RangeTestConfig
|
||||
#define LocalModuleConfig_telemetry_MSGTYPE ModuleConfig_TelemetryConfig
|
||||
#define LocalModuleConfig_canned_message_MSGTYPE ModuleConfig_CannedMessageConfig
|
||||
#define LocalModuleConfig_audio_MSGTYPE ModuleConfig_AudioConfig
|
||||
|
||||
extern const pb_msgdesc_t LocalConfig_msg;
|
||||
extern const pb_msgdesc_t LocalModuleConfig_msg;
|
||||
@ -144,8 +150,8 @@ extern const pb_msgdesc_t LocalModuleConfig_msg;
|
||||
#define LocalModuleConfig_fields &LocalModuleConfig_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define LocalConfig_size 361
|
||||
#define LocalModuleConfig_size 270
|
||||
#define LocalConfig_size 363
|
||||
#define LocalModuleConfig_size 294
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
@ -12,6 +12,9 @@ PB_BIND(ModuleConfig, ModuleConfig, AUTO)
|
||||
PB_BIND(ModuleConfig_MQTTConfig, ModuleConfig_MQTTConfig, AUTO)
|
||||
|
||||
|
||||
PB_BIND(ModuleConfig_AudioConfig, ModuleConfig_AudioConfig, AUTO)
|
||||
|
||||
|
||||
PB_BIND(ModuleConfig_SerialConfig, ModuleConfig_SerialConfig, AUTO)
|
||||
|
||||
|
||||
@ -34,3 +37,4 @@ PB_BIND(ModuleConfig_CannedMessageConfig, ModuleConfig_CannedMessageConfig, AUTO
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -10,6 +10,18 @@
|
||||
#endif
|
||||
|
||||
/* Enum definitions */
|
||||
typedef enum _ModuleConfig_AudioConfig_Audio_Baud {
|
||||
ModuleConfig_AudioConfig_Audio_Baud_CODEC2_DEFAULT = 0,
|
||||
ModuleConfig_AudioConfig_Audio_Baud_CODEC2_3200 = 1,
|
||||
ModuleConfig_AudioConfig_Audio_Baud_CODEC2_2400 = 2,
|
||||
ModuleConfig_AudioConfig_Audio_Baud_CODEC2_1600 = 3,
|
||||
ModuleConfig_AudioConfig_Audio_Baud_CODEC2_1400 = 4,
|
||||
ModuleConfig_AudioConfig_Audio_Baud_CODEC2_1300 = 5,
|
||||
ModuleConfig_AudioConfig_Audio_Baud_CODEC2_1200 = 6,
|
||||
ModuleConfig_AudioConfig_Audio_Baud_CODEC2_700 = 7,
|
||||
ModuleConfig_AudioConfig_Audio_Baud_CODEC2_700B = 8
|
||||
} ModuleConfig_AudioConfig_Audio_Baud;
|
||||
|
||||
typedef enum _ModuleConfig_SerialConfig_Serial_Baud {
|
||||
ModuleConfig_SerialConfig_Serial_Baud_BAUD_DEFAULT = 0,
|
||||
ModuleConfig_SerialConfig_Serial_Baud_BAUD_110 = 1,
|
||||
@ -49,6 +61,14 @@ typedef enum _ModuleConfig_CannedMessageConfig_InputEventChar {
|
||||
} ModuleConfig_CannedMessageConfig_InputEventChar;
|
||||
|
||||
/* Struct definitions */
|
||||
typedef struct _ModuleConfig_AudioConfig {
|
||||
bool codec2_enabled;
|
||||
uint32_t mic_chan;
|
||||
uint32_t amp_pin;
|
||||
uint32_t ptt_pin;
|
||||
ModuleConfig_AudioConfig_Audio_Baud bitrate;
|
||||
} ModuleConfig_AudioConfig;
|
||||
|
||||
typedef struct _ModuleConfig_CannedMessageConfig {
|
||||
bool rotary1_enabled;
|
||||
uint32_t inputbroker_pin_a;
|
||||
@ -131,11 +151,17 @@ typedef struct _ModuleConfig {
|
||||
ModuleConfig_TelemetryConfig telemetry;
|
||||
/* TODO: REPLACE */
|
||||
ModuleConfig_CannedMessageConfig canned_message;
|
||||
/* TODO: REPLACE */
|
||||
ModuleConfig_AudioConfig audio;
|
||||
} payload_variant;
|
||||
} ModuleConfig;
|
||||
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _ModuleConfig_AudioConfig_Audio_Baud_MIN ModuleConfig_AudioConfig_Audio_Baud_CODEC2_DEFAULT
|
||||
#define _ModuleConfig_AudioConfig_Audio_Baud_MAX ModuleConfig_AudioConfig_Audio_Baud_CODEC2_700B
|
||||
#define _ModuleConfig_AudioConfig_Audio_Baud_ARRAYSIZE ((ModuleConfig_AudioConfig_Audio_Baud)(ModuleConfig_AudioConfig_Audio_Baud_CODEC2_700B+1))
|
||||
|
||||
#define _ModuleConfig_SerialConfig_Serial_Baud_MIN ModuleConfig_SerialConfig_Serial_Baud_BAUD_DEFAULT
|
||||
#define _ModuleConfig_SerialConfig_Serial_Baud_MAX ModuleConfig_SerialConfig_Serial_Baud_BAUD_921600
|
||||
#define _ModuleConfig_SerialConfig_Serial_Baud_ARRAYSIZE ((ModuleConfig_SerialConfig_Serial_Baud)(ModuleConfig_SerialConfig_Serial_Baud_BAUD_921600+1))
|
||||
@ -156,6 +182,7 @@ extern "C" {
|
||||
/* Initializer values for message structs */
|
||||
#define ModuleConfig_init_default {0, {ModuleConfig_MQTTConfig_init_default}}
|
||||
#define ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0}
|
||||
#define ModuleConfig_AudioConfig_init_default {0, 0, 0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN}
|
||||
#define ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN}
|
||||
#define ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0}
|
||||
#define ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0}
|
||||
@ -164,6 +191,7 @@ extern "C" {
|
||||
#define ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
|
||||
#define ModuleConfig_init_zero {0, {ModuleConfig_MQTTConfig_init_zero}}
|
||||
#define ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0}
|
||||
#define ModuleConfig_AudioConfig_init_zero {0, 0, 0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN}
|
||||
#define ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN}
|
||||
#define ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0}
|
||||
#define ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0}
|
||||
@ -172,6 +200,11 @@ extern "C" {
|
||||
#define ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define ModuleConfig_AudioConfig_codec2_enabled_tag 1
|
||||
#define ModuleConfig_AudioConfig_mic_chan_tag 2
|
||||
#define ModuleConfig_AudioConfig_amp_pin_tag 3
|
||||
#define ModuleConfig_AudioConfig_ptt_pin_tag 4
|
||||
#define ModuleConfig_AudioConfig_bitrate_tag 5
|
||||
#define ModuleConfig_CannedMessageConfig_rotary1_enabled_tag 1
|
||||
#define ModuleConfig_CannedMessageConfig_inputbroker_pin_a_tag 2
|
||||
#define ModuleConfig_CannedMessageConfig_inputbroker_pin_b_tag 3
|
||||
@ -222,6 +255,7 @@ extern "C" {
|
||||
#define ModuleConfig_range_test_tag 5
|
||||
#define ModuleConfig_telemetry_tag 6
|
||||
#define ModuleConfig_canned_message_tag 7
|
||||
#define ModuleConfig_audio_tag 8
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define ModuleConfig_FIELDLIST(X, a) \
|
||||
@ -231,7 +265,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,external_notification,payloa
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,store_forward,payload_variant.store_forward), 4) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,range_test,payload_variant.range_test), 5) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,telemetry,payload_variant.telemetry), 6) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,canned_message,payload_variant.canned_message), 7)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,canned_message,payload_variant.canned_message), 7) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,audio,payload_variant.audio), 8)
|
||||
#define ModuleConfig_CALLBACK NULL
|
||||
#define ModuleConfig_DEFAULT NULL
|
||||
#define ModuleConfig_payload_variant_mqtt_MSGTYPE ModuleConfig_MQTTConfig
|
||||
@ -241,6 +276,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,canned_message,payload_varia
|
||||
#define ModuleConfig_payload_variant_range_test_MSGTYPE ModuleConfig_RangeTestConfig
|
||||
#define ModuleConfig_payload_variant_telemetry_MSGTYPE ModuleConfig_TelemetryConfig
|
||||
#define ModuleConfig_payload_variant_canned_message_MSGTYPE ModuleConfig_CannedMessageConfig
|
||||
#define ModuleConfig_payload_variant_audio_MSGTYPE ModuleConfig_AudioConfig
|
||||
|
||||
#define ModuleConfig_MQTTConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
|
||||
@ -252,6 +288,15 @@ X(a, STATIC, SINGULAR, BOOL, json_enabled, 6)
|
||||
#define ModuleConfig_MQTTConfig_CALLBACK NULL
|
||||
#define ModuleConfig_MQTTConfig_DEFAULT NULL
|
||||
|
||||
#define ModuleConfig_AudioConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, codec2_enabled, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, mic_chan, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, amp_pin, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, ptt_pin, 4) \
|
||||
X(a, STATIC, SINGULAR, UENUM, bitrate, 5)
|
||||
#define ModuleConfig_AudioConfig_CALLBACK NULL
|
||||
#define ModuleConfig_AudioConfig_DEFAULT NULL
|
||||
|
||||
#define ModuleConfig_SerialConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, echo, 2) \
|
||||
@ -315,6 +360,7 @@ X(a, STATIC, SINGULAR, BOOL, send_bell, 11)
|
||||
|
||||
extern const pb_msgdesc_t ModuleConfig_msg;
|
||||
extern const pb_msgdesc_t ModuleConfig_MQTTConfig_msg;
|
||||
extern const pb_msgdesc_t ModuleConfig_AudioConfig_msg;
|
||||
extern const pb_msgdesc_t ModuleConfig_SerialConfig_msg;
|
||||
extern const pb_msgdesc_t ModuleConfig_ExternalNotificationConfig_msg;
|
||||
extern const pb_msgdesc_t ModuleConfig_StoreForwardConfig_msg;
|
||||
@ -325,6 +371,7 @@ extern const pb_msgdesc_t ModuleConfig_CannedMessageConfig_msg;
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define ModuleConfig_fields &ModuleConfig_msg
|
||||
#define ModuleConfig_MQTTConfig_fields &ModuleConfig_MQTTConfig_msg
|
||||
#define ModuleConfig_AudioConfig_fields &ModuleConfig_AudioConfig_msg
|
||||
#define ModuleConfig_SerialConfig_fields &ModuleConfig_SerialConfig_msg
|
||||
#define ModuleConfig_ExternalNotificationConfig_fields &ModuleConfig_ExternalNotificationConfig_msg
|
||||
#define ModuleConfig_StoreForwardConfig_fields &ModuleConfig_StoreForwardConfig_msg
|
||||
@ -333,6 +380,7 @@ extern const pb_msgdesc_t ModuleConfig_CannedMessageConfig_msg;
|
||||
#define ModuleConfig_CannedMessageConfig_fields &ModuleConfig_CannedMessageConfig_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define ModuleConfig_AudioConfig_size 22
|
||||
#define ModuleConfig_CannedMessageConfig_size 49
|
||||
#define ModuleConfig_ExternalNotificationConfig_size 20
|
||||
#define ModuleConfig_MQTTConfig_size 105
|
||||
|
@ -51,6 +51,9 @@ typedef enum _PortNum {
|
||||
/* Waypoint payloads.
|
||||
Payload is a [Waypoint](/docs/developers/protobufs/api#waypoint) message */
|
||||
PortNum_WAYPOINT_APP = 8,
|
||||
/* Audio Payloads.
|
||||
Encapsulated codec2 packets. On 2.4 GHZ Bandwidths only for now */
|
||||
PortNum_AUDIO_APP = 9,
|
||||
/* Provides a 'ping' service that replies to any packet it receives.
|
||||
Also serves as a small example module. */
|
||||
PortNum_REPLY_APP = 32,
|
||||
|
@ -169,6 +169,11 @@ bool initWifi()
|
||||
WiFi.mode(WIFI_MODE_STA);
|
||||
WiFi.setHostname(ourHost);
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
WiFi.setAutoReconnect(true);
|
||||
WiFi.setSleep(false);
|
||||
if (config.network.wifi_mode == Config_NetworkConfig_EthMode_STATIC && config.network.ipv4_config.ip != 0) {
|
||||
WiFi.config(config.network.ipv4_config.ip,config.network.ipv4_config.gateway,config.network.ipv4_config.subnet,config.network.ipv4_config.dns,config.network.ipv4_config.dns);
|
||||
}
|
||||
|
||||
// This is needed to improve performance.
|
||||
esp_wifi_set_ps(WIFI_PS_NONE); // Disable radio power saving
|
||||
@ -222,8 +227,6 @@ static void WiFiEvent(WiFiEvent_t event)
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||
DEBUG_MSG("Disconnected from WiFi access point\n");
|
||||
// Event 5
|
||||
|
||||
needReconnect = true;
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_AUTHMODE_CHANGE:
|
||||
@ -236,6 +239,7 @@ static void WiFiEvent(WiFiEvent_t event)
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_LOST_IP:
|
||||
DEBUG_MSG("Lost IP address and IP address is reset to 0\n");
|
||||
needReconnect = true;
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_WPS_ER_SUCCESS:
|
||||
DEBUG_MSG("WiFi Protected Setup (WPS): succeeded in enrollee mode\n");
|
||||
@ -251,7 +255,6 @@ static void WiFiEvent(WiFiEvent_t event)
|
||||
break;
|
||||
case SYSTEM_EVENT_AP_START:
|
||||
DEBUG_MSG("WiFi access point started\n");
|
||||
|
||||
onNetworkConnected();
|
||||
break;
|
||||
case SYSTEM_EVENT_AP_STOP:
|
||||
|
@ -19,6 +19,9 @@
|
||||
#ifdef ARCH_ESP32
|
||||
#include "modules/esp32/RangeTestModule.h"
|
||||
#include "modules/esp32/StoreForwardModule.h"
|
||||
#ifdef USE_SX1280
|
||||
#include "modules/esp32/AudioModule.h"
|
||||
#endif
|
||||
#endif
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52)
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
@ -65,17 +68,16 @@ void setupModules()
|
||||
#endif
|
||||
#ifdef ARCH_ESP32
|
||||
// Only run on an esp32 based device.
|
||||
|
||||
/*
|
||||
Maintained by MC Hamster (Jm Casler) jm@casler.org
|
||||
*/
|
||||
#ifdef USE_SX1280
|
||||
new AudioModule();
|
||||
#endif
|
||||
new ExternalNotificationModule();
|
||||
|
||||
storeForwardModule = new StoreForwardModule();
|
||||
|
||||
new RangeTestModule();
|
||||
#elif defined(ARCH_NRF52)
|
||||
new ExternalNotificationModule();
|
||||
new ExternalNotificationModule();
|
||||
#endif
|
||||
|
||||
// NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra acks
|
||||
|
@ -16,6 +16,14 @@ int32_t BME280Sensor::runOnce() {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
status = bme280.begin(nodeTelemetrySensorsMap[sensorType]);
|
||||
|
||||
bme280.setSampling( Adafruit_BME280::MODE_FORCED,
|
||||
Adafruit_BME280::SAMPLING_X1, // Temp. oversampling
|
||||
Adafruit_BME280::SAMPLING_X1, // Pressure oversampling
|
||||
Adafruit_BME280::SAMPLING_X1, // Humidity oversampling
|
||||
Adafruit_BME280::FILTER_OFF,
|
||||
Adafruit_BME280::STANDBY_MS_1000);
|
||||
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
@ -23,6 +31,7 @@ void BME280Sensor::setup() { }
|
||||
|
||||
bool BME280Sensor::getMetrics(Telemetry *measurement) {
|
||||
DEBUG_MSG("BME280Sensor::getMetrics\n");
|
||||
bme280.takeForcedMeasurement();
|
||||
measurement->variant.environment_metrics.temperature = bme280.readTemperature();
|
||||
measurement->variant.environment_metrics.relative_humidity = bme280.readHumidity();
|
||||
measurement->variant.environment_metrics.barometric_pressure = bme280.readPressure() / 100.0F;
|
||||
|
@ -14,25 +14,19 @@ int32_t BME680Sensor::runOnce() {
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
status = bme680.begin(nodeTelemetrySensorsMap[sensorType]);
|
||||
status = bme680.begin(nodeTelemetrySensorsMap[sensorType]);
|
||||
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void BME680Sensor::setup()
|
||||
{
|
||||
// Set up oversampling and filter initialization
|
||||
bme680.setTemperatureOversampling(BME680_OS_8X);
|
||||
bme680.setHumidityOversampling(BME680_OS_2X);
|
||||
bme680.setPressureOversampling(BME680_OS_4X);
|
||||
bme680.setIIRFilterSize(BME680_FILTER_SIZE_3);
|
||||
bme680.setGasHeater(320, 150); // 320*C for 150 ms
|
||||
}
|
||||
void BME680Sensor::setup() { }
|
||||
|
||||
bool BME680Sensor::getMetrics(Telemetry *measurement) {
|
||||
measurement->variant.environment_metrics.temperature = bme680.readTemperature();
|
||||
measurement->variant.environment_metrics.relative_humidity = bme680.readHumidity();
|
||||
measurement->variant.environment_metrics.barometric_pressure = bme680.readPressure() / 100.0F;
|
||||
measurement->variant.environment_metrics.gas_resistance = bme680.readGas() / 1000.0;
|
||||
bme680.performReading();
|
||||
measurement->variant.environment_metrics.temperature = bme680.temperature;
|
||||
measurement->variant.environment_metrics.relative_humidity = bme680.humidity;
|
||||
measurement->variant.environment_metrics.barometric_pressure = bme680.pressure / 100.0F;
|
||||
measurement->variant.environment_metrics.gas_resistance = bme680.gas_resistance / 1000.0;
|
||||
|
||||
return true;
|
||||
}
|
@ -16,6 +16,13 @@ int32_t BMP280Sensor::runOnce() {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
status = bmp280.begin(nodeTelemetrySensorsMap[sensorType]);
|
||||
|
||||
bmp280.setSampling( Adafruit_BMP280::MODE_FORCED,
|
||||
Adafruit_BMP280::SAMPLING_X1, // Temp. oversampling
|
||||
Adafruit_BMP280::SAMPLING_X1, // Pressure oversampling
|
||||
Adafruit_BMP280::FILTER_OFF,
|
||||
Adafruit_BMP280::STANDBY_MS_1000);
|
||||
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
@ -23,6 +30,7 @@ void BMP280Sensor::setup() { }
|
||||
|
||||
bool BMP280Sensor::getMetrics(Telemetry *measurement) {
|
||||
DEBUG_MSG("BMP280Sensor::getMetrics\n");
|
||||
bmp280.takeForcedMeasurement();
|
||||
measurement->variant.environment_metrics.temperature = bmp280.readTemperature();
|
||||
measurement->variant.environment_metrics.barometric_pressure = bmp280.readPressure() / 100.0F;
|
||||
|
||||
|
240
src/modules/esp32/AudioModule.cpp
Normal file
240
src/modules/esp32/AudioModule.cpp
Normal file
@ -0,0 +1,240 @@
|
||||
#include "configuration.h"
|
||||
#include "AudioModule.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
#include "Router.h"
|
||||
#include "FSCommon.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
AudioModule
|
||||
A interface to send raw codec2 audio data over the mesh network. Based on the example code from the ESP32_codec2 project.
|
||||
https://github.com/deulis/ESP32_Codec2
|
||||
|
||||
Codec 2 is a low-bitrate speech audio codec (speech coding)
|
||||
that is patent free and open source develop by David Grant Rowe.
|
||||
http://www.rowetel.com/ and https://github.com/drowe67/codec2
|
||||
|
||||
Basic Usage:
|
||||
1) Enable the module by setting audio.codec2_enabled to 1.
|
||||
2) Set the pins (audio.mic_pin / audio.amp_pin) for your preferred microphone and amplifier GPIO pins.
|
||||
On tbeam, recommend to use:
|
||||
audio.mic_chan 7 (GPIO 35)
|
||||
audio.amp_pin 25 (GPIO 25)
|
||||
3) Set audio.timeout to the amount of time to wait before we consider
|
||||
your voice stream as "done".
|
||||
4) Set audio.bitrate to the desired codec2 rate (CODEC2_3200, CODEC2_2400, CODEC2_1600, CODEC2_1400, CODEC2_1300, CODEC2_1200, CODEC2_700, CODEC2_700B)
|
||||
|
||||
KNOWN PROBLEMS
|
||||
* Until the module is initilized by the startup sequence, the amp_pin pin is in a floating
|
||||
state. This may produce a bit of "noise".
|
||||
* Will not work on NRF and the Linux device targets.
|
||||
*/
|
||||
|
||||
#define AMIC 7
|
||||
#define AAMP 25
|
||||
#define PTT_PIN 39
|
||||
|
||||
#define AUDIO_MODULE_RX_BUFFER 128
|
||||
#define AUDIO_MODULE_DATA_MAX Constants_DATA_PAYLOAD_LEN
|
||||
#define AUDIO_MODULE_MODE 7 // 700B
|
||||
#define AUDIO_MODULE_ACK 1
|
||||
|
||||
#if defined(ARCH_ESP32) && defined(USE_SX1280)
|
||||
|
||||
AudioModule *audioModule;
|
||||
|
||||
ButterworthFilter hp_filter(240, 8000, ButterworthFilter::ButterworthFilter::Highpass, 1);
|
||||
|
||||
//int16_t 1KHz sine test tone
|
||||
int16_t Sine1KHz[8] = { -21210 , -30000, -21210, 0 , 21210 , 30000 , 21210, 0 };
|
||||
int Sine1KHz_index = 0;
|
||||
|
||||
uint8_t rx_raw_audio_value = 127;
|
||||
|
||||
AudioModule::AudioModule() : SinglePortModule("AudioModule", PortNum_AUDIO_APP), concurrency::OSThread("AudioModule") {
|
||||
audio_fifo.init();
|
||||
}
|
||||
|
||||
void AudioModule::run_codec2()
|
||||
{
|
||||
if (state == State::tx)
|
||||
{
|
||||
for (int i = 0; i < ADC_BUFFER_SIZE; i++)
|
||||
speech[i] = (int16_t)hp_filter.Update((float)speech[i]);
|
||||
|
||||
codec2_encode(codec2_state, tx_encode_frame + tx_encode_frame_index, speech);
|
||||
|
||||
//increment the pointer where the encoded frame must be saved
|
||||
tx_encode_frame_index += 8;
|
||||
|
||||
//If it is the 5th time then we have a ready trasnmission frame
|
||||
if (tx_encode_frame_index == ENCODE_FRAME_SIZE)
|
||||
{
|
||||
tx_encode_frame_index = 0;
|
||||
//Transmit it
|
||||
sendPayload();
|
||||
}
|
||||
}
|
||||
if (state == State::rx) //Receiving
|
||||
{
|
||||
//Make a cycle to get each codec2 frame from the received frame
|
||||
for (int i = 0; i < ENCODE_FRAME_SIZE; i += 8)
|
||||
{
|
||||
//Decode the codec2 frame
|
||||
codec2_decode(codec2_state, output_buffer, rx_encode_frame + i);
|
||||
|
||||
// Add to the audio buffer the 320 samples resulting of the decode of the codec2 frame.
|
||||
for (int g = 0; g < ADC_BUFFER_SIZE; g++)
|
||||
audio_fifo.put(output_buffer[g]);
|
||||
}
|
||||
}
|
||||
state = State::standby;
|
||||
}
|
||||
|
||||
void AudioModule::handleInterrupt()
|
||||
{
|
||||
audioModule->onTimer();
|
||||
}
|
||||
|
||||
void AudioModule::onTimer()
|
||||
{
|
||||
if (state == State::tx) {
|
||||
adc_buffer[adc_buffer_index++] = (16 * adc1_get_raw(mic_chan)) - 32768;
|
||||
|
||||
//If you want to test with a 1KHz tone, comment the line above and descomment the three lines below
|
||||
|
||||
// adc_buffer[adc_buffer_index++] = Sine1KHz[Sine1KHz_index++];
|
||||
// if (Sine1KHz_index >= 8)
|
||||
// Sine1KHz_index = 0;
|
||||
|
||||
if (adc_buffer_index == ADC_BUFFER_SIZE) {
|
||||
adc_buffer_index = 0;
|
||||
memcpy((void*)speech, (void*)adc_buffer, 2 * ADC_BUFFER_SIZE);
|
||||
audioModule->setIntervalFromNow(0); // process buffer immediately
|
||||
}
|
||||
} else if (state == State::rx) {
|
||||
|
||||
int16_t v;
|
||||
|
||||
//Get a value from audio_fifo and convert it to 0 - 255 to play it in the ADC
|
||||
//If none value is available the DAC will play the last one that was read, that's
|
||||
//why the rx_raw_audio_value variable is a global one.
|
||||
if (audio_fifo.get(&v))
|
||||
rx_raw_audio_value = (uint8_t)((v + 32768) / 256);
|
||||
|
||||
//Play
|
||||
dacWrite(moduleConfig.audio.amp_pin ? moduleConfig.audio.amp_pin : AAMP, rx_raw_audio_value);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t AudioModule::runOnce()
|
||||
{
|
||||
if (moduleConfig.audio.codec2_enabled) {
|
||||
|
||||
if (firstTime) {
|
||||
|
||||
DEBUG_MSG("Initializing ADC on Channel %u\n", moduleConfig.audio.mic_chan ? moduleConfig.audio.mic_chan : AMIC);
|
||||
|
||||
mic_chan = moduleConfig.audio.mic_chan ? (adc1_channel_t)(int)moduleConfig.audio.mic_chan : (adc1_channel_t)AMIC;
|
||||
adc1_config_width(ADC_WIDTH_12Bit);
|
||||
adc1_config_channel_atten(mic_chan, ADC_ATTEN_DB_6);
|
||||
|
||||
// Start a timer at 8kHz to sample the ADC and play the audio on the DAC.
|
||||
uint32_t cpufreq = getCpuFrequencyMhz();
|
||||
switch (cpufreq){
|
||||
case 160:
|
||||
adcTimer = timerBegin(3, 1000, true); // 160 MHz / 1000 = 160KHz
|
||||
break;
|
||||
case 240:
|
||||
adcTimer = timerBegin(3, 1500, true); // 240 MHz / 1500 = 160KHz
|
||||
break;
|
||||
case 320:
|
||||
adcTimer = timerBegin(3, 2000, true); // 320 MHz / 2000 = 160KHz
|
||||
break;
|
||||
case 80:
|
||||
default:
|
||||
adcTimer = timerBegin(3, 500, true); // 80 MHz / 500 = 160KHz
|
||||
break;
|
||||
}
|
||||
timerAttachInterrupt(adcTimer, &AudioModule::handleInterrupt, true);
|
||||
timerAlarmWrite(adcTimer, 20, true); // Interrupts when counter == 20, 8.000 times a second
|
||||
timerAlarmEnable(adcTimer);
|
||||
|
||||
DEBUG_MSG("Initializing DAC on Pin %u\n", moduleConfig.audio.amp_pin ? moduleConfig.audio.amp_pin : AAMP);
|
||||
DEBUG_MSG("Initializing PTT on Pin %u\n", moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN);
|
||||
|
||||
// Configure PTT input
|
||||
pinMode(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN, INPUT_PULLUP);
|
||||
|
||||
state = State::rx;
|
||||
|
||||
DEBUG_MSG("Setting up codec2 in mode %u\n", moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE);
|
||||
|
||||
codec2_state = codec2_create(moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE);
|
||||
codec2_set_lpc_post_filter(codec2_state, 1, 0, 0.8, 0.2);
|
||||
|
||||
firstTime = 0;
|
||||
} else {
|
||||
// Check if we have a PTT press
|
||||
if (digitalRead(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN) == LOW) {
|
||||
// PTT pressed, recording
|
||||
state = State::tx;
|
||||
}
|
||||
if (state != State::standby) {
|
||||
run_codec2();
|
||||
}
|
||||
}
|
||||
|
||||
return 100;
|
||||
} else {
|
||||
DEBUG_MSG("Audio Module Disabled\n");
|
||||
|
||||
return INT32_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
MeshPacket *AudioModule::allocReply()
|
||||
{
|
||||
|
||||
auto reply = allocDataPacket(); // Allocate a packet for sending
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
void AudioModule::sendPayload(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
MeshPacket *p = allocReply();
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
|
||||
p->want_ack = AUDIO_MODULE_ACK;
|
||||
|
||||
p->decoded.payload.size = ENCODE_FRAME_SIZE;
|
||||
memcpy(p->decoded.payload.bytes, tx_encode_frame, p->decoded.payload.size);
|
||||
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
ProcessMessage AudioModule::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
if (moduleConfig.audio.codec2_enabled) {
|
||||
auto &p = mp.decoded;
|
||||
if (getFrom(&mp) != nodeDB.getNodeNum()) {
|
||||
if (p.payload.size == ENCODE_FRAME_SIZE) {
|
||||
memcpy(rx_encode_frame, p.payload.bytes, p.payload.size);
|
||||
state = State::rx;
|
||||
audioModule->setIntervalFromNow(0);
|
||||
run_codec2();
|
||||
} else {
|
||||
DEBUG_MSG("Invalid payload size %u != %u\n", p.payload.size, ENCODE_FRAME_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ProcessMessage::CONTINUE;
|
||||
}
|
||||
|
||||
#endif
|
68
src/modules/esp32/AudioModule.h
Normal file
68
src/modules/esp32/AudioModule.h
Normal file
@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include "SinglePortModule.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
#include "NodeDB.h"
|
||||
#include <Arduino.h>
|
||||
#include <driver/adc.h>
|
||||
#include <functional>
|
||||
#if defined(ARCH_ESP32) && defined(USE_SX1280)
|
||||
#include <codec2.h>
|
||||
#include <ButterworthFilter.h>
|
||||
#include <FastAudioFIFO.h>
|
||||
#endif
|
||||
|
||||
#define ADC_BUFFER_SIZE 320 // 40ms of voice in 8KHz sampling frequency
|
||||
#define ENCODE_FRAME_SIZE 40 // 5 codec2 frames of 8 bytes each
|
||||
|
||||
class AudioModule : public SinglePortModule, private concurrency::OSThread
|
||||
{
|
||||
#if defined(ARCH_ESP32) && defined(USE_SX1280)
|
||||
bool firstTime = 1;
|
||||
hw_timer_t* adcTimer = NULL;
|
||||
uint16_t adc_buffer[ADC_BUFFER_SIZE] = {};
|
||||
int16_t speech[ADC_BUFFER_SIZE] = {};
|
||||
int16_t output_buffer[ADC_BUFFER_SIZE] = {};
|
||||
unsigned char rx_encode_frame[ENCODE_FRAME_SIZE] = {};
|
||||
unsigned char tx_encode_frame[ENCODE_FRAME_SIZE] = {};
|
||||
int tx_encode_frame_index = 0;
|
||||
FastAudioFIFO audio_fifo;
|
||||
uint16_t adc_buffer_index = 0;
|
||||
adc1_channel_t mic_chan = (adc1_channel_t)0;
|
||||
struct CODEC2* codec2_state = NULL;
|
||||
|
||||
enum State
|
||||
{
|
||||
standby, rx, tx
|
||||
};
|
||||
volatile State state = State::tx;
|
||||
|
||||
public:
|
||||
AudioModule();
|
||||
|
||||
/**
|
||||
* Send our payload into the mesh
|
||||
*/
|
||||
void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
static void handleInterrupt();
|
||||
|
||||
void onTimer();
|
||||
|
||||
void run_codec2();
|
||||
|
||||
virtual MeshPacket *allocReply() override;
|
||||
|
||||
/** Called to handle a particular incoming message
|
||||
* @return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const MeshPacket &mp) override;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern AudioModule *audioModule;
|
||||
|
@ -3,5 +3,6 @@ extends = esp32_base
|
||||
board = ttgo-lora32-v21
|
||||
lib_deps =
|
||||
${esp32_base.lib_deps}
|
||||
caveman99/ESP32 Codec2@^1.0.1
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D TLORA_V2_1_18 -I variants/tlora_v2_1_18
|
Loading…
Reference in New Issue
Block a user