diff --git a/.gitmodules b/.gitmodules
index e6f376a0b..238eda7de 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,4 @@
[submodule "protobufs"]
path = protobufs
url = https://github.com/meshtastic/protobufs.git
+ branch = develop
diff --git a/platformio.ini b/platformio.ini
index 7c1ba6851..0021350dd 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -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]
diff --git a/protobufs b/protobufs
index 6b46e42a6..2954e5b02 160000
--- a/protobufs
+++ b/protobufs
@@ -1 +1 @@
-Subproject commit 6b46e42a656dd3aab74c373e79b70e699eeac834
+Subproject commit 2954e5b0228c85902c841bfb0f18add43980a2e2
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index 4ddbe10d4..d6e90c6f9 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -50,8 +50,6 @@ along with this program. If not, see .
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;
}
}
diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp
index 81821ac19..97dd66fae 100644
--- a/src/mesh/RadioInterface.cpp
+++ b/src/mesh/RadioInterface.cpp
@@ -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;
}
diff --git a/src/mesh/generated/admin.pb.h b/src/mesh/generated/admin.pb.h
index 9b93bfd44..b5dc769ca 100644
--- a/src/mesh/generated/admin.pb.h
+++ b/src/mesh/generated/admin.pb.h
@@ -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
diff --git a/src/mesh/generated/config.pb.c b/src/mesh/generated/config.pb.c
index 2b75b7558..c5bc69552 100644
--- a/src/mesh/generated/config.pb.c
+++ b/src/mesh/generated/config.pb.c
@@ -43,4 +43,3 @@ PB_BIND(Config_BluetoothConfig, Config_BluetoothConfig, AUTO)
-
diff --git a/src/mesh/generated/config.pb.h b/src/mesh/generated/config.pb.h
index 263b1e916..a9005ddcd 100644
--- a/src/mesh/generated/config.pb.h
+++ b/src/mesh/generated/config.pb.h
@@ -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" */
diff --git a/src/mesh/generated/localonly.pb.h b/src/mesh/generated/localonly.pb.h
index 8e4199d48..a69aefc10 100644
--- a/src/mesh/generated/localonly.pb.h
+++ b/src/mesh/generated/localonly.pb.h
@@ -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" */
diff --git a/src/mesh/generated/module_config.pb.c b/src/mesh/generated/module_config.pb.c
index a3e4ddfbe..381ce6351 100644
--- a/src/mesh/generated/module_config.pb.c
+++ b/src/mesh/generated/module_config.pb.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
+
diff --git a/src/mesh/generated/module_config.pb.h b/src/mesh/generated/module_config.pb.h
index b0f14eea2..af4d4dce9 100644
--- a/src/mesh/generated/module_config.pb.h
+++ b/src/mesh/generated/module_config.pb.h
@@ -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
diff --git a/src/mesh/generated/portnums.pb.h b/src/mesh/generated/portnums.pb.h
index d272fe2b9..ec7b7eaec 100644
--- a/src/mesh/generated/portnums.pb.h
+++ b/src/mesh/generated/portnums.pb.h
@@ -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,
diff --git a/src/mesh/http/WiFiAPClient.cpp b/src/mesh/http/WiFiAPClient.cpp
index a031414e3..6caad79c0 100644
--- a/src/mesh/http/WiFiAPClient.cpp
+++ b/src/mesh/http/WiFiAPClient.cpp
@@ -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:
diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp
index 986a375df..d24fa8f26 100644
--- a/src/modules/Modules.cpp
+++ b/src/modules/Modules.cpp
@@ -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
diff --git a/src/modules/Telemetry/Sensor/BME280Sensor.cpp b/src/modules/Telemetry/Sensor/BME280Sensor.cpp
index 15ec18007..4b6a50091 100644
--- a/src/modules/Telemetry/Sensor/BME280Sensor.cpp
+++ b/src/modules/Telemetry/Sensor/BME280Sensor.cpp
@@ -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;
diff --git a/src/modules/Telemetry/Sensor/BME680Sensor.cpp b/src/modules/Telemetry/Sensor/BME680Sensor.cpp
index 474c376dd..a9171facf 100644
--- a/src/modules/Telemetry/Sensor/BME680Sensor.cpp
+++ b/src/modules/Telemetry/Sensor/BME680Sensor.cpp
@@ -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;
}
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/BMP280Sensor.cpp b/src/modules/Telemetry/Sensor/BMP280Sensor.cpp
index 4fecdf1a8..917c40d6f 100644
--- a/src/modules/Telemetry/Sensor/BMP280Sensor.cpp
+++ b/src/modules/Telemetry/Sensor/BMP280Sensor.cpp
@@ -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;
diff --git a/src/modules/esp32/AudioModule.cpp b/src/modules/esp32/AudioModule.cpp
new file mode 100644
index 000000000..7147db43c
--- /dev/null
+++ b/src/modules/esp32/AudioModule.cpp
@@ -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
+
+/*
+ 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
\ No newline at end of file
diff --git a/src/modules/esp32/AudioModule.h b/src/modules/esp32/AudioModule.h
new file mode 100644
index 000000000..d82af4d43
--- /dev/null
+++ b/src/modules/esp32/AudioModule.h
@@ -0,0 +1,68 @@
+#pragma once
+
+#include "SinglePortModule.h"
+#include "concurrency/OSThread.h"
+#include "configuration.h"
+#include "NodeDB.h"
+#include
+#include
+#include
+#if defined(ARCH_ESP32) && defined(USE_SX1280)
+#include
+#include
+#include
+#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;
+
diff --git a/variants/tlora_v2_1_18/platformio.ini b/variants/tlora_v2_1_18/platformio.ini
index 2cb1c3d2f..4160be5de 100644
--- a/variants/tlora_v2_1_18/platformio.ini
+++ b/variants/tlora_v2_1_18/platformio.ini
@@ -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
\ No newline at end of file