diff --git a/examples/Audio_Examples/AudioExample1_PlayTone/AudioExample1_PlayTone.ino b/examples/Audio_Examples/AudioExample1_PlayTone/AudioExample1_PlayTone.ino new file mode 100644 index 0000000..60f802d --- /dev/null +++ b/examples/Audio_Examples/AudioExample1_PlayTone/AudioExample1_PlayTone.ino @@ -0,0 +1,129 @@ +#include "SparkFun_u-blox_Cellular_Arduino_Library.h" + +// Uncomment the line below that you need for Serial on your platform +#define mySerial Serial1 +// SoftwareSerial mySerial(16, 17); + +// Uncomment the module you're using. If your module is not listed below, then +// it's not supported for this example +UBX_CELL_VOICE_BASE myModule; // This example works with all voice-enabled modules, so this base class can be used +// LARA_R6001 myModule; +// LARA_R6401 myModule; +// LARA_R6801_00B myModule; + +void setup() +{ + Serial.begin(115200); // Start the serial console + + // Wait for user to press key to begin + Serial.println(F("u-blox Cellular Audio Example 1 - Play Tone")); + + Serial.println(); + Serial.println(F("! ! ! ! ! ATTENTION ! ! ! ! ! ATTENTION ! ! ! ! ! ATTENTION ! ! ! ! !")); + Serial.println(F("This example requires an audio codec attached to the I2S interface")); + Serial.println(F("of the cellular modem. Please add one and update this example as")); + Serial.println(F("needed to configure your audio codec!")); + Serial.println(F("! ! ! ! ! ATTENTION ! ! ! ! ! ATTENTION ! ! ! ! ! ATTENTION ! ! ! ! !")); + Serial.println(); + + Serial.println(F("Press any key to begin")); + + while (!Serial.available()) // Wait for the user to press a key (send any serial character) + ; + while (Serial.available()) // Empty the serial RX buffer + Serial.read(); + + Serial.println(F("Beginning...")); + + // myModule.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial + + // For the MicroMod Asset Tracker, we need to invert the power pin so it pulls high instead of low + // Uncomment the next line if required + // myModule.invertPowerPin(true); + + // Initialize the module + if (myModule.begin(mySerial, UBX_CELL_DEFAULT_BAUD_RATE) ) + { + Serial.println(F("Module connected!")); + } + else + { + Serial.println(F("Unable to communicate with the module.")); + Serial.println(F("Manually power-on (hold the module's On button for 3 seconds) and try again.")); + while (1) ; // Loop forever on fail + } + Serial.println(); +} + +void loop() +{ + String inputString; + char dtmfChar = 0; + uint16_t frequency = 0; + uint16_t duration = 0; + uint8_t volume = 0; + + while(true) + { + while(Serial.available() != 0){Serial.read();} + Serial.println(F("Enter a frequency in Hz (300-3400) or a DTMF character (0-9, *, #)")); + while(Serial.available() == 0){} + + inputString = Serial.readStringUntil('\n'); + + if(inputString.length() == 1) + { + dtmfChar = inputString.charAt(0); + if((dtmfChar >= '0' && dtmfChar <= '9') || dtmfChar == '*' || dtmfChar == '#') + { + break; + } + } + else + { + frequency = inputString.toInt(); + if(frequency >= 300 && frequency <= 3400) + { + dtmfChar == 0; + break; + } + } + } + + while(true) + { + while(Serial.available() != 0){Serial.read();} + Serial.println(F("Enter a duration in ms (50-1360)")); + while(Serial.available() == 0){} + + inputString = Serial.readStringUntil('\n'); + duration = inputString.toInt(); + if(duration >= 50 && duration <= 1360) + { + break; + } + } + + while(true) + { + while(Serial.available() != 0){Serial.read();} + Serial.println(F("Enter a volume (0-100)")); + while(Serial.available() == 0){} + + inputString = Serial.readStringUntil('\n'); + volume = inputString.toInt(); + if(volume <= 100) + { + break; + } + } + + if(dtmfChar == 0) + { + myModule.generateToneFreq(frequency, duration, volume); + } + else + { + myModule.generateToneDTMF(dtmfChar, duration, volume); + } +} \ No newline at end of file diff --git a/examples/Audio_Examples/AudioExample2_Loopback/AudioExample2_Loopback.ino b/examples/Audio_Examples/AudioExample2_Loopback/AudioExample2_Loopback.ino new file mode 100644 index 0000000..b07ce47 --- /dev/null +++ b/examples/Audio_Examples/AudioExample2_Loopback/AudioExample2_Loopback.ino @@ -0,0 +1,71 @@ +#include "SparkFun_u-blox_Cellular_Arduino_Library.h" + +// Uncomment the line below that you need for Serial on your platform +#define mySerial Serial1 +// SoftwareSerial mySerial(16, 17); + +// Uncomment the module you're using. If your module is not listed below, then +// it's not supported for this example +UBX_CELL_VOICE_BASE myModule; // This example works with all voice-enabled modules, so this base class can be used +// LARA_R6001 myModule; +// LARA_R6401 myModule; +// LARA_R6801_00B myModule; + +void setup() +{ + Serial.begin(115200); // Start the serial console + + // Wait for user to press key to begin + Serial.println(F("u-blox Cellular Audio Example 2 - Loopback")); + + Serial.println(); + Serial.println(F("! ! ! ! ! ATTENTION ! ! ! ! ! ATTENTION ! ! ! ! ! ATTENTION ! ! ! ! !")); + Serial.println(F("This example requires an audio codec attached to the I2S interface")); + Serial.println(F("of the cellular modem. Please add one and update this example as")); + Serial.println(F("needed to configure your audio codec!")); + Serial.println(F("! ! ! ! ! ATTENTION ! ! ! ! ! ATTENTION ! ! ! ! ! ATTENTION ! ! ! ! !")); + Serial.println(); + + Serial.println(F("Press any key to begin")); + + while (!Serial.available()) // Wait for the user to press a key (send any serial character) + ; + while (Serial.available()) // Empty the serial RX buffer + Serial.read(); + + Serial.println(F("Beginning...")); + + // myModule.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial + + // For the MicroMod Asset Tracker, we need to invert the power pin so it pulls high instead of low + // Uncomment the next line if required + // myModule.invertPowerPin(true); + + // Initialize the module + if (myModule.begin(mySerial, UBX_CELL_DEFAULT_BAUD_RATE) ) + { + Serial.println(F("Module connected!")); + } + else + { + Serial.println(F("Unable to communicate with the module.")); + Serial.println(F("Manually power-on (hold the module's On button for 3 seconds) and try again.")); + while (1) ; // Loop forever on fail + } + Serial.println(); +} + +void loop() +{ + while(Serial.available() != 0){Serial.read();} + Serial.println(F("Enter any key to begin loopback")); + while(Serial.available() == 0){} + + myModule.playAudioResource(UBX_CELL_AUDIO_RESOURCE_LOOPBACK); + + while(Serial.available() != 0){Serial.read();} + Serial.println(F("Enter any key to stop loopback")); + while(Serial.available() == 0){} + + myModule.stopAudioResource(UBX_CELL_AUDIO_RESOURCE_LOOPBACK); +} \ No newline at end of file diff --git a/examples/Audio_Examples/AudioExample3_CallControl/AudioExample3_CallControl.ino b/examples/Audio_Examples/AudioExample3_CallControl/AudioExample3_CallControl.ino new file mode 100644 index 0000000..47f407f --- /dev/null +++ b/examples/Audio_Examples/AudioExample3_CallControl/AudioExample3_CallControl.ino @@ -0,0 +1,129 @@ +#include "SparkFun_u-blox_Cellular_Arduino_Library.h" + +// Uncomment the line below that you need for Serial on your platform +#define mySerial Serial1 +// SoftwareSerial mySerial(16, 17); + +// Uncomment the module you're using. If your module is not listed below, then +// it's not supported for this example +UBX_CELL_VOICE_BASE myModule; // This example works with all voice-enabled modules, so this base class can be used +// LARA_R6001 myModule; +// LARA_R6401 myModule; +// LARA_R6801_00B myModule; + +bool callInProgress = false; +bool incomingCall = false; + +void ringCallback() +{ + Serial.println(F("Incoming call! Enter \"A\" to answer, or anything else to reject")); + incomingCall = true; +} + +void setup() +{ + String currentOperator = ""; + + Serial.begin(115200); // Start the serial console + + // Wait for user to press key to begin + Serial.println(F("u-blox Cellular Audio Example 3 - Call Control")); + + Serial.println(); + Serial.println(F("! ! ! ! ! ATTENTION ! ! ! ! ! ATTENTION ! ! ! ! ! ATTENTION ! ! ! ! !")); + Serial.println(F("This example requires an audio codec attached to the I2S interface")); + Serial.println(F("of the cellular modem. Please add one and update this example as")); + Serial.println(F("needed to configure your audio codec!")); + Serial.println(F("! ! ! ! ! ATTENTION ! ! ! ! ! ATTENTION ! ! ! ! ! ATTENTION ! ! ! ! !")); + Serial.println(); + + Serial.println(F("Press any key to begin")); + + while (!Serial.available()) // Wait for the user to press a key (send any serial character) + ; + while (Serial.available()) // Empty the serial RX buffer + Serial.read(); + + Serial.println(F("Beginning...")); + + // myModule.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial + + // For the MicroMod Asset Tracker, we need to invert the power pin so it pulls high instead of low + // Uncomment the next line if required + // myModule.invertPowerPin(true); + + // Initialize the module + if (myModule.begin(mySerial, UBX_CELL_DEFAULT_BAUD_RATE) ) + { + Serial.println(F("Module connected!")); + } + else + { + Serial.println(F("Unable to communicate with the module.")); + Serial.println(F("Manually power-on (hold the module's On button for 3 seconds) and try again.")); + while (1) ; // Loop forever on fail + } + Serial.println(); + + // First check to see if we're connected to an operator: + if (myModule.getOperator(¤tOperator) == UBX_CELL_SUCCESS) + { + Serial.print(F("Connected to: ")); + Serial.println(currentOperator); + } + else + { + Serial.print(F("The module is not yet connected to an operator. Please use the previous examples to connect. Or wait and retry. Freezing...")); + while (1) + ; // Do nothing more + } + + // Set callback function for when a new call is received + myModule.setRingCallback(&ringCallback); + + Serial.println(F("Enter a number to dial")); + + // Clear any input + while(Serial.available()){Serial.read();} +} + +void loop() +{ + String inputString; + + myModule.bufferedPoll(); + + if(Serial.available()) + { + inputString = Serial.readStringUntil('\n'); + while(Serial.available()){Serial.read();} + + if(incomingCall) + { + if(inputString == "A" || inputString == "a") + { + Serial.println(F("Answering call, enter any key to hang up")); + myModule.answer(); + callInProgress = true; + } + else + { + Serial.println(F("Rejecting call")); + myModule.hangUp(); + } + incomingCall = false; + } + else if(callInProgress == false) + { + Serial.println("Dialing " + inputString + ", enter any key to hang up"); + myModule.dial(inputString); + callInProgress = true; + } + else + { + Serial.println(F("Hanging up, enter a new number to dial")); + myModule.hangUp(); + callInProgress = false; + } + } +} \ No newline at end of file diff --git a/src/SparkFun_u-blox_Cellular_Arduino_Library.h b/src/SparkFun_u-blox_Cellular_Arduino_Library.h index a5b2243..96e8cd8 100644 --- a/src/SparkFun_u-blox_Cellular_Arduino_Library.h +++ b/src/SparkFun_u-blox_Cellular_Arduino_Library.h @@ -1,3 +1,4 @@ #include "sfe_ublox_cellular.h" +#include "sfe_ublox_cellular_voice.h" #include "sfe_sara_r5.h" #include "sfe_lara_r6.h" diff --git a/src/sfe_ublox_cellular_voice.h b/src/sfe_ublox_cellular_voice.h index 0e291dd..9ceee64 100644 --- a/src/sfe_ublox_cellular_voice.h +++ b/src/sfe_ublox_cellular_voice.h @@ -10,11 +10,29 @@ const char* const UBX_CELL_COMMAND_PLAY_AUDIO = "+UPAR"; // Play audio resour const char* const UBX_CELL_COMMAND_STOP_AUDIO = "+USAR"; // Stop audio resource const char* const UBX_CELL_COMMAND_GENERATE_TONE = "+UTGN"; // Tone generator +const char* const UBX_CELL_RING_URC = "RING"; + +typedef enum +{ + UBX_CELL_AUDIO_RESOURCE_TONE = 0, + UBX_CELL_AUDIO_RESOURCE_MIDI = 1, + UBX_CELL_AUDIO_RESOURCE_LOOPBACK = 2 +} UBX_CELL_audio_resource_t; + // Base class for any modules supporting voice calls template class UBX_CELL_VOICE { public: + UBX_CELL_VOICE(void) + { + // Set ring URC callback to nullptr + _ringCallback = nullptr; + + // Add handler for ring URC + static_cast(this)->addURCHandler(UBX_CELL_RING_URC, [this](const char* event){return this->urcCheckRing(event);}); + } + UBX_CELL_error_t dial(String number) { char *command; @@ -60,7 +78,7 @@ class UBX_CELL_VOICE nullptr, UBX_CELL_STANDARD_RESPONSE_TIMEOUT); } - UBX_CELL_error_t playAudioResource(uint8_t audio_resource, uint8_t tone_id, uint8_t nof_repeat) + UBX_CELL_error_t playAudioResource(uint8_t audio_resource, uint8_t tone_id = 0, uint8_t nof_repeat = 0) { UBX_CELL_error_t err; char *command; @@ -125,6 +143,36 @@ class UBX_CELL_VOICE free(command); return err; } + + void setRingCallback(void (*callback)(void)) + { + _ringCallback = callback; + } + +protected: + // Callback for incoming calls + void (*_ringCallback)(void); + + bool urcCheckRing(const char *event) + { + int socket, length; + char *searchPtr = strstr(event, UBX_CELL_RING_URC); + if (searchPtr != nullptr) + { + if(_ringCallback != nullptr) + { + _ringCallback(); + } + return true; + } + + return false; + } +}; + +class UBX_CELL_VOICE_BASE : public UBX_CELL, public UBX_CELL_VOICE +{ + }; #endif \ No newline at end of file