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