diff --git a/.clang-format b/.clang-format index 5c4f8fb..353008b 100644 --- a/.clang-format +++ b/.clang-format @@ -1,16 +1,245 @@ --- -# options: https://clang.llvm.org/docs/ClangFormatStyleOptions.html -BasedOnStyle: chromium -IndentWidth: 2 -# Must be 80 characters or less! -# ColumnLimit: 80 -# does (int) x instead of (int)x -SpaceAfterCStyleCast: true -# spaces, not tabs! -UseTab: Never -# -AlignTrailingComments: true -# #define SHORT_NAME 42 -# #define LONGER_NAME 0x007f # does nice spacing for macros -AlignConsecutiveMacros: Consecutive -IndentPPDirectives: BeforeHash +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: AlwaysBreak +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true + AlignCompound: false + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: false + AcrossComments: true + AlignCompound: true + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveShortCaseStatements: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCaseColons: false +AlignEscapedNewlines: Left +AlignOperands: Align +AlignTrailingComments: + Kind: Never + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowBreakBeforeNoexceptSpecifier: Never +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortCompoundRequirementOnASingleLine: true +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +BinPackArguments: false +BinPackParameters: false +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAdjacentStringLiterals: true +BreakAfterAttributes: Leave +BreakAfterJavaFieldAnnotations: false +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Attach +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: false +BreakConstructorInitializers: BeforeComma +BreakInheritanceList: BeforeColon +BreakStringLiterals: false +ColumnLimit: 99 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: false +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH + - M_EACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: false +IndentWidth: 4 +IndentWrappedFunctionNames: true +InsertBraces: false +InsertNewlineAtEOF: true +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +KeepEmptyLinesAtEOF: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 4 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: BinPack +PenaltyBreakAssignment: 10 +PenaltyBreakBeforeFirstCallParameter: 30 +PenaltyBreakComment: 10 +PenaltyBreakFirstLessLess: 0 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakScopeResolution: 500 +PenaltyBreakString: 10 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 100 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Left +PPIndentWidth: -1 +QualifierAlignment: Leave +ReferenceAlignment: Pointer +ReflowComments: false +RemoveBracesLLVM: false +RemoveParentheses: Leave +RemoveSemicolon: true +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SkipMacroDefinitionBody: false +SortIncludes: Never +SortJavaStaticImport: Before +SortUsingDeclarations: Never +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeJsonColon: false +SpaceBeforeParens: Never +SpaceBeforeParensOptions: + AfterControlStatements: false + AfterForeachMacros: false + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: false + AfterOverloadedOperator: false + AfterPlacementOperator: true + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInContainerLiterals: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParens: Never +SpacesInParensOptions: + InCStyleCasts: false + InConditionalStatements: false + InEmptyParentheses: false + Other: false +SpacesInSquareBrackets: false +Standard: c++20 +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +UseTab: Never +VerilogBreakBetweenInstancePorts: true +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +... diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..c63d175 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,22 @@ +name: "FAP: Build and lint" +on: [push, pull_request] +jobs: + ufbt-build-action: + runs-on: ubuntu-latest + name: 'ufbt: Build for Dev branch' + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Build with ufbt + uses: flipperdevices/flipperzero-ufbt-action@v0.1.3 + id: build-app + with: + # Set to 'release' to build for latest published release version or dev for develop + sdk-index-url: https://up.unleashedflip.com/directory.json + sdk-channel: release + app-dir: ./applications_user/lora_app + - name: Upload app artifacts + uses: actions/upload-artifact@v3 + with: + name: ${{ github.event.repository.name }}-${{ steps.build-app.outputs.suffix }} + path: ${{ steps.build-app.outputs.fap-artifacts }} diff --git a/README.md b/README.md index 2198b8c..3b0bc56 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +![GitHub release (with filter)](https://img.shields.io/github/v/release/ElectronicCats/flipper-rs485modbus?color=%23008000) +![GitHub actions](https://img.shields.io/github/actions/workflow/status/ElectronicCats/flipper-rs485modbus/build.yml) + # Flipper LoRa Relay App :dolphin: Work with LoRa radio communication signals. Now you can interact with LoRa transmissions using the Flipper Zero. Basic tasks such as sniffing and injection are available, making it easy to perform activities such as analysis, error detection and configuration of new peripherals to the network. diff --git a/applications_user/lora_app/README.md b/applications_user/lora_app/README.md deleted file mode 100644 index 90fabd6..0000000 --- a/applications_user/lora_app/README.md +++ /dev/null @@ -1,83 +0,0 @@ -# skeleton_app -You can use this application as a starting point for creating your own application. It contains the skeleton framework to get an application running on the Flipper Zero. - -Please let me know any feedback! -- Discord - https://discord.com/invite/NsjCvqwPAd (@CodeAllNight) -- YouTube - https://youtube.com/@MrDerekJamison/playlists -- GitHub - https://github.com/jamisonderek/flipper-zero-tutorials -- Wiki - https://github.com/jamisonderek/flipper-zero-tutorials/wiki - -## Overview - -This application has three submenu items: -* Config -* Play -* About - -## Config -The "Config" menu item currently has 2 settings. The first setting has a selection of 3 options (and demonstrates how the numeric values associated with them don't have to be sequential.) The other setting has a text field which is set by clicking OK while selecting the setting (depending on your application, you may want to do something else when an item is clicked, like bring up a hex selector.) - -## Play -The "Play" screen is where you would put your primary application. The current implementation renders some data. When Left/Right buttons are clicked the value of x changes and the icon moves left/right. Up/Down buttons don't do anything in our implementation. As soon as the OK button is pressed, a tone is made based on the value of x. Pressing the back button goes back to the menu. - -## About - -The "About" menu item contains information about your application, so people know what to do with it & how to contact you. - -## Modifying the project - -### application.fam - -Set the `appid` to a unique value for your application. This should be lowercase letters, numbers, and underscores. Your icons header file will be impacted by this change (in app.c). - -Set the `name` to the name to dispay in the UI when selecting an application to load. - -Set the `entry_point` to the name of the method in your app.c file, that should get executed when your application is selected to be run. This method should take a (void\*) input parameter and return a uint32_t status code. - -For most applications a 4K `stack_size` should be a good default. - -Make sure `fap_icon` is the name of the PNG file with your 10x10 pixel icon that should be displayed when selecting your application. - -The `fap_category` is the category that your application is mostly related to. If your primary purpose is not GPIO then change this category. This will determine what folder it is in when starting, as well as where people will locate your application in the Hub mobile app. - -### app.png - -This is a 10x10 PNG icon to display when selecting your application. If you want to rename this file to something other than `app.png`, be sure to also edit the application.fam `fap_icon` value. - -### app.c - -#### Icons file - -Replace `my_app_id_42_icons.h` with your `appid`\_icons.h (based on the you set in application.fam) - -#### TAG value - -Change the #define TAG to be the name of the application to appear in log messages. - -#### BACKLIGHT_ALWAYS_ON - -Remove the `#define BACKLIGHT_ALWAYS_ON` statement if you don't want the backlight to automatically turn off after some duration. - -#### MyApp and my_app - -Replace all occurances of `MyApp` and `my_app_` with the name of your application. - -#### FlipTheWorld - -Replace `"Play"` with the action you want for your main applicaiton. - -#### "This is a sample application" - -Replace the about text in your application. Search for `This is a sample application`. You can use '\n' to force a newline. - -#### my_app_view_draw_callback - -Change the code in `..._view_draw_callback` to draw the primary screen for your application. - -#### my_app_view_input_callback - -Change the code in `..._view_input_callback` to handle user input in the primary screen for your application. - -#### setting_1_values - -Make sure the number of items in `setting_1_values` and `setting_1_names` is the same length. Change these settings to whatever values makes sense for your user to configure. You may also want to change `"Setting 1"` to be a more descriptive name for the setting and perhaps update the variable names as well. diff --git a/applications_user/lora_app/lora.c b/applications_user/lora_app/lora.c index d63b932..2f2c122 100644 --- a/applications_user/lora_app/lora.c +++ b/applications_user/lora_app/lora.c @@ -1,6 +1,5 @@ /* -Code porting from LoRa library -https://github.dev/thekakester/Arduino-LoRa-Sx1262 +Code porting from LoRa library https://github.dev/thekakester/Arduino-LoRa-Sx1262 */ #include @@ -8,7 +7,7 @@ Code porting from LoRa library #define TAG "LORA" -// Presets. These help make radio config easier +//Presets. These help make radio config easier #define PRESET_DEFAULT 0 #define PRESET_LONGRANGE 1 #define PRESET_FAST 2 @@ -24,7 +23,7 @@ Code porting from LoRa library #define FREQ_STEP 0.95367431640625 static uint32_t timeout = 1000; -// static uint32_t timeout = 100; +//static uint32_t timeout = 100; static FuriHalSpiBusHandle* spi = &furi_hal_spi_bus_handle_external; const GpioPin* const pin_beacon = &gpio_swclk; @@ -35,15 +34,15 @@ const GpioPin* const pin_busy = &gpio_usart_rx; const GpioPin* const pin_dio1 = &gpio_ext_pc3; bool inReceiveMode = false; -uint8_t spiBuff[32]; // Buffer for sending SPI commands to radio +uint8_t spiBuff[32]; //Buffer for sending SPI commands to radio -// Config variables (set to PRESET_DEFAULT on init) +//Config variables (set to PRESET_DEFAULT on init) uint32_t pllFrequency; uint8_t bandwidth; uint8_t codingRate; uint8_t spreadingFactor; uint8_t lowDataRateOptimize; -uint32_t transmitTimeout; // Worst-case transmit time depends on some factors +uint32_t transmitTimeout; //Worst-case transmit time depends on some factors int rssi = 0; int snr = 0; @@ -51,528 +50,501 @@ int signalRssi = 0; // test void abandone() { - FURI_LOG_E(TAG, "abandon hope all ye who enter here"); + FURI_LOG_E(TAG, "abandon hope all ye who enter here"); } int16_t getRSSI() { - return rssi; + return rssi; } void checkBusy() { - uint8_t busy_timeout_cnt; - busy_timeout_cnt = 0; + uint8_t busy_timeout_cnt; + busy_timeout_cnt = 0; - furi_hal_gpio_init_simple(pin_busy, GpioModeInput); + furi_hal_gpio_init_simple(pin_busy, GpioModeInput); - while (furi_hal_gpio_read(pin_busy)) { - furi_delay_ms(1); - busy_timeout_cnt++; + while(furi_hal_gpio_read(pin_busy)) { + furi_delay_ms(1); + busy_timeout_cnt++; - if (busy_timeout_cnt > 10) // wait 10mS for busy to complete - { - busy_timeout_cnt = 0; - FURI_LOG_E(TAG, "ERROR - Busy Timeout!"); - break; + if(busy_timeout_cnt > 10) //wait 10mS for busy to complete + { + busy_timeout_cnt = 0; + FURI_LOG_E(TAG, "ERROR - Busy Timeout!"); + break; + } } - } } void readRegisters(uint16_t address, uint8_t* buffer, uint16_t size) { - uint16_t index; - uint8_t addr_l, addr_h; + uint16_t index; + uint8_t addr_l, addr_h; - addr_h = address >> 8; - addr_l = address & 0x00FF; - checkBusy(); + addr_h = address >> 8; + addr_l = address & 0x00FF; + checkBusy(); - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); + furi_hal_spi_acquire(spi); - spiBuff[0] = RADIO_READ_REGISTER; - spiBuff[1] = addr_h; - spiBuff[2] = addr_l; - spiBuff[3] = 0x00; + spiBuff[0] = RADIO_READ_REGISTER; + spiBuff[1] = addr_h; + spiBuff[2] = addr_l; + spiBuff[3] = 0x00; - furi_hal_spi_bus_tx(spi, spiBuff, 4, timeout); + furi_hal_spi_bus_tx(spi, spiBuff, 4, timeout); - for (index = 0; index < size; index++) { - furi_hal_spi_bus_rx(spi, buffer + index, 1, timeout); - } + for(index = 0; index < size; index++) { + furi_hal_spi_bus_rx(spi, buffer + index, 1, timeout); + } - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + furi_hal_spi_release(spi); + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select } uint8_t readRegister(uint16_t address) { - uint8_t data; + uint8_t data; - readRegisters(address, &data, 1); - return data; + readRegisters(address, &data, 1); + return data; } uint16_t getSyncWord() { - uint8_t msb, lsb; - uint16_t syncword; - msb = readRegister(REG_LR_SYNCWORD); - lsb = readRegister(REG_LR_SYNCWORD + 1); + uint8_t msb, lsb; + uint16_t syncword; + msb = readRegister(REG_LR_SYNCWORD); + lsb = readRegister(REG_LR_SYNCWORD + 1); - FURI_LOG_E(TAG, "MSB: %02x", msb); - FURI_LOG_E(TAG, "LSB: %02x", lsb); + FURI_LOG_E(TAG, "MSB: %02x", msb); + FURI_LOG_E(TAG, "LSB: %02x", lsb); - syncword = (msb << 8) + lsb; + syncword = (msb << 8) + lsb; - return syncword; + return syncword; } uint32_t getFreqInt() { - // get the current set device frequency from registers, return as long integer - - uint8_t MsbH, MsbL, Mid, Lsb; - uint32_t uinttemp; - float floattemp; - MsbH = readRegister(REG_RFFrequency31_24); - MsbL = readRegister(REG_RFFrequency23_16); - Mid = readRegister(REG_RFFrequency15_8); - Lsb = readRegister(REG_RFFrequency7_0); - floattemp = - ((MsbH * 0x1000000ul) + (MsbL * 0x10000ul) + (Mid * 0x100ul) + Lsb); - floattemp = ((floattemp * FREQ_STEP) / 1000000ul); - uinttemp = (uint32_t) (floattemp * 1000000); - return uinttemp; + //get the current set device frequency from registers, return as long integer + + uint8_t MsbH, MsbL, Mid, Lsb; + uint32_t uinttemp; + float floattemp; + MsbH = readRegister(REG_RFFrequency31_24); + MsbL = readRegister(REG_RFFrequency23_16); + Mid = readRegister(REG_RFFrequency15_8); + Lsb = readRegister(REG_RFFrequency7_0); + floattemp = ((MsbH * 0x1000000ul) + (MsbL * 0x10000ul) + (Mid * 0x100ul) + Lsb); + floattemp = ((floattemp * FREQ_STEP) / 1000000ul); + uinttemp = (uint32_t)(floattemp * 1000000); + return uinttemp; } /*Convert a frequency in hz (such as 915000000) to the respective PLL setting. - * The radio requires that we set the PLL, which controls the multipler on the - * internal clock to achieve the desired frequency. Valid frequencies are 150MHz - * to 960MHz (150000000 to 960000000) - * - * NOTE: This assumes the radio is using a 32mhz clock, which is standard. This - * is independent of the microcontroller clock See datasheet section 13.4.1 for - * this calculation. Example: 915mhz (915000000) has a PLL of 959447040 - */ +* The radio requires that we set the PLL, which controls the multipler on the internal clock to achieve the desired frequency. +* Valid frequencies are 150MHz to 960MHz (150000000 to 960000000) +* +* NOTE: This assumes the radio is using a 32mhz clock, which is standard. This is independent of the microcontroller clock +* See datasheet section 13.4.1 for this calculation. +* Example: 915mhz (915000000) has a PLL of 959447040 +*/ uint32_t frequencyToPLL(long rfFreq) { - /* Datasheet Says: - * rfFreq = (pllFreq * xtalFreq) / 2^25 - * Rewrite to solve for pllFreq - * pllFreq = (2^25 * rfFreq)/xtalFreq - * - * In our case, xtalFreq is 32mhz - * pllFreq = (2^25 * rfFreq) / 32000000 - */ - // Basically, we need to do "return ((1 << 25) * rfFreq) / 32000000L" - // It's very important to perform this without losing precision or integer - // overflow. If arduino supported 64-bit varibales (which it doesn't), we - // could just do this: - // uint64_t firstPart = (1 << 25) * (uint64_t)rfFreq; - // return (uint32_t)(firstPart / 32000000L); - // - // Instead, we need to break this up mathimatically to avoid integer overflow - // First, we'll simplify the equation by dividing both parts by 2048 (2^11) - // ((1 << 25) * rfFreq) / 32000000L --> (16384 * rfFreq) / - // 15625; - // - // Now, we'll divide first, then multiply (multiplying first would cause - // integer overflow) Because we're dividing, we need to keep track of the - // remainder to avoid losing precision - uint32_t q = rfFreq / 15625UL; // Gives us the result (quotient), rounded - // down to the nearest integer - uint32_t r = rfFreq % 15625UL; // Everything that isn't divisible, aka "the - // part that hasn't been divided yet" - - // Multiply by 16384 to satisfy the equation above - q *= 16384UL; - r *= 16384UL; // Don't forget, this part still needs to be divided because it - // was too small to divide before - - return q + (r / 15625UL); // Finally divide the the remainder part before - // adding it back in with the quotient + /* Datasheet Says: + * rfFreq = (pllFreq * xtalFreq) / 2^25 + * Rewrite to solve for pllFreq + * pllFreq = (2^25 * rfFreq)/xtalFreq + * + * In our case, xtalFreq is 32mhz + * pllFreq = (2^25 * rfFreq) / 32000000 + */ + //Basically, we need to do "return ((1 << 25) * rfFreq) / 32000000L" + //It's very important to perform this without losing precision or integer overflow. + //If arduino supported 64-bit varibales (which it doesn't), we could just do this: + // uint64_t firstPart = (1 << 25) * (uint64_t)rfFreq; + // return (uint32_t)(firstPart / 32000000L); + // + //Instead, we need to break this up mathimatically to avoid integer overflow + //First, we'll simplify the equation by dividing both parts by 2048 (2^11) + // ((1 << 25) * rfFreq) / 32000000L --> (16384 * rfFreq) / 15625; + // + // Now, we'll divide first, then multiply (multiplying first would cause integer overflow) + // Because we're dividing, we need to keep track of the remainder to avoid losing precision + uint32_t q = + rfFreq / 15625UL; //Gives us the result (quotient), rounded down to the nearest integer + uint32_t r = + rfFreq % + 15625UL; //Everything that isn't divisible, aka "the part that hasn't been divided yet" + + //Multiply by 16384 to satisfy the equation above + q *= 16384UL; + r *= + 16384UL; //Don't forget, this part still needs to be divided because it was too small to divide before + + return q + + (r / + 15625UL); //Finally divide the the remainder part before adding it back in with the quotient } -// Set the radio frequency. Just a single SPI call, -// but this is broken out to make it more convenient to change frequency -// on-the-fly You must set this->pllFrequency before calling this +//Set the radio frequency. Just a single SPI call, +//but this is broken out to make it more convenient to change frequency on-the-fly +//You must set this->pllFrequency before calling this void updateRadioFrequency() { - // Set PLL frequency (this is a complicated math equation. See datasheet entry - // for SetRfFrequency) - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x86; // Opcode for set RF Frequencty - spiBuff[1] = (pllFrequency >> 24) & 0xFF; // MSB of pll frequency - spiBuff[2] = (pllFrequency >> 16) & 0xFF; // - spiBuff[3] = (pllFrequency >> 8) & 0xFF; // - spiBuff[4] = (pllFrequency >> 0) & 0xFF; // LSB of requency - furi_hal_spi_bus_tx(spi, spiBuff, 5, timeout); - - furi_hal_spi_release(spi); - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for the radio to process command + // Set PLL frequency (this is a complicated math equation. See datasheet entry for SetRfFrequency) + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + furi_hal_spi_acquire(spi); + + spiBuff[0] = 0x86; //Opcode for set RF Frequencty + spiBuff[1] = (pllFrequency >> 24) & 0xFF; //MSB of pll frequency + spiBuff[2] = (pllFrequency >> 16) & 0xFF; // + spiBuff[3] = (pllFrequency >> 8) & 0xFF; // + spiBuff[4] = (pllFrequency >> 0) & 0xFF; //LSB of requency + furi_hal_spi_bus_tx(spi, spiBuff, 5, timeout); + + furi_hal_spi_release(spi); + + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + furi_delay_ms(100); // Give time for the radio to process command } /** (Optional) Set the operating frequency of the radio. - * The 1262 radio supports 150-960Mhz. This library uses a default of 915Mhz. - * MAKE SURE THAT YOU ARE OPERATING IN A FREQUENCY THAT IS ALLOWED IN YOUR - * COUNTRY! For example, 915mhz (915000000 hz) is safe in the US. - * - * Specify the desired frequency in Hz (eg 915MHZ is 915000000). - * Returns TRUE on success, FALSE on invalid frequency - */ +* The 1262 radio supports 150-960Mhz. This library uses a default of 915Mhz. +* MAKE SURE THAT YOU ARE OPERATING IN A FREQUENCY THAT IS ALLOWED IN YOUR COUNTRY! +* For example, 915mhz (915000000 hz) is safe in the US. +* +* Specify the desired frequency in Hz (eg 915MHZ is 915000000). +* Returns TRUE on success, FALSE on invalid frequency +*/ bool configSetFrequency(long frequencyInHz) { - // Make sure the specified frequency is in the valid range. - if (frequencyInHz < 150000000 || frequencyInHz > 960000000) { - return false; - } - - // Calculate the PLL frequency (See datasheet section 13.4.1 for calculation) - // PLL frequency controls the radio's clock multipler to achieve the desired - // frequency - pllFrequency = frequencyToPLL(frequencyInHz); - updateRadioFrequency(); - return true; + //Make sure the specified frequency is in the valid range. + if(frequencyInHz < 150000000 || frequencyInHz > 960000000) { + return false; + } + + //Calculate the PLL frequency (See datasheet section 13.4.1 for calculation) + //PLL frequency controls the radio's clock multipler to achieve the desired frequency + pllFrequency = frequencyToPLL(frequencyInHz); + updateRadioFrequency(); + return true; } // Set the radio modulation parameters. // This is things like bandwidth, spreading factor, coding rate, etc. -// This is broken into its own function because this command might get called -// frequently +// This is broken into its own function because this command might get called frequently void updateModulationParameters() { - // Set modulation parameters - // Modulation parameters are: - // - SpreadingFactor - // - Bandwidth - // - CodingRate - // - LowDataRateOptimize - // None of these actually matter that much. You can set them to anything, and - // data will still show up on a radio frequency monitor. You just MUST call - // "setModulationParameters", otherwise the radio won't work at all - - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - - spiBuff[0] = 0x8B; // Opcode for "SetModulationParameters" - spiBuff[1] = spreadingFactor; // ModParam1 = Spreading Factor. Can be - // SF5-SF12, written in hex (0x05-0x0C) - spiBuff[2] = bandwidth; // ModParam2 = Bandwidth. See Datasheet 13.4.5.2 for - // details. 0x00=7.81khz (slowest) - spiBuff[3] = codingRate; // ModParam3 = CodingRate. Semtech recommends - // CR_4_5 (which is 0x01). Options are 0x01-0x04, - // which correspond to coding rate 5-8 respectively - spiBuff[4] = lowDataRateOptimize; // LowDataRateOptimize. 0x00 = 0ff, 0x01 = - // On. Required to be on for SF11 + SF12 - - furi_hal_spi_acquire(spi); - - if (furi_hal_spi_bus_tx( - spi, spiBuff, 5, - timeout)) { // Assuming 'timeout' is defined somewhere in the code - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } + // Set modulation parameters + // Modulation parameters are: + // - SpreadingFactor + // - Bandwidth + // - CodingRate + // - LowDataRateOptimize + // None of these actually matter that much. You can set them to anything, and data will still show up + // on a radio frequency monitor. + // You just MUST call "setModulationParameters", otherwise the radio won't work at all + + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + + spiBuff[0] = 0x8B; // Opcode for "SetModulationParameters" + spiBuff[1] = + spreadingFactor; // ModParam1 = Spreading Factor. Can be SF5-SF12, written in hex (0x05-0x0C) + spiBuff[2] = + bandwidth; // ModParam2 = Bandwidth. See Datasheet 13.4.5.2 for details. 0x00=7.81khz (slowest) + spiBuff[3] = + codingRate; // ModParam3 = CodingRate. Semtech recommends CR_4_5 (which is 0x01). Options are 0x01-0x04, which correspond to coding rate 5-8 respectively + spiBuff[4] = + lowDataRateOptimize; // LowDataRateOptimize. 0x00 = 0ff, 0x01 = On. Required to be on for SF11 + SF12 - // furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for the radio to process command + furi_hal_spi_acquire(spi); + + if(furi_hal_spi_bus_tx( + spi, spiBuff, 5, timeout)) { // Assuming 'timeout' is defined somewhere in the code + furi_hal_spi_release(spi); + } else { + FURI_LOG_E(TAG, "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); + furi_hal_spi_release(spi); + } - // Determine transmit timeout based on spreading factor - // TODO: - // TIMEOUT SET TO 1000, STILL CHECKING HOW TO FIX - switch (spreadingFactor) { + //furi_hal_spi_release(spi); + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + furi_delay_ms(100); // Give time for the radio to process command + + // Determine transmit timeout based on spreading factor + // TODO: + // TIMEOUT SET TO 1000, STILL CHECKING HOW TO FIX + switch(spreadingFactor) { case 12: - transmitTimeout = 1000; // 252000; // Actual tx time 126 seconds - break; + transmitTimeout = 1000; // 252000; // Actual tx time 126 seconds + break; case 11: - transmitTimeout = 1000; // 160000; // Actual tx time 81 seconds - break; + transmitTimeout = 1000; // 160000; // Actual tx time 81 seconds + break; case 10: - transmitTimeout = 1000; // 60000; // Actual tx time 36 seconds - break; + transmitTimeout = 1000; // 60000; // Actual tx time 36 seconds + break; case 9: - transmitTimeout = 1000; // 40000; // Actual tx time 20 seconds - break; + transmitTimeout = 1000; // 40000; // Actual tx time 20 seconds + break; case 8: - transmitTimeout = 1000; // 20000; // Actual tx time 11 seconds - break; + transmitTimeout = 1000; // 20000; // Actual tx time 11 seconds + break; case 7: - transmitTimeout = 1000; // 12000; // Actual tx time 6.3 seconds - break; + transmitTimeout = 1000; // 12000; // Actual tx time 6.3 seconds + break; case 6: - transmitTimeout = 1000; // 7000; // Actual tx time 3.7s seconds - break; - default: // SF5 - transmitTimeout = 1000; // 5000; // Actual tx time 2.2 seconds - break; - } + transmitTimeout = 1000; // 7000; // Actual tx time 3.7s seconds + break; + default: // SF5 + transmitTimeout = 1000; //5000; // Actual tx time 2.2 seconds + break; + } } /**(Optional) Use one of the pre-made radio configurations - * This is ideal for making simple changes to the radio config - * without needing to understand how the underlying settings work - * - * Argument: pass in one of the following - * - PRESET_DEFAULT: Default radio config. - * Medium range, medium speed - * - PRESET_FAST: Faster speeds, but less reliable at long ranges. - * Use when you need fast data transfer and have radios - * close together - * - PRESET_LONGRANGE: Most reliable option, but slow. Suitable when you - * prioritize reliability over speed, or when transmitting over long distances - */ +* This is ideal for making simple changes to the radio config +* without needing to understand how the underlying settings work +* +* Argument: pass in one of the following +* - PRESET_DEFAULT: Default radio config. +* Medium range, medium speed +* - PRESET_FAST: Faster speeds, but less reliable at long ranges. +* Use when you need fast data transfer and have radios close together +* - PRESET_LONGRANGE: Most reliable option, but slow. Suitable when you prioritize +* reliability over speed, or when transmitting over long distances +*/ bool configSetPreset(int preset) { - if (preset == PRESET_DEFAULT) { - bandwidth = 0x04; // 125khz - codingRate = 0x01; // CR_4_5 - spreadingFactor = 0x08; // SF8 - lowDataRateOptimize = 0; // Don't optimize (used for SF12 only) - updateModulationParameters(); - return true; - } + if(preset == PRESET_DEFAULT) { + bandwidth = 0x04; //125khz + codingRate = 0x01; //CR_4_5 + spreadingFactor = 0x08; //SF8 + lowDataRateOptimize = 0; //Don't optimize (used for SF12 only) + updateModulationParameters(); + return true; + } - if (preset == PRESET_LONGRANGE) { - bandwidth = 4; // 125khz - codingRate = 1; // CR_4_5 - spreadingFactor = 12; // SF12 - lowDataRateOptimize = 1; // Optimize for low data rate (SF12 only) - updateModulationParameters(); - return true; - } + if(preset == PRESET_LONGRANGE) { + bandwidth = 4; //125khz + codingRate = 1; //CR_4_5 + spreadingFactor = 12; //SF12 + lowDataRateOptimize = 1; //Optimize for low data rate (SF12 only) + updateModulationParameters(); + return true; + } - if (preset == PRESET_FAST) { - bandwidth = 6; // 500khz - codingRate = 1; // CR_4_5 - spreadingFactor = 5; // SF5 - lowDataRateOptimize = 0; // Don't optimize (used for SF12 only) - updateModulationParameters(); - return true; - } + if(preset == PRESET_FAST) { + bandwidth = 6; //500khz + codingRate = 1; //CR_4_5 + spreadingFactor = 5; //SF5 + lowDataRateOptimize = 0; //Don't optimize (used for SF12 only) + updateModulationParameters(); + return true; + } - // Invalid preset specified - return false; + //Invalid preset specified + return false; } /*Send the bare-bones required commands needed for radio to run. - * Do not set custom or optional commands here, please keep this section as - * simplified as possible. Essential commands are found by reading the datasheet - */ +* Do not set custom or optional commands here, please keep this section as simplified as possible. +* Essential commands are found by reading the datasheet +*/ void configureRadioEssentials() { - // Tell DIO2 to control the RF switch so we don't have to do it manually - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + // Tell DIO2 to control the RF switch so we don't have to do it manually + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); + furi_hal_spi_acquire(spi); - spiBuff[0] = 0x9D; // Opcode for "SetDIO2AsRfSwitchCtrl" - spiBuff[1] = 0x01; // Enable + spiBuff[0] = 0x9D; //Opcode for "SetDIO2AsRfSwitchCtrl" + spiBuff[1] = 0x01; //Enable - if (furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } + if(furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout)) { + furi_hal_spi_release(spi); + } else { + FURI_LOG_E(TAG, "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); + furi_hal_spi_release(spi); + } - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for the radio to process command + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + furi_delay_ms(100); // Give time for the radio to process command - // Just a single SPI command to set the frequency, but it's broken out - // into its own function so we can call it on-the-fly when the config changes - configSetFrequency(915000000); // Set default frequency to 915mhz + // Just a single SPI command to set the frequency, but it's broken out + // into its own function so we can call it on-the-fly when the config changes + configSetFrequency(915000000); // Set default frequency to 915mhz - // Set modem to LoRa (described in datasheet section 13.4.2) - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); + // Set modem to LoRa (described in datasheet section 13.4.2) + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + furi_hal_spi_acquire(spi); - spiBuff[0] = 0x8A; // Opcode for "SetPacketType" - spiBuff[1] = 0x01; // Packet Type: 0x00=GFSK, 0x01=LoRa + spiBuff[0] = 0x8A; // Opcode for "SetPacketType" + spiBuff[1] = 0x01; // Packet Type: 0x00=GFSK, 0x01=LoRa - if (furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for radio to process the command + if(furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout)) { + furi_hal_spi_release(spi); + } else { + FURI_LOG_E(TAG, "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); + furi_hal_spi_release(spi); + } - // Set Rx Timeout to reset on SyncWord or Header detection - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + furi_delay_ms(100); // Give time for radio to process the command - spiBuff[0] = 0x9F; // Opcode for "StopTimerOnPreamble" - spiBuff[1] = 0x00; // Stop timer on: 0x00=SyncWord or header detection, - // 0x01=preamble detection + // Set Rx Timeout to reset on SyncWord or Header detection + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + furi_hal_spi_acquire(spi); - if (furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for radio to process the command - - // Set modulation parameters is just one more SPI command, but since it - // is often called frequently when changing the radio config, it's broken up - // into its own function - configSetPreset(PRESET_DEFAULT); // Sets default modulation parameters - - // Set PA Config - // See datasheet 13.1.4 for descriptions and optimal settings recommendations - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x95; // Opcode for "SetPaConfig" - spiBuff[1] = - 0x04; // paDutyCycle. See datasheet, set in conjunction with hpMax - spiBuff[2] = - 0x07; // hpMax. Basically Tx power. 0x00-0x07 where 0x07 is max power - spiBuff[3] = 0x00; // device select: 0x00 = SX1262, 0x01 = SX1261 - spiBuff[4] = 0x01; // paLut (reserved, always set to 1) - - if (furi_hal_spi_bus_tx(spi, spiBuff, 5, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } + spiBuff[0] = 0x9F; // Opcode for "StopTimerOnPreamble" + spiBuff[1] = 0x00; // Stop timer on: 0x00=SyncWord or header detection, 0x01=preamble detection - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for radio to process the command + if(furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout)) { + furi_hal_spi_release(spi); + } else { + FURI_LOG_E(TAG, "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); + furi_hal_spi_release(spi); + } - // Set TX Params - // See datasheet 13.4.4 for details - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + furi_delay_ms(100); // Give time for radio to process the command - spiBuff[0] = 0x8E; // Opcode for SetTxParams - spiBuff[1] = 22; // Power. Can be -17(0xEF) to +14x0E in Low Pow mode. - // -9(0xF7) to 22(0x16) in high power mode - spiBuff[2] = 0x02; // Ramp time. Lookup table. See table 13-41. 0x02="40uS" + // Set modulation parameters is just one more SPI command, but since it + // is often called frequently when changing the radio config, it's broken up into its own function + configSetPreset(PRESET_DEFAULT); // Sets default modulation parameters - if (furi_hal_spi_bus_tx(spi, spiBuff, 3, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } + // Set PA Config + // See datasheet 13.1.4 for descriptions and optimal settings recommendations + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + furi_hal_spi_acquire(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for radio to process the command + spiBuff[0] = 0x95; // Opcode for "SetPaConfig" + spiBuff[1] = 0x04; // paDutyCycle. See datasheet, set in conjunction with hpMax + spiBuff[2] = 0x07; // hpMax. Basically Tx power. 0x00-0x07 where 0x07 is max power + spiBuff[3] = 0x00; // device select: 0x00 = SX1262, 0x01 = SX1261 + spiBuff[4] = 0x01; // paLut (reserved, always set to 1) + + if(furi_hal_spi_bus_tx(spi, spiBuff, 5, timeout)) { + furi_hal_spi_release(spi); + } else { + FURI_LOG_E(TAG, "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); + furi_hal_spi_release(spi); + } - // Set LoRa Symbol Number timeout - // How many symbols are needed for a good receive. - // Symbols are preamble symbols - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + furi_delay_ms(100); // Give time for radio to process the command - spiBuff[0] = 0xA0; // Opcode for "SetLoRaSymbNumTimeout" - spiBuff[1] = - 0x00; // Number of symbols. Ping-pong example from Semtech uses 5 + // Set TX Params + // See datasheet 13.4.4 for details + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + furi_hal_spi_acquire(spi); - if (furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for radio to process the command - - // Enable interrupts - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x08; // 0x08 is the opcode for "SetDioIrqParams" - spiBuff[1] = 0x00; // IRQMask MSB. IRQMask is "what interrupts are enabled" - spiBuff[2] = 0x02; // IRQMask LSB See datasheet table 13-29 for details - spiBuff[3] = 0xFF; // DIO1 mask MSB. Of the interrupts detected, which should - // be triggered on DIO1 pin - spiBuff[4] = 0xFF; // DIO1 Mask LSB - spiBuff[5] = 0x00; // DIO2 Mask MSB - spiBuff[6] = 0x00; // DIO2 Mask LSB - spiBuff[7] = 0x00; // DIO3 Mask MSB - spiBuff[8] = 0x00; // DIO3 Mask LSB - - if (furi_hal_spi_bus_tx(spi, spiBuff, 9, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } + spiBuff[0] = 0x8E; // Opcode for SetTxParams + spiBuff[1] = + 22; // Power. Can be -17(0xEF) to +14x0E in Low Pow mode. -9(0xF7) to 22(0x16) in high power mode + spiBuff[2] = 0x02; // Ramp time. Lookup table. See table 13-41. 0x02="40uS" + + if(furi_hal_spi_bus_tx(spi, spiBuff, 3, timeout)) { + furi_hal_spi_release(spi); + } else { + FURI_LOG_E(TAG, "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); + furi_hal_spi_release(spi); + } - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for radio to process the command -} + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + furi_delay_ms(100); // Give time for radio to process the command -bool waitForRadioCommandCompletion(uint32_t timeout) { - uint32_t startTime = furi_get_tick(); // Get the start time in ticks - bool dataTransmitted = false; + // Set LoRa Symbol Number timeout + // How many symbols are needed for a good receive. + // Symbols are preamble symbols + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + furi_hal_spi_acquire(spi); - // Keep checking the radio status until the operation is completed - while (!dataTransmitted) { - // Wait a while between SPI status queries to avoid reading too quickly - furi_delay_ms(5); + spiBuff[0] = 0xA0; // Opcode for "SetLoRaSymbNumTimeout" + spiBuff[1] = 0x00; // Number of symbols. Ping-pong example from Semtech uses 5 - // Request a status update from the radio - furi_hal_gpio_write(pin_nss1, false); // Enable the radio chip-select - furi_hal_spi_acquire(spi); + if(furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout)) { + furi_hal_spi_release(spi); + } else { + FURI_LOG_E(TAG, "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); + furi_hal_spi_release(spi); + } - spiBuff[0] = 0xC0; // Opcode for the "getStatus" command - spiBuff[1] = 0x00; // Dummy byte, status will overwrite this byte + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + furi_delay_ms(100); // Give time for radio to process the command - furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout); + // Enable interrupts + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + furi_hal_spi_acquire(spi); - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable the radio chip-select - - // Parse the status - uint8_t chipMode = - (spiBuff[1] >> 4) & 0x07; // Chip mode is bits [6:4] (3-bits) - uint8_t commandStatus = - (spiBuff[1] >> 1) & 0x07; // Command status is bits [3:1] (3-bits) - - // Check if the operation has finished - // Status 0, 1, 2 mean we're still busy. Anything else means we're done. - // Commands 3-6 = command timeout, command processing error, failure to - // execute command, and Tx Done (respoectively) - if (commandStatus != 0 && commandStatus != 1 && commandStatus != 2) { - dataTransmitted = true; - FURI_LOG_E(TAG, "DATA TRANSMITTED"); + spiBuff[0] = 0x08; // 0x08 is the opcode for "SetDioIrqParams" + spiBuff[1] = 0x00; // IRQMask MSB. IRQMask is "what interrupts are enabled" + spiBuff[2] = 0x02; // IRQMask LSB See datasheet table 13-29 for details + spiBuff[3] = + 0xFF; // DIO1 mask MSB. Of the interrupts detected, which should be triggered on DIO1 pin + spiBuff[4] = 0xFF; // DIO1 Mask LSB + spiBuff[5] = 0x00; // DIO2 Mask MSB + spiBuff[6] = 0x00; // DIO2 Mask LSB + spiBuff[7] = 0x00; // DIO3 Mask MSB + spiBuff[8] = 0x00; // DIO3 Mask LSB + + if(furi_hal_spi_bus_tx(spi, spiBuff, 9, timeout)) { + furi_hal_spi_release(spi); + } else { + FURI_LOG_E(TAG, "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); + furi_hal_spi_release(spi); } - // If we are in standby mode, there's no need to wait anymore - if (chipMode == 0x03 || chipMode == 0x02) { - dataTransmitted = true; - FURI_LOG_E(TAG, "DATA TRANSMITTED STANBY MODE"); - } + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + furi_delay_ms(100); // Give time for radio to process the command +} - // Prevent infinite loop by implementing a timeout - if ((furi_get_tick() - startTime) >= furi_ms_to_ticks(timeout)) { - return false; +bool waitForRadioCommandCompletion(uint32_t timeout) { + uint32_t startTime = furi_get_tick(); // Get the start time in ticks + bool dataTransmitted = false; + + // Keep checking the radio status until the operation is completed + while(!dataTransmitted) { + // Wait a while between SPI status queries to avoid reading too quickly + furi_delay_ms(5); + + // Request a status update from the radio + furi_hal_gpio_write(pin_nss1, false); // Enable the radio chip-select + furi_hal_spi_acquire(spi); + + spiBuff[0] = 0xC0; // Opcode for the "getStatus" command + spiBuff[1] = 0x00; // Dummy byte, status will overwrite this byte + + furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout); + + furi_hal_spi_release(spi); + furi_hal_gpio_write(pin_nss1, true); // Disable the radio chip-select + + // Parse the status + uint8_t chipMode = (spiBuff[1] >> 4) & 0x07; // Chip mode is bits [6:4] (3-bits) + uint8_t commandStatus = (spiBuff[1] >> 1) & 0x07; // Command status is bits [3:1] (3-bits) + + // Check if the operation has finished + //Status 0, 1, 2 mean we're still busy. Anything else means we're done. + //Commands 3-6 = command timeout, command processing error, failure to execute command, and Tx Done (respoectively) + if(commandStatus != 0 && commandStatus != 1 && commandStatus != 2) { + dataTransmitted = true; + FURI_LOG_E(TAG, "DATA TRANSMITTED"); + } + + // If we are in standby mode, there's no need to wait anymore + if(chipMode == 0x03 || chipMode == 0x02) { + dataTransmitted = true; + FURI_LOG_E(TAG, "DATA TRANSMITTED STANBY MODE"); + } + + // Prevent infinite loop by implementing a timeout + if((furi_get_tick() - startTime) >= furi_ms_to_ticks(timeout)) { + return false; + } } - } - // Success! - return true; + // Success! + return true; } -/* Set the bandwidth (basically, this is how big the frequency span is that we -occupy) Bigger bandwidth allows us to transmit large amounts of data faster, but -it occupies a larger span of frequencies. Smaller bandwidth takes longer to -transmit large amounts of data, but its less likely to collide with other -frequencies. +/* Set the bandwidth (basically, this is how big the frequency span is that we occupy) +Bigger bandwidth allows us to transmit large amounts of data faster, but it occupies a larger span of frequencies. +Smaller bandwidth takes longer to transmit large amounts of data, but its less likely to collide with other frequencies. Available bandwidth settings, pulled from datasheet 13.4.5.2 SETTING. | Bandwidth @@ -589,498 +561,467 @@ SETTING. | Bandwidth 0x06 | 500.00khz */ bool configSetBandwidth(int bw) { - if (bw < 0 || bw > 0x0A || bw == 7) { - return false; - } - bandwidth = bw; - updateModulationParameters(); - return true; + if(bw < 0 || bw > 0x0A || bw == 7) { + return false; + } + bandwidth = bw; + updateModulationParameters(); + return true; } /* Set the coding rate*/ bool configSetCodingRate(int cr) { - // Coding rate must be 1-4 (inclusive) - if (cr < 1 || cr > 4) { - return false; - } - codingRate = cr; - updateModulationParameters(); - return true; + // Coding rate must be 1-4 (inclusive) + if(cr < 1 || cr > 4) { + return false; + } + codingRate = cr; + updateModulationParameters(); + return true; } /* Change the spreading factor of a packet -The higher the spreading factor, the slower and more reliable the transmission -will be. */ +The higher the spreading factor, the slower and more reliable the transmission will be. */ bool configSetSpreadingFactor(int sf) { - if (sf < 5 || sf > 12) { - return false; - } - lowDataRateOptimize = - (sf >= 11) ? 1 : 0; // Turn on for SF11+SF12, turn off for anything else - spreadingFactor = sf; - updateModulationParameters(); - return true; + if(sf < 5 || sf > 12) { + return false; + } + lowDataRateOptimize = (sf >= 11) ? 1 : 0; // Turn on for SF11+SF12, turn off for anything else + spreadingFactor = sf; + updateModulationParameters(); + return true; } -void setPacketParams(uint16_t packetParam1, - uint8_t packetParam2, - uint8_t packetParam3, - uint8_t packetParam4, - uint8_t packetParam5) { - // Order is preamble, header type, packet length, CRC, IQ - - uint8_t preambleMSB = packetParam1 >> 8; - uint8_t preambleLSB = packetParam1 & 0xFF; - - // savedPacketParam1 = packetParam1; - // savedPacketParam2 = packetParam2; - // savedPacketParam3 = packetParam3; - // savedPacketParam4 = packetParam4; - // savedPacketParam5 = packetParam5; - - spiBuff[0] = 0x8C; // Opcode for "SetPacketParameters" - spiBuff[1] = preambleMSB; // Preamble Len MSB - spiBuff[2] = preambleLSB; // Preamble Len LSB - spiBuff[3] = - packetParam2; // Header Type. 0x00 = Variable Len, 0x01 = Fixed Length - spiBuff[4] = packetParam3; // Payload Length (Max is 255 bytes) - spiBuff[5] = packetParam4; // 0x00 = Off, 0x01 = on - spiBuff[6] = packetParam5; // 0x00 = Standard, 0x01 = Inverted - - // Acquire SPI and write command - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - if (furi_hal_spi_bus_tx(spi, spiBuff, 7, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } +void setPacketParams( + uint16_t packetParam1, + uint8_t packetParam2, + uint8_t packetParam3, + uint8_t packetParam4, + uint8_t packetParam5) { + // Order is preamble, header type, packet length, CRC, IQ + + uint8_t preambleMSB = packetParam1 >> 8; + uint8_t preambleLSB = packetParam1 & 0xFF; + + //savedPacketParam1 = packetParam1; + //savedPacketParam2 = packetParam2; + //savedPacketParam3 = packetParam3; + //savedPacketParam4 = packetParam4; + //savedPacketParam5 = packetParam5; + + spiBuff[0] = 0x8C; //Opcode for "SetPacketParameters" + spiBuff[1] = preambleMSB; //Preamble Len MSB + spiBuff[2] = preambleLSB; //Preamble Len LSB + spiBuff[3] = packetParam2; //Header Type. 0x00 = Variable Len, 0x01 = Fixed Length + spiBuff[4] = packetParam3; //Payload Length (Max is 255 bytes) + spiBuff[5] = packetParam4; //0x00 = Off, 0x01 = on + spiBuff[6] = packetParam5; //0x00 = Standard, 0x01 = Inverted + + // Acquire SPI and write command + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + furi_hal_spi_acquire(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - waitForRadioCommandCompletion(100); + if(furi_hal_spi_bus_tx(spi, spiBuff, 7, timeout)) { + furi_hal_spi_release(spi); + } else { + FURI_LOG_E(TAG, "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); + furi_hal_spi_release(spi); + } + + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + waitForRadioCommandCompletion(100); } -// Sets the radio into receive mode, allowing it to listen for incoming packets. -// If radio is already in receive mode, this does nothing. -// There's no such thing as "setModeTransmit" because it is set automatically -// when transmit() is called +//Sets the radio into receive mode, allowing it to listen for incoming packets. +//If radio is already in receive mode, this does nothing. +//There's no such thing as "setModeTransmit" because it is set automatically when transmit() is called void setModeReceive() { - if (inReceiveMode) { - return; - } // We're already in receive mode, this would do nothing - - // Set packet parameters - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x8C; // Opcode for "SetPacketParameters" - spiBuff[1] = 0x00; // PacketParam1 = Preamble Len MSB - spiBuff[2] = 0x0C; // PacketParam2 = Preamble Len LSB - spiBuff[3] = 0x00; // PacketParam3 = Header Type. 0x00 = Variable Len, 0x01 = - // Fixed Length - spiBuff[4] = 0xFF; // PacketParam4 = Payload Length (Max is 255 bytes) - spiBuff[5] = 0x00; // PacketParam5 = CRC Type. 0x00 = Off, 0x01 = on - spiBuff[6] = - 0x00; // PacketParam6 = Invert IQ. 0x00 = Standard, 0x01 = Inverted - - if (furi_hal_spi_bus_tx(spi, spiBuff, 7, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } + if(inReceiveMode) { + return; + } // We're already in receive mode, this would do nothing - // furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + // Set packet parameters + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + furi_hal_spi_acquire(spi); - waitForRadioCommandCompletion(100); + spiBuff[0] = 0x8C; //Opcode for "SetPacketParameters" + spiBuff[1] = 0x00; //PacketParam1 = Preamble Len MSB + spiBuff[2] = 0x0C; //PacketParam2 = Preamble Len LSB + spiBuff[3] = 0x00; //PacketParam3 = Header Type. 0x00 = Variable Len, 0x01 = Fixed Length + spiBuff[4] = 0xFF; //PacketParam4 = Payload Length (Max is 255 bytes) + spiBuff[5] = 0x00; //PacketParam5 = CRC Type. 0x00 = Off, 0x01 = on + spiBuff[6] = 0x00; //PacketParam6 = Invert IQ. 0x00 = Standard, 0x01 = Inverted + + if(furi_hal_spi_bus_tx(spi, spiBuff, 7, timeout)) { + furi_hal_spi_release(spi); + } else { + FURI_LOG_E(TAG, "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); + furi_hal_spi_release(spi); + } - // Tell the chip to wait for it to receive a packet. - // Based on our previous config, this should throw an interrupt when we get a - // packet - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); + //furi_hal_spi_release(spi); + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - spiBuff[0] = 0x82; // 0x82 is the opcode for "SetRX" - spiBuff[1] = 0xFF; // 24-bit timeout, 0xFFFFFF means no timeout - spiBuff[2] = 0xFF; // ^^ - spiBuff[3] = 0xFF; // ^^ + waitForRadioCommandCompletion(100); - if (furi_hal_spi_bus_tx(spi, spiBuff, 4, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } + // Tell the chip to wait for it to receive a packet. + // Based on our previous config, this should throw an interrupt when we get a packet + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + furi_hal_spi_acquire(spi); + + spiBuff[0] = 0x82; //0x82 is the opcode for "SetRX" + spiBuff[1] = 0xFF; //24-bit timeout, 0xFFFFFF means no timeout + spiBuff[2] = 0xFF; // ^^ + spiBuff[3] = 0xFF; // ^^ - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + if(furi_hal_spi_bus_tx(spi, spiBuff, 4, timeout)) { + furi_hal_spi_release(spi); + } else { + FURI_LOG_E(TAG, "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); + furi_hal_spi_release(spi); + } - waitForRadioCommandCompletion(100); + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - // Remember that we're in receive mode so we don't need to run this code again - // unnecessarily - inReceiveMode = true; + waitForRadioCommandCompletion(100); + + // Remember that we're in receive mode so we don't need to run this code again unnecessarily + inReceiveMode = true; } /* Set radio into standby mode. -Switching directly from Rx to Tx mode can be slow, so we first want to go into -standby */ +Switching directly from Rx to Tx mode can be slow, so we first want to go into standby */ void setModeStandby() { - // Tell the chip to wait for it to receive a packet. - // Based on our previous config, this should throw an interrupt when we get a - // packet - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + // Tell the chip to wait for it to receive a packet. + // Based on our previous config, this should throw an interrupt when we get a packet + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - spiBuff[0] = 0x80; // 0x80 is the opcode for "SetStandby" - spiBuff[1] = 0x01; // 0x00 = STDBY_RC, 0x01=STDBY_XOSC + spiBuff[0] = 0x80; //0x80 is the opcode for "SetStandby" + spiBuff[1] = 0x01; //0x00 = STDBY_RC, 0x01=STDBY_XOSC - furi_hal_spi_acquire(spi); - furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout); - furi_hal_spi_release(spi); + furi_hal_spi_acquire(spi); + furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout); + furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - waitForRadioCommandCompletion(100); - inReceiveMode = false; // No longer in receive mode + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + waitForRadioCommandCompletion(100); + inReceiveMode = false; // No longer in receive mode } void transmit(uint8_t* data, int dataLen) { - // Max lora packet size is 255 bytes - if (dataLen > 255) { - dataLen = 255; - } - - // Switching directly from rx to tx mode is slow. Go to standby first - if (inReceiveMode) { - setModeStandby(); - } - - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - - spiBuff[0] = 0x8C; // Opcode for "SetPacketParameters" - spiBuff[1] = 0x00; // PacketParam1 = Preamble Len MSB - spiBuff[2] = 0x0C; // PacketParam2 = Preamble Len LSB - spiBuff[3] = 0x00; // PacketParam3 = Header Type. 0x00 = Variable Len, 0x01 = - // Fixed Length - spiBuff[4] = dataLen; // PacketParam4 = Payload Length (Max is 255 bytes) - spiBuff[5] = 0x00; // PacketParam5 = CRC Type. 0x00 = Off, 0x01 = on - spiBuff[6] = - 0x00; // PacketParam6 = Invert IQ. 0x00 = Standard, 0x01 = Inverted - - furi_hal_spi_acquire(spi); - furi_hal_spi_bus_tx(spi, spiBuff, 7, timeout); - furi_hal_spi_release(spi); - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - waitForRadioCommandCompletion( - 100); // Give time for radio to process the command - - // Write the payload to the buffer - // Reminder: PayloadLength is defined in setPacketParams - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - - spiBuff[0] = 0x0E, // Opcode for WriteBuffer command - spiBuff[1] = 0x00; // Dummy byte before writing payload - - furi_hal_spi_acquire(spi); - furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout); - - // Transmit data in chunks to avoid overwriting the original buffer - uint8_t size = sizeof(spiBuff); - for (uint16_t i = 0; i < dataLen; i += size) { - if (i + size > dataLen) { - size = dataLen - i; + // Max lora packet size is 255 bytes + if(dataLen > 255) { + dataLen = 255; + } + + // Switching directly from rx to tx mode is slow. Go to standby first + if(inReceiveMode) { + setModeStandby(); + } + + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + + spiBuff[0] = 0x8C; // Opcode for "SetPacketParameters" + spiBuff[1] = 0x00; // PacketParam1 = Preamble Len MSB + spiBuff[2] = 0x0C; // PacketParam2 = Preamble Len LSB + spiBuff[3] = 0x00; // PacketParam3 = Header Type. 0x00 = Variable Len, 0x01 = Fixed Length + spiBuff[4] = dataLen; // PacketParam4 = Payload Length (Max is 255 bytes) + spiBuff[5] = 0x00; // PacketParam5 = CRC Type. 0x00 = Off, 0x01 = on + spiBuff[6] = 0x00; // PacketParam6 = Invert IQ. 0x00 = Standard, 0x01 = Inverted + + furi_hal_spi_acquire(spi); + furi_hal_spi_bus_tx(spi, spiBuff, 7, timeout); + furi_hal_spi_release(spi); + + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + waitForRadioCommandCompletion(100); // Give time for radio to process the command + + // Write the payload to the buffer + // Reminder: PayloadLength is defined in setPacketParams + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + + spiBuff[0] = 0x0E, //Opcode for WriteBuffer command + spiBuff[1] = 0x00; //Dummy byte before writing payload + + furi_hal_spi_acquire(spi); + furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout); + + // Transmit data in chunks to avoid overwriting the original buffer + uint8_t size = sizeof(spiBuff); + for(uint16_t i = 0; i < dataLen; i += size) { + if(i + size > dataLen) { + size = dataLen - i; + } + memcpy(spiBuff, &(data[i]), size); + furi_hal_spi_bus_tx(spi, data + i, size, timeout); // Write the payload itself } - memcpy(spiBuff, &(data[i]), size); - furi_hal_spi_bus_tx(spi, data + i, size, - timeout); // Write the payload itself - } - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - waitForRadioCommandCompletion( - 1000); // Give time for radio to process the command + furi_hal_spi_release(spi); + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + waitForRadioCommandCompletion(1000); // Give time for radio to process the command - // Transmit - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + // Transmit + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - spiBuff[0] = 0x83; // Opcode for SetTx command - spiBuff[1] = 0xFF; // Timeout (3-byte number) - spiBuff[2] = 0xFF; // Timeout (3-byte number) - spiBuff[3] = 0xFF; // Timeout (3-byte number) + spiBuff[0] = 0x83; // Opcode for SetTx command + spiBuff[1] = 0xFF; // Timeout (3-byte number) + spiBuff[2] = 0xFF; // Timeout (3-byte number) + spiBuff[3] = 0xFF; // Timeout (3-byte number) - furi_hal_spi_acquire(spi); - furi_hal_spi_bus_tx(spi, spiBuff, 4, timeout); - furi_hal_spi_release(spi); + furi_hal_spi_acquire(spi); + furi_hal_spi_bus_tx(spi, spiBuff, 4, timeout); + furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - waitForRadioCommandCompletion( - transmitTimeout); // Wait for tx to complete, with a timeout so we don't - // wait forever + waitForRadioCommandCompletion( + transmitTimeout); // Wait for tx to complete, with a timeout so we don't wait forever - // Remember that we are in Tx mode. If we want to receive a packet, we need - // to switch into receiving mode - inReceiveMode = false; + // Remember that we are in Tx mode. If we want to receive a packet, we need to switch into receiving mode + inReceiveMode = false; } /*Receive a packet if available -If available, this will return the size of the packet and store the packet -contents into the user-provided buffer. A max length of the buffer can be -provided to avoid buffer overflow. If buffer is not large enough for entire -payload, overflow is thrown out. Recommended to pass in a buffer that is 255 -bytes long to make sure you can received any lora packet that comes in. +If available, this will return the size of the packet and store the packet contents into the user-provided buffer. +A max length of the buffer can be provided to avoid buffer overflow. If buffer is not large enough for entire payload, overflow is thrown out. +Recommended to pass in a buffer that is 255 bytes long to make sure you can received any lora packet that comes in. Returns -1 when no packet is available. Returns 0 when an empty packet is received (packet with no payload) -Returns payload size (1-255) when a packet with a non-zero payload is received. -If packet received is larger than the buffer provided, this will return -buffMaxLen +Returns payload size (1-255) when a packet with a non-zero payload is received. If packet received is larger than the buffer provided, this will return buffMaxLen */ int lora_receive_async(uint8_t* buff, int buffMaxLen) { - setModeReceive(); // Sets the mode to receive (if not already in receive - // mode) - - if (furi_hal_gpio_read(pin_dio1)) { - furi_hal_gpio_write(pin_beacon, true); - furi_delay_ms(50); - furi_hal_gpio_write(pin_beacon, false); - } - - // Radio pin DIO1 (interrupt) goes high when we have a packet ready. If it's - // low, there's no packet yet - if (!furi_hal_gpio_read(pin_dio1)) { - return -1; - } // Return -1, meaning no packet ready - - FURI_LOG_E(TAG, "packet ready... "); - - // Tell the radio to clear the interrupt, and set the pin back inactive. - while (furi_hal_gpio_read(pin_dio1)) { - // Clear all interrupt flags. This should result in the interrupt pin going - // low - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + setModeReceive(); // Sets the mode to receive (if not already in receive mode) + + if(furi_hal_gpio_read(pin_dio1)) { + furi_hal_gpio_write(pin_beacon, true); + furi_delay_ms(50); + furi_hal_gpio_write(pin_beacon, false); + } + + // Radio pin DIO1 (interrupt) goes high when we have a packet ready. If it's low, there's no packet yet + if(!furi_hal_gpio_read(pin_dio1)) { + return -1; + } // Return -1, meaning no packet ready + + FURI_LOG_E(TAG, "packet ready... "); + + // Tell the radio to clear the interrupt, and set the pin back inactive. + while(furi_hal_gpio_read(pin_dio1)) { + // Clear all interrupt flags. This should result in the interrupt pin going low + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + furi_hal_spi_acquire(spi); + + spiBuff[0] = 0x02; //Opcode for ClearIRQStatus command + spiBuff[1] = 0xFF; //IRQ bits to clear (MSB) (0xFFFF means clear all interrupts) + spiBuff[2] = 0xFF; //IRQ bits to clear (LSB) + + furi_hal_spi_bus_tx(spi, spiBuff, 3, timeout); + + furi_hal_spi_release(spi); + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + } + + // (Optional) Read the packet status info from the radio. + // This provides debug info about the packet we received + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select furi_hal_spi_acquire(spi); - spiBuff[0] = 0x02; // Opcode for ClearIRQStatus command - spiBuff[1] = - 0xFF; // IRQ bits to clear (MSB) (0xFFFF means clear all interrupts) - spiBuff[2] = 0xFF; // IRQ bits to clear (LSB) + spiBuff[0] = 0x14; //Opcode for get packet status + spiBuff[1] = 0xFF; //Dummy byte. Returns status + spiBuff[2] = 0xFF; //Dummy byte. Returns rssi + spiBuff[3] = 0xFF; //Dummy byte. Returns snd + spiBuff[4] = 0xFF; //Dummy byte. Returns signal RSSI + + furi_hal_spi_bus_rx(spi, spiBuff, 5, timeout); + + furi_hal_spi_release(spi); + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + + // Store these values as class variables so they can be accessed if needed + // Documentation for what these variables mean can be found in the .h file + rssi = + -((int)spiBuff[2]) / + 2; // "Average over last packet received of RSSI. Actual signal power is –RssiPkt/2 (dBm)" + snr = ((int8_t)spiBuff[3]) / + 4; // SNR is returned as a SIGNED byte, so we need to do some conversion first + signalRssi = -((int)spiBuff[4]) / 2; + + // We're almost ready to read the packet from the radio + // But first we have to know how big the packet is, and where in the radio memory it is stored + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + furi_hal_spi_acquire(spi); + + spiBuff[0] = 0x13; //Opcode for GetRxBufferStatus command + spiBuff[1] = 0xFF; //Dummy. Returns radio status + spiBuff[2] = 0xFF; //Dummy. Returns loraPacketLength + spiBuff[3] = 0xFF; //Dummy. Returns memory offset (address) + + furi_hal_spi_bus_rx(spi, spiBuff, 4, timeout); + + furi_hal_spi_release(spi); + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + + uint8_t payloadLen = spiBuff[2]; // How long the lora packet is - furi_hal_spi_bus_tx(spi, spiBuff, 3, timeout); + FURI_LOG_E(TAG, "payloadLen = %d", payloadLen); + + uint8_t startAddress = spiBuff[3]; // Where in 1262 memory is the packet stored + + // Make sure we don't overflow the buffer if the packet is larger than our buffer + if(buffMaxLen < payloadLen) { + payloadLen = buffMaxLen; + } + + // Read the radio buffer from the SX1262 into the user-supplied buffer + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + furi_hal_spi_acquire(spi); + + spiBuff[0] = 0x1E; // Opcode for ReadBuffer command + spiBuff[1] = startAddress; // SX1262 memory location to start reading from + spiBuff[2] = 0x00; // Dummy byte + furi_hal_spi_bus_tx(spi, spiBuff, 3, timeout); // Send commands to get read started + furi_hal_spi_bus_rx( + spi, + buff, + payloadLen, + timeout); // Get the contents from the radio and store it into the user provided buffer furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - } - - // (Optional) Read the packet status info from the radio. - // This provides debug info about the packet we received - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x14; // Opcode for get packet status - spiBuff[1] = 0xFF; // Dummy byte. Returns status - spiBuff[2] = 0xFF; // Dummy byte. Returns rssi - spiBuff[3] = 0xFF; // Dummy byte. Returns snd - spiBuff[4] = 0xFF; // Dummy byte. Returns signal RSSI - - furi_hal_spi_bus_rx(spi, spiBuff, 5, timeout); - - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - - // Store these values as class variables so they can be accessed if needed - // Documentation for what these variables mean can be found in the .h file - rssi = - -((int) spiBuff[2]) / 2; // "Average over last packet received of RSSI. - // Actual signal power is –RssiPkt/2 (dBm)" - snr = ((int8_t) spiBuff[3]) / 4; // SNR is returned as a SIGNED byte, so we - // need to do some conversion first - signalRssi = -((int) spiBuff[4]) / 2; - - // We're almost ready to read the packet from the radio - // But first we have to know how big the packet is, and where in the radio - // memory it is stored - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x13; // Opcode for GetRxBufferStatus command - spiBuff[1] = 0xFF; // Dummy. Returns radio status - spiBuff[2] = 0xFF; // Dummy. Returns loraPacketLength - spiBuff[3] = 0xFF; // Dummy. Returns memory offset (address) - - furi_hal_spi_bus_rx(spi, spiBuff, 4, timeout); - - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - - uint8_t payloadLen = spiBuff[2]; // How long the lora packet is - - FURI_LOG_E(TAG, "payloadLen = %d", payloadLen); - - uint8_t startAddress = - spiBuff[3]; // Where in 1262 memory is the packet stored - - // Make sure we don't overflow the buffer if the packet is larger than our - // buffer - if (buffMaxLen < payloadLen) { - payloadLen = buffMaxLen; - } - - // Read the radio buffer from the SX1262 into the user-supplied buffer - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x1E; // Opcode for ReadBuffer command - spiBuff[1] = startAddress; // SX1262 memory location to start reading from - spiBuff[2] = 0x00; // Dummy byte - furi_hal_spi_bus_tx(spi, spiBuff, 3, - timeout); // Send commands to get read started - furi_hal_spi_bus_rx(spi, buff, payloadLen, - timeout); // Get the contents from the radio and store it - // into the user provided buffer - - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - - return payloadLen; // Return how many bytes we actually read + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + + return payloadLen; // Return how many bytes we actually read } void regTest() { - uint8_t regValue; - checkBusy(); + uint8_t regValue; + checkBusy(); - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); + furi_hal_spi_acquire(spi); - spiBuff[0] = 0x1D; - spiBuff[1] = 0x07; - spiBuff[2] = 0x40; - spiBuff[3] = 0x00; + spiBuff[0] = 0x1D; + spiBuff[1] = 0x07; + spiBuff[2] = 0x40; + spiBuff[3] = 0x00; - furi_hal_spi_bus_tx(spi, spiBuff, 4, timeout); - furi_hal_spi_bus_rx(spi, ®Value, 1, timeout); + furi_hal_spi_bus_tx(spi, spiBuff, 4, timeout); + furi_hal_spi_bus_rx(spi, ®Value, 1, timeout); - furi_hal_spi_release(spi); + furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select } /* Tests that SPI is communicating correctly with the radio. - * If this fails, check your SPI wiring. This does not require any setup to - * run. We test the radio by reading a register that should have a known value. - * - * Returns: True if radio is communicating over SPI. False if no connection. - */ +* If this fails, check your SPI wiring. This does not require any setup to run. +* We test the radio by reading a register that should have a known value. +* +* Returns: True if radio is communicating over SPI. False if no connection. +*/ bool sanityCheck() { - uint8_t command_read_register[1] = {0x1D}; // OpCode for "read register" - uint8_t read_register_address[2] = {0x07, 0x40}; - uint8_t dummy_byte = 0x00; - uint8_t regValue; - - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - if (furi_hal_spi_bus_tx(spi, command_read_register, 1, timeout) && - furi_hal_spi_bus_tx(spi, read_register_address, 2, timeout) && - furi_hal_spi_bus_tx(spi, &dummy_byte, 1, timeout) && - furi_hal_spi_bus_rx(spi, ®Value, 1, timeout)) { - FURI_LOG_E(TAG, "REGISTER VALUE: %02x", regValue); - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - - if (regValue == 0x14) { - // Initialize the LED pin as output. - // GpioModeOutputPushPull means true = 3.3 volts, false = 0 volts. - // GpioModeOutputOpenDrain means true = floating, false = 0 volts. - furi_hal_gpio_init_simple(pin_beacon, GpioModeOutputPushPull); - furi_hal_gpio_write(pin_beacon, true); - furi_delay_ms(100); - furi_hal_gpio_write(pin_beacon, false); - furi_delay_ms(100); - furi_hal_gpio_write(pin_beacon, true); - furi_delay_ms(100); - furi_hal_gpio_write(pin_beacon, false); - furi_delay_ms(100); - } + uint8_t command_read_register[1] = {0x1D}; // OpCode for "read register" + uint8_t read_register_address[2] = {0x07, 0x40}; + uint8_t dummy_byte = 0x00; + uint8_t regValue; - return regValue == 0x14; // Success if we read 0x14 from the register - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - return false; - } + furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select + furi_hal_spi_acquire(spi); + + if(furi_hal_spi_bus_tx(spi, command_read_register, 1, timeout) && + furi_hal_spi_bus_tx(spi, read_register_address, 2, timeout) && + furi_hal_spi_bus_tx(spi, &dummy_byte, 1, timeout) && + furi_hal_spi_bus_rx(spi, ®Value, 1, timeout)) { + FURI_LOG_E(TAG, "REGISTER VALUE: %02x", regValue); + furi_hal_spi_release(spi); + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + + if(regValue == 0x14) { + // Initialize the LED pin as output. + // GpioModeOutputPushPull means true = 3.3 volts, false = 0 volts. + // GpioModeOutputOpenDrain means true = floating, false = 0 volts. + furi_hal_gpio_init_simple(pin_beacon, GpioModeOutputPushPull); + furi_hal_gpio_write(pin_beacon, true); + furi_delay_ms(100); + furi_hal_gpio_write(pin_beacon, false); + furi_delay_ms(100); + furi_hal_gpio_write(pin_beacon, true); + furi_delay_ms(100); + furi_hal_gpio_write(pin_beacon, false); + furi_delay_ms(100); + } + + return regValue == 0x14; // Success if we read 0x14 from the register + } else { + FURI_LOG_E(TAG, "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); + furi_hal_spi_release(spi); + furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select + return false; + } } void printRegisters(uint16_t Start, uint16_t End) { - // prints the contents of SX126x registers to serial monitor + //prints the contents of SX126x registers to serial monitor - uint16_t Loopv1, Loopv2, RegData; + uint16_t Loopv1, Loopv2, RegData; - FURI_LOG_E(TAG, "Reg 0 1 2 3 4 5 6 7 8 9 A B C D E F"); + FURI_LOG_E(TAG, "Reg 0 1 2 3 4 5 6 7 8 9 A B C D E F"); - for (Loopv1 = Start; Loopv1 <= End;) // 32 lines - { - FURI_LOG_E(TAG, "0x%02x ", Loopv1); + for(Loopv1 = Start; Loopv1 <= End;) //32 lines + { + FURI_LOG_E(TAG, "0x%02x ", Loopv1); - for (Loopv2 = 0; Loopv2 <= 15; Loopv2++) { - RegData = readRegister(Loopv1); - if (RegData < 0x10) { - // FURI_LOG_E(TAG,"0"); - } + for(Loopv2 = 0; Loopv2 <= 15; Loopv2++) { + RegData = readRegister(Loopv1); + if(RegData < 0x10) { + //FURI_LOG_E(TAG,"0"); + } - FURI_LOG_E(TAG, "0x%02x ", RegData); + FURI_LOG_E(TAG, "0x%02x ", RegData); - Loopv1++; + Loopv1++; + } + FURI_LOG_E(TAG, "\n"); } - FURI_LOG_E(TAG, "\n"); - } } bool begin() { - // furi_hal_gpio_init(pin_reset, GpioModeOutputPushPull, GpioPullUp, - // GpioSpeedVeryHigh); furi_hal_gpio_init(pin_nss1, GpioModeOutputPushPull, - // GpioPullUp, GpioSpeedVeryHigh); + //furi_hal_gpio_init(pin_reset, GpioModeOutputPushPull, GpioPullUp, GpioSpeedVeryHigh); + //furi_hal_gpio_init(pin_nss1, GpioModeOutputPushPull, GpioPullUp, GpioSpeedVeryHigh); - furi_hal_gpio_init_simple(pin_reset, GpioModeOutputPushPull); - furi_hal_gpio_init_simple(pin_nss1, GpioModeOutputPushPull); + furi_hal_gpio_init_simple(pin_reset, GpioModeOutputPushPull); + furi_hal_gpio_init_simple(pin_nss1, GpioModeOutputPushPull); - furi_hal_gpio_init_simple(pin_beacon, GpioModeOutputPushPull); + furi_hal_gpio_init_simple(pin_beacon, GpioModeOutputPushPull); - furi_hal_gpio_write(pin_nss1, true); - furi_hal_gpio_write(pin_reset, true); + furi_hal_gpio_write(pin_nss1, true); + furi_hal_gpio_write(pin_reset, true); - furi_hal_gpio_init_simple(pin_dio1, GpioModeInput); + furi_hal_gpio_init_simple(pin_dio1, GpioModeInput); - FURI_LOG_E(TAG, "RESET DEVICE..."); - furi_delay_ms(10); - furi_hal_gpio_write(pin_reset, false); - furi_delay_ms(2); - furi_hal_gpio_write(pin_reset, true); - furi_delay_ms(25); + FURI_LOG_E(TAG, "RESET DEVICE..."); + furi_delay_ms(10); + furi_hal_gpio_write(pin_reset, false); + furi_delay_ms(2); + furi_hal_gpio_write(pin_reset, true); + furi_delay_ms(25); - checkBusy(); + checkBusy(); - // Ensure SPI communication is working with the radio - FURI_LOG_E(TAG, "SANITYCHECK..."); - bool success = sanityCheck(); - if (!success) { - return false; - } + //Ensure SPI communication is working with the radio + FURI_LOG_E(TAG, "SANITYCHECK..."); + bool success = sanityCheck(); + if(!success) { + return false; + } - // Run the bare-minimum required SPI commands to set up the radio to use - configureRadioEssentials(); + //Run the bare-minimum required SPI commands to set up the radio to use + configureRadioEssentials(); - uint32_t lora_freq = getFreqInt(); + uint32_t lora_freq = getFreqInt(); - FURI_LOG_E(TAG, " FREQUENCY: %ld", lora_freq); + FURI_LOG_E(TAG, " FREQUENCY: %ld", lora_freq); - return true; // Return success that we set up the radio + return true; //Return success that we set up the radio } diff --git a/applications_user/lora_app/lora_relay.c b/applications_user/lora_app/lora_relay.c index 228343a..d4e0b46 100644 --- a/applications_user/lora_app/lora_relay.c +++ b/applications_user/lora_app/lora_relay.c @@ -1,14 +1,14 @@ #include #include #include -#include +#include +#include +#include #include #include -#include +#include #include -#include -#include -#include +#include #include #include @@ -52,178 +52,174 @@ bool configSetFrequency(long frequencyInHz); bool configSetBandwidth(int bw); bool configSetSpreadingFactor(int sf); bool configSetCodingRate(int cr); -void setPacketParams(uint16_t packetParam1, - uint8_t packetParam2, - uint8_t packetParam3, - uint8_t packetParam4, - uint8_t packetParam5); +void setPacketParams( + uint16_t packetParam1, + uint8_t packetParam2, + uint8_t packetParam3, + uint8_t packetParam4, + uint8_t packetParam5); void transmit(uint8_t* data, int dataLen); -// Change this to BACKLIGHT_AUTO if you don't want the backlight to be -// continuously on. +// Change this to BACKLIGHT_AUTO if you don't want the backlight to be continuously on. #define BACKLIGHT_ON 1 // Our application menu has 6 items. You can add more items if you want. typedef enum { - LoRaSubmenuIndexConfigure, - LoRaSubmenuIndexLoRaWAN, - LoRaSubmenuIndexSniffer, - LoRaSubmenuIndexTransmitter, - LoRaSubmenuIndexManualTX, - LoRaSubmenuIndexAbout, + LoRaSubmenuIndexConfigure, + LoRaSubmenuIndexLoRaWAN, + LoRaSubmenuIndexSniffer, + LoRaSubmenuIndexTransmitter, + LoRaSubmenuIndexManualTX, + LoRaSubmenuIndexAbout, } LoRaSubmenuIndex; // Each view is a screen we show the user. typedef enum { - LoRaViewSubmenu, // The menu when the app starts - LoRaViewFrequencyInput, // Input for configuring frequency settings - LoRaViewByteInput, // Input for send data (bytes) - LoRaViewConfigure, // The configuration screen - LoRaViewLoRaWAN, // The presets LoRaWAN screen - LoRaViewSniffer, // Sniffer - LoraViewTransmitter, // Transmitter - LoRaViewAbout, // The about screen with directions, link to social channel, - // etc. + LoRaViewSubmenu, // The menu when the app starts + LoRaViewFrequencyInput, // Input for configuring frequency settings + LoRaViewByteInput, // Input for send data (bytes) + LoRaViewConfigure, // The configuration screen + LoRaViewLoRaWAN, // The presets LoRaWAN screen + LoRaViewSniffer, // Sniffer + LoraViewTransmitter, // Transmitter + LoRaViewAbout, // The about screen with directions, link to social channel, etc. } LoRaView; typedef enum { - LoRaEventIdRedrawScreen = 0, // Custom event to redraw the screen - LoRaEventIdOkPressed = - 42, // Custom event to process OK button getting pressed down + LoRaEventIdRedrawScreen = 0, // Custom event to redraw the screen + LoRaEventIdOkPressed = 42, // Custom event to process OK button getting pressed down } LoRaEventId; typedef struct { - ViewDispatcher* view_dispatcher; // Switches between our views - NotificationApp* notifications; // Used for controlling the backlight - Submenu* submenu; // The application menu - TextInput* frequency_input; // The text input screen - ByteInput* byte_input; // The byte input screen + ViewDispatcher* view_dispatcher; // Switches between our views + NotificationApp* notifications; // Used for controlling the backlight + Submenu* submenu; // The application menu + TextInput* frequency_input; // The text input screen + ByteInput* byte_input; // The byte input screen - VariableItemList* variable_item_list_config; // The configuration screen - VariableItemList* variable_item_list_lorawan; // The lorawan presets screen + VariableItemList* variable_item_list_config; // The configuration screen + VariableItemList* variable_item_list_lorawan; // The lorawan presets screen - View* view_sniffer; // The sniffer screen - View* view_transmitter; // The transmitter screen - Widget* widget_about; // The about screen + View* view_sniffer; // The sniffer screen + View* view_transmitter; // The transmitter screen + Widget* widget_about; // The about screen - VariableItem* config_freq_item; // The frequency setting item (so we can - // update the frequency) - char* temp_buffer; // Temporary buffer for text input - uint32_t temp_buffer_size; // Size of temporary buffer + VariableItem* config_freq_item; // The frequency setting item (so we can update the frequency) + char* temp_buffer; // Temporary buffer for text input + uint32_t temp_buffer_size; // Size of temporary buffer - uint8_t* byte_buffer; // Temporary buffer for text input - uint32_t byte_buffer_size; // Size of temporary buffer + uint8_t* byte_buffer; // Temporary buffer for text input + uint32_t byte_buffer_size; // Size of temporary buffer - FuriTimer* timer_rx; // Timer for redrawing the sniffer screen - FuriTimer* timer_tx; // Timer for redrawing the transmitter screen + FuriTimer* timer_rx; // Timer for redrawing the sniffer screen + FuriTimer* timer_tx; // Timer for redrawing the transmitter screen - uint32_t config_frequency; + uint32_t config_frequency; - // Order is preamble, header type, packet length, CRC, IQ - uint16_t packetPreamble; - uint8_t packetHeaderType; - uint8_t packetPayloadLength; - uint8_t packetCRC; - uint8_t packetInvertIQ; + // Order is preamble, header type, packet length, CRC, IQ + uint16_t packetPreamble; + uint8_t packetHeaderType; + uint8_t packetPayloadLength; + uint8_t packetCRC; + uint8_t packetInvertIQ; } LoRaApp; typedef struct { - FuriString* config_freq_name; // The frequency setting - uint32_t config_bw_index; // Bandwidth setting index - uint32_t config_sf_index; // Spread Factor setting index - uint32_t config_cr_index; // Coding Rate setting index - - uint32_t config_header_type_index; // Header Type setting index - uint32_t config_crc_index; // CRC setting index - uint32_t config_iq_index; // IQ setting index - - uint32_t config_region_index; // Frequency plan setting index - uint32_t config_bw_region_index; // BW region setting index - uint32_t config_us_dr_index; // US915 Data Rate setting index - uint32_t config_eu_dr_index; // EU868 Data Rate setting index - - uint32_t config_us915_ul_channels_125k_index; - uint32_t config_us915_ul_channels_500k_index; - uint32_t config_eu868_ul_channels_125k_index; - - uint32_t config_eu868_ul_channels_250k_index; - uint32_t config_us915_dl_channels_500k_index; - uint32_t config_eu868_dl_channels_rx1_index; - - uint8_t x; // The x coordinate (dummy variable) - - bool flag_file; - DialogsApp* dialogs_rx; - Storage* storage_rx; - File* file_rx; + FuriString* config_freq_name; // The frequency setting + uint32_t config_bw_index; // Bandwidth setting index + uint32_t config_sf_index; // Spread Factor setting index + uint32_t config_cr_index; // Coding Rate setting index + + uint32_t config_header_type_index; // Header Type setting index + uint32_t config_crc_index; // CRC setting index + uint32_t config_iq_index; // IQ setting index + + uint32_t config_region_index; // Frequency plan setting index + uint32_t config_bw_region_index; // BW region setting index + uint32_t config_us_dr_index; // US915 Data Rate setting index + uint32_t config_eu_dr_index; // EU868 Data Rate setting index + + uint32_t config_us915_ul_channels_125k_index; + uint32_t config_us915_ul_channels_500k_index; + uint32_t config_eu868_ul_channels_125k_index; + + uint32_t config_eu868_ul_channels_250k_index; + uint32_t config_us915_dl_channels_500k_index; + uint32_t config_eu868_dl_channels_rx1_index; + + uint8_t x; // The x coordinate (dummy variable) + + bool flag_file; + DialogsApp* dialogs_rx; + Storage* storage_rx; + File* file_rx; } LoRaSnifferModel; typedef struct { - uint32_t test; - bool flag_tx_file; - bool flag_signal; - FuriString* text; - DialogsApp* dialogs_tx; - Storage* storage_tx; - File* file_tx; - uint8_t x; // The x coordinate + uint32_t test; + bool flag_tx_file; + bool flag_signal; + FuriString* text; + DialogsApp* dialogs_tx; + Storage* storage_tx; + File* file_tx; + uint8_t x; // The x coordinate } LoRaTransmitterModel; void makePaths(void* context) { - LoRaApp* app = (LoRaApp*) context; - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - furi_assert(app); - if (!storage_simply_mkdir(model->storage_rx, PATHAPPEXT)) { - dialog_message_show_storage_error(model->dialogs_rx, - "Cannot create\napp folder"); - } + LoRaApp* app = (LoRaApp*)context; + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + furi_assert(app); + if(!storage_simply_mkdir(model->storage_rx, PATHAPPEXT)) { + dialog_message_show_storage_error(model->dialogs_rx, "Cannot create\napp folder"); + } } /** * @brief Callback for exiting the application. - * @details This function is called when user press back button. We return - * VIEW_NONE to indicate that we want to exit the application. + * @details This function is called when user press back button. We return VIEW_NONE to + * indicate that we want to exit the application. * @param _context The context - unused * @return next view id - */ +*/ static uint32_t lora_navigation_exit_callback(void* _context) { - UNUSED(_context); - return VIEW_NONE; + UNUSED(_context); + return VIEW_NONE; } /** * @brief Callback for returning to submenu. - * @details This function is called when user press back button. We return - * VIEW_NONE to indicate that we want to navigate to the submenu. + * @details This function is called when user press back button. We return VIEW_NONE to + * indicate that we want to navigate to the submenu. * @param _context The context - unused * @return next view id - */ +*/ static uint32_t lora_navigation_submenu_callback(void* _context) { - UNUSED(_context); - return LoRaViewSubmenu; + UNUSED(_context); + return LoRaViewSubmenu; } /** * @brief Callback for returning to configure screen. - * @details This function is called when user press back button. We return - * VIEW_NONE to indicate that we want to navigate to the configure screen. + * @details This function is called when user press back button. We return VIEW_NONE to + * indicate that we want to navigate to the configure screen. * @param _context The context - unused * @return next view id - */ +*/ static uint32_t lora_navigation_configure_callback(void* _context) { - UNUSED(_context); - return LoRaViewConfigure; + UNUSED(_context); + return LoRaViewConfigure; } /** * @brief Callback for returning to LoRaWAN screen. - * @details This function is called when user press back button. We return - * VIEW_NONE to indicate that we want to navigate to the LoRaWAN screen. + * @details This function is called when user press back button. We return VIEW_NONE to + * indicate that we want to navigate to the LoRaWAN screen. * @param _context The context - unused * @return next view id - */ +*/ // +++++++++++++++ TODO +++++++++++++++ // not used at the moment @@ -235,60 +231,90 @@ static uint32_t lora_navigation_configure_callback(void* _context) { /** * @brief Handle submenu item selection. - * @details This function is called when user selects an item from the - * submenu. + * @details This function is called when user selects an item from the submenu. * @param context The context - LoRaApp object. * @param index The LoRaSubmenuIndex item that was clicked. - */ +*/ static void lora_submenu_callback(void* context, uint32_t index) { - LoRaApp* app = (LoRaApp*) context; - switch (index) { + LoRaApp* app = (LoRaApp*)context; + switch(index) { case LoRaSubmenuIndexConfigure: - view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewConfigure); - break; + view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewConfigure); + break; case LoRaSubmenuIndexLoRaWAN: - view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewLoRaWAN); - break; + view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewLoRaWAN); + break; case LoRaSubmenuIndexSniffer: - view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewSniffer); - break; + view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewSniffer); + break; case LoRaSubmenuIndexTransmitter: - view_dispatcher_switch_to_view(app->view_dispatcher, LoraViewTransmitter); - break; + view_dispatcher_switch_to_view(app->view_dispatcher, LoraViewTransmitter); + break; case LoRaSubmenuIndexManualTX: - view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewByteInput); - break; + view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewByteInput); + break; case LoRaSubmenuIndexAbout: - view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewAbout); - break; + view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewAbout); + break; default: - break; - } + break; + } } // Bandwidth configuration const uint8_t config_bw_values[] = { - 0x00, 0x08, 0x01, 0x09, 0x02, 0x0A, 0x03, 0x04, 0x05, 0x06, + 0x00, + 0x08, + 0x01, + 0x09, + 0x02, + 0x0A, + 0x03, + 0x04, + 0x05, + 0x06, }; const char* const config_bw_names[] = { - "7.81 kHz", "10.42 kHz", "15.63 kHz", "20.83 kHz", "31.25 kHz", - "41.67 kHz", "62.50 kHz", "125 kHz", "250 kHz", "500 kHz", + "7.81 kHz", + "10.42 kHz", + "15.63 kHz", + "20.83 kHz", + "31.25 kHz", + "41.67 kHz", + "62.50 kHz", + "125 kHz", + "250 kHz", + "500 kHz", }; // Spreading Factor configuration const uint8_t config_sf_values[] = { - 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, }; const char* const config_sf_names[] = { - "SF5", "SF6", "SF7", "SF8", "SF9", "SF10", "SF11", "SF12", + "SF5", + "SF6", + "SF7", + "SF8", + "SF9", + "SF10", + "SF11", + "SF12", }; // Coding Rate configuration const uint8_t config_cr_values[] = { - 0x01, // 4/5 - 0x02, // 4/6 - 0x03, // 4/7 - 0x04, // 4/8 + 0x01, // 4/5 + 0x02, // 4/6 + 0x03, // 4/7 + 0x04, // 4/8 }; const char* const config_cr_names[] = { @@ -299,7 +325,8 @@ const char* const config_cr_names[] = { }; const uint8_t config_region_values[] = { - 0x01, 0x02 + 0x01, + 0x02 //, // 0x03, // 0x04, @@ -316,7 +343,8 @@ const uint8_t config_region_values[] = { // Regional names const char* const config_region_names[] = { - "EU868", "US915" + "EU868", + "US915" //, // "CN779", // "EU433", @@ -333,91 +361,105 @@ const char* const config_region_names[] = { // Data Rate configuration for US915 const uint8_t config_us_dr_values[] = { - 0x00, // DR0 - 0x01, // DR1 - 0x02, // DR2 - 0x03, // DR3 - 0x04, // DR4 - 0x08, // DR8 - 0x09, // DR9 - 0x0A, // DR10 - 0x0B, // DR11 - 0x0C, // DR12 - 0x0D // DR13 + 0x00, // DR0 + 0x01, // DR1 + 0x02, // DR2 + 0x03, // DR3 + 0x04, // DR4 + 0x08, // DR8 + 0x09, // DR9 + 0x0A, // DR10 + 0x0B, // DR11 + 0x0C, // DR12 + 0x0D // DR13 }; const char* const config_us_dr_names[] = { - "SF10/125kHz", "SF9/125kHz", "SF8/125kHz", "SF7/125kHz", - "SF8/500kHz", "SF12/500kHz", "SF11/500kHz", "SF10/500kHz", - "SF9/500kHz", "SF8/500kHz", "SF7/500kHz"}; + "SF10/125kHz", + "SF9/125kHz", + "SF8/125kHz", + "SF7/125kHz", + "SF8/500kHz", + "SF12/500kHz", + "SF11/500kHz", + "SF10/500kHz", + "SF9/500kHz", + "SF8/500kHz", + "SF7/500kHz"}; // Data Rate configuration for EU868 -const uint8_t config_eu_dr_values[] = {0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06}; +const uint8_t config_eu_dr_values[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; const char* const config_eu_dr_names[] = { - "SF12/125kHz", "SF11/125kHz", "SF10/125kHz", "SF9/125kHz", - "SF8/125kHz", "SF7/125kHz", "SF7/250kHz"}; + "SF12/125kHz", + "SF11/125kHz", + "SF10/125kHz", + "SF9/125kHz", + "SF8/125kHz", + "SF7/125kHz", + "SF7/250kHz"}; // Transmit Power configuration for US915 const uint8_t config_txpower_values[] = { - 0x00, // 30 dBm - 0x01, // 28 dBm - 0x02, // 26 dBm - 0x03, // 24 dBm - 0x04, // 22 dBm - 0x05, // 20 dBm - 0x06, // 18 dBm - 0x07, // 16 dBm - 0x08, // 14 dBm - 0x09, // 12 dBm - 0x0A // 10 dBm + 0x00, // 30 dBm + 0x01, // 28 dBm + 0x02, // 26 dBm + 0x03, // 24 dBm + 0x04, // 22 dBm + 0x05, // 20 dBm + 0x06, // 18 dBm + 0x07, // 16 dBm + 0x08, // 14 dBm + 0x09, // 12 dBm + 0x0A // 10 dBm }; const char* const config_txpower_names[] = { - "30 dBm", "28 dBm", "26 dBm", "24 dBm", "22 dBm", "20 dBm", - "18 dBm", "16 dBm", "14 dBm", "12 dBm", "10 dBm"}; + "30 dBm", + "28 dBm", + "26 dBm", + "24 dBm", + "22 dBm", + "20 dBm", + "18 dBm", + "16 dBm", + "14 dBm", + "12 dBm", + "10 dBm"}; // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Uplink channel frequencies for US915 (125 kHz channels) const uint32_t config_us915_ul_channels_125k[] = { - 902300000, 902500000, 902700000, 902900000, 903100000, 903300000, 903500000, - 903700000, 903900000, 904100000, 904300000, 904500000, 904700000, 904900000, - 905100000, 905300000, 905500000, 905700000, 905900000, 906100000, 906300000, - 906500000, 906700000, 906900000, 907100000, 907300000, 907500000, 907700000, - 907900000, 908100000, 908300000, 908500000, 908700000, 908900000, 909100000, - 909300000, 909500000, 909700000, 909900000, 910100000, 910300000, 910500000, - 910700000, 910900000, 911100000, 911300000, 911500000, 911700000, 911900000, - 912100000, 912300000, 912500000, 912700000, 912900000, 913100000, 913300000, - 913500000, 913700000, 913900000, 914100000, 914300000, 914500000, 914700000, - 914900000}; + 902300000, 902500000, 902700000, 902900000, 903100000, 903300000, 903500000, 903700000, + 903900000, 904100000, 904300000, 904500000, 904700000, 904900000, 905100000, 905300000, + 905500000, 905700000, 905900000, 906100000, 906300000, 906500000, 906700000, 906900000, + 907100000, 907300000, 907500000, 907700000, 907900000, 908100000, 908300000, 908500000, + 908700000, 908900000, 909100000, 909300000, 909500000, 909700000, 909900000, 910100000, + 910300000, 910500000, 910700000, 910900000, 911100000, 911300000, 911500000, 911700000, + 911900000, 912100000, 912300000, 912500000, 912700000, 912900000, 913100000, 913300000, + 913500000, 913700000, 913900000, 914100000, 914300000, 914500000, 914700000, 914900000}; // Uplink channel frequencies for US915 (500 kHz channels) -const uint32_t config_us915_ul_channels_500k[] = { - 903000000, 904600000, 906200000, 907800000, - 909400000, 911000000, 912600000, 914200000}; +const uint32_t config_us915_ul_channels_500k[] = + {903000000, 904600000, 906200000, 907800000, 909400000, 911000000, 912600000, 914200000}; // Downlink channel frequencies for US915 -const uint32_t config_us915_dl_channels_500k[] = { - 923300000, 923900000, 924500000, 925100000, - 925700000, 926300000, 926900000, 927500000}; +const uint32_t config_us915_dl_channels_500k[] = + {923300000, 923900000, 924500000, 925100000, 925700000, 926300000, 926900000, 927500000}; // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Uplink channel frequencies for EU868 (125 kHz default channels) -const uint32_t config_eu868_ul_channels_125k[] = {868100000, 868300000, - 868500000}; +const uint32_t config_eu868_ul_channels_125k[] = {868100000, 868300000, 868500000}; // Uplink channel frequencies for EU868 (250 kHz channel) const uint32_t config_eu868_ul_channels_250k[] = {868300000}; -// Additional uplink channel frequencies for EU868 (may be used depending on -// local regulations) -const uint32_t config_eu868_ul_channels_additional[] = { - 867100000, 867300000, 867500000, 867700000, 867900000}; +// Additional uplink channel frequencies for EU868 (may be used depending on local regulations) +const uint32_t config_eu868_ul_channels_additional[] = + {867100000, 867300000, 867500000, 867700000, 867900000}; // Downlink channel frequencies for EU868 (RX1 - same as uplink) -const uint32_t config_eu868_dl_channels_rx1[] = {868100000, 868300000, - 868500000}; +const uint32_t config_eu868_dl_channels_rx1[] = {868100000, 868300000, 868500000}; // Downlink channel frequency for EU868 (RX2 - fixed frequency) const uint32_t config_eu868_dl_channel_rx2 = 869525000; @@ -427,10 +469,9 @@ const uint32_t config_eu868_dl_channel_rx2 = 869525000; // Uplink channel frequencies for AS923 (125 kHz default channels) const uint32_t config_as923_ul_channels_125k[] = {923200000, 923400000}; -// Additional uplink channel frequencies for AS923 (may be used depending on -// local regulations) -const uint32_t config_as923_ul_channels_additional[] = { - 923600000, 923800000, 924000000, 924200000, 924400000, 924600000}; +// Additional uplink channel frequencies for AS923 (may be used depending on local regulations) +const uint32_t config_as923_ul_channels_additional[] = + {923600000, 923800000, 924000000, 924200000, 924400000, 924600000}; // Downlink channel frequencies for AS923 (RX1 - same as uplink) const uint32_t config_as923_dl_channels_rx1[] = {923200000, 923400000}; @@ -440,15 +481,15 @@ const uint32_t config_as923_dl_channel_rx2 = 923200000; // Frequency offsets for different AS923 sub-bands const int32_t config_as923_frequency_offsets[] = { - 0, // AS923-1 - -1800000, // AS923-2 - -6600000, // AS923-3 - -5900000 // AS923-4 + 0, // AS923-1 + -1800000, // AS923-2 + -6600000, // AS923-3 + -5900000 // AS923-4 }; // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -// Header Type. 0x00 = Variable Len, 0x01 = Fixed Length +//Header Type. 0x00 = Variable Len, 0x01 = Fixed Length const uint8_t config_header_type_values[] = { 0x00, 0x01, @@ -458,7 +499,7 @@ const char* const config_header_type_names[] = { "Fixed Length", }; -// CRC. 0x00 = Off, 0x01 = On +//CRC. 0x00 = Off, 0x01 = On const uint8_t config_crc_values[] = { 0x00, 0x01, @@ -468,7 +509,7 @@ const char* const config_crc_names[] = { "On", }; -// IQ. 0x00 = Standard, 0x01 = Inverted +//IQ. 0x00 = Standard, 0x01 = Inverted const uint8_t config_iq_values[] = { 0x00, 0x01, @@ -481,1752 +522,1834 @@ const char* const config_iq_names[] = { static const char* config_bw_label = "Bandwidth"; static void lora_config_bw_change(VariableItem* item) { - LoRaApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, config_bw_names[index]); - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - model->config_bw_index = index; + LoRaApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, config_bw_names[index]); + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + model->config_bw_index = index; - configSetBandwidth(config_bw_values[index]); + configSetBandwidth(config_bw_values[index]); } static const char* config_sf_label = "Spread Factor"; static void lora_config_sf_change(VariableItem* item) { - LoRaApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, config_sf_names[index]); - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - model->config_sf_index = index; + LoRaApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, config_sf_names[index]); + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + model->config_sf_index = index; - configSetSpreadingFactor(config_sf_values[index]); + configSetSpreadingFactor(config_sf_values[index]); } static const char* config_cr_label = "Coding Rate"; static void lora_config_cr_change(VariableItem* item) { - LoRaApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, config_cr_names[index]); - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - model->config_cr_index = index; + LoRaApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, config_cr_names[index]); + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + model->config_cr_index = index; - configSetCodingRate(config_cr_values[index]); + configSetCodingRate(config_cr_values[index]); } static const char* config_header_type_label = "Header Type"; static void lora_config_header_type_change(VariableItem* item) { - LoRaApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, config_header_type_names[index]); - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - model->config_header_type_index = index; - - app->packetHeaderType = config_header_type_values[index]; - - // Order is preamble, header type, packet length, CRC, IQ - setPacketParams(app->packetPreamble, app->packetHeaderType, - app->packetPayloadLength, app->packetCRC, - app->packetInvertIQ); + LoRaApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, config_header_type_names[index]); + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + model->config_header_type_index = index; + + app->packetHeaderType = config_header_type_values[index]; + + // Order is preamble, header type, packet length, CRC, IQ + setPacketParams( + app->packetPreamble, + app->packetHeaderType, + app->packetPayloadLength, + app->packetCRC, + app->packetInvertIQ); } static const char* config_crc_label = "CRC"; static void lora_config_crc_change(VariableItem* item) { - LoRaApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, config_crc_names[index]); - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - model->config_crc_index = index; - - app->packetCRC = config_crc_values[index]; - - // Order is preamble, header type, packet length, CRC, IQ - setPacketParams(app->packetPreamble, app->packetHeaderType, - app->packetPayloadLength, app->packetCRC, - app->packetInvertIQ); + LoRaApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, config_crc_names[index]); + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + model->config_crc_index = index; + + app->packetCRC = config_crc_values[index]; + + // Order is preamble, header type, packet length, CRC, IQ + setPacketParams( + app->packetPreamble, + app->packetHeaderType, + app->packetPayloadLength, + app->packetCRC, + app->packetInvertIQ); } static const char* config_iq_label = "IQ"; static void lora_config_iq_change(VariableItem* item) { - LoRaApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - - variable_item_set_current_value_text(item, config_iq_names[index]); - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - model->config_iq_index = index; - - app->packetInvertIQ = config_iq_values[index]; - - // Order is preamble, header type, packet length, CRC, IQ - setPacketParams(app->packetPreamble, app->packetHeaderType, - app->packetPayloadLength, app->packetCRC, - app->packetInvertIQ); + LoRaApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, config_iq_names[index]); + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + model->config_iq_index = index; + + app->packetInvertIQ = config_iq_values[index]; + + // Order is preamble, header type, packet length, CRC, IQ + setPacketParams( + app->packetPreamble, + app->packetHeaderType, + app->packetPayloadLength, + app->packetCRC, + app->packetInvertIQ); } static const char* config_eu_dr_label = "EU868 Data Rate"; static void lora_config_eu_dr_change(VariableItem* item) { - VariableItem* alt_item; - LoRaApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, config_eu_dr_names[index]); - - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - model->config_eu_dr_index = index; - - switch (index) { - case 0: // SF12/125kHz - configSetSpreadingFactor(0xC); - configSetBandwidth(0x04); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 7); - variable_item_set_current_value_text(alt_item, config_bw_names[7]); - model->config_bw_index = 7; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 7); - variable_item_set_current_value_text(alt_item, config_sf_names[7]); - model->config_sf_index = 7; - - break; - case 1: // SF11/125kHz - configSetSpreadingFactor(0x0B); - configSetBandwidth(0x04); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 7); - variable_item_set_current_value_text(alt_item, config_bw_names[7]); - model->config_bw_index = 7; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 6); - variable_item_set_current_value_text(alt_item, config_sf_names[6]); - model->config_sf_index = 6; - - break; - case 2: // SF10/125kHz - configSetSpreadingFactor(0x0A); - configSetBandwidth(0x04); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 7); - variable_item_set_current_value_text(alt_item, config_bw_names[7]); - model->config_bw_index = 7; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 5); - variable_item_set_current_value_text(alt_item, config_sf_names[5]); - model->config_sf_index = 5; - - break; - case 3: // SF9/125kHz - configSetSpreadingFactor(0x09); - configSetBandwidth(0x04); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 7); - variable_item_set_current_value_text(alt_item, config_bw_names[7]); - model->config_bw_index = 7; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 4); - variable_item_set_current_value_text(alt_item, config_sf_names[4]); - model->config_sf_index = 4; - - break; - case 4: // SF8/125kHz - configSetSpreadingFactor(0x08); - configSetBandwidth(0x04); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 7); - variable_item_set_current_value_text(alt_item, config_bw_names[7]); - model->config_bw_index = 7; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 3); - variable_item_set_current_value_text(alt_item, config_sf_names[3]); - model->config_sf_index = 3; - - break; - case 5: // SF7/125kHz - configSetSpreadingFactor(0x07); - configSetBandwidth(0x04); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 7); - variable_item_set_current_value_text(alt_item, config_bw_names[7]); - model->config_bw_index = 7; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 2); - variable_item_set_current_value_text(alt_item, config_sf_names[2]); - model->config_sf_index = 2; - - break; - case 6: // SF7/250kHz - configSetSpreadingFactor(0x07); - configSetBandwidth(0x06); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 9); - variable_item_set_current_value_text(alt_item, config_bw_names[9]); - model->config_bw_index = 9; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 1); - variable_item_set_current_value_text(alt_item, config_sf_names[1]); - model->config_sf_index = 1; - - break; - } + VariableItem* alt_item; + LoRaApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, config_eu_dr_names[index]); + + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + model->config_eu_dr_index = index; + + switch(index) { + case 0: // SF12/125kHz + configSetSpreadingFactor(0xC); + configSetBandwidth(0x04); + + alt_item = (VariableItem*)variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 7); + variable_item_set_current_value_text(alt_item, config_bw_names[7]); + model->config_bw_index = 7; + + alt_item = (VariableItem*)variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 7); + variable_item_set_current_value_text(alt_item, config_sf_names[7]); + model->config_sf_index = 7; + + break; + case 1: // SF11/125kHz + configSetSpreadingFactor(0x0B); + configSetBandwidth(0x04); + + alt_item = (VariableItem*)variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 7); + variable_item_set_current_value_text(alt_item, config_bw_names[7]); + model->config_bw_index = 7; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 6); + variable_item_set_current_value_text(alt_item, config_sf_names[6]); + model->config_sf_index = 6; + + break; + case 2: // SF10/125kHz + configSetSpreadingFactor(0x0A); + configSetBandwidth(0x04); + + alt_item = variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 7); + variable_item_set_current_value_text(alt_item, config_bw_names[7]); + model->config_bw_index = 7; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 5); + variable_item_set_current_value_text(alt_item, config_sf_names[5]); + model->config_sf_index = 5; + + break; + case 3: // SF9/125kHz + configSetSpreadingFactor(0x09); + configSetBandwidth(0x04); + + alt_item = variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 7); + variable_item_set_current_value_text(alt_item, config_bw_names[7]); + model->config_bw_index = 7; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 4); + variable_item_set_current_value_text(alt_item, config_sf_names[4]); + model->config_sf_index = 4; + + break; + case 4: // SF8/125kHz + configSetSpreadingFactor(0x08); + configSetBandwidth(0x04); + + alt_item = variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 7); + variable_item_set_current_value_text(alt_item, config_bw_names[7]); + model->config_bw_index = 7; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 3); + variable_item_set_current_value_text(alt_item, config_sf_names[3]); + model->config_sf_index = 3; + + break; + case 5: // SF7/125kHz + configSetSpreadingFactor(0x07); + configSetBandwidth(0x04); + + alt_item = variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 7); + variable_item_set_current_value_text(alt_item, config_bw_names[7]); + model->config_bw_index = 7; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 2); + variable_item_set_current_value_text(alt_item, config_sf_names[2]); + model->config_sf_index = 2; + + break; + case 6: // SF7/250kHz + configSetSpreadingFactor(0x07); + configSetBandwidth(0x06); + + alt_item = variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 9); + variable_item_set_current_value_text(alt_item, config_bw_names[9]); + model->config_bw_index = 9; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 1); + variable_item_set_current_value_text(alt_item, config_sf_names[1]); + model->config_sf_index = 1; + + break; + } } static const char* config_us_dr_label = "US915 Data Rate"; static void lora_config_us_dr_change(VariableItem* item) { - VariableItem* alt_item; - LoRaApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, config_us_dr_names[index]); - - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - model->config_us_dr_index = index; - - switch (index) { - case 0: // SF10/125kHz - configSetSpreadingFactor(0x0A); - configSetBandwidth(0x04); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 7); - variable_item_set_current_value_text(alt_item, config_bw_names[7]); - model->config_bw_index = 7; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 5); - variable_item_set_current_value_text(alt_item, config_sf_names[5]); - model->config_sf_index = 5; - - break; - case 1: // SF9/125kHz - configSetSpreadingFactor(0x09); - configSetBandwidth(0x04); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 7); - variable_item_set_current_value_text(alt_item, config_bw_names[7]); - model->config_bw_index = 7; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 4); - variable_item_set_current_value_text(alt_item, config_sf_names[4]); - model->config_sf_index = 4; - - break; - case 2: // SF8/125kHz - configSetSpreadingFactor(0x08); - configSetBandwidth(0x04); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 7); - variable_item_set_current_value_text(alt_item, config_bw_names[7]); - model->config_bw_index = 7; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 3); - variable_item_set_current_value_text(alt_item, config_sf_names[3]); - model->config_sf_index = 3; - - break; - case 3: // SF7/125kHz - configSetSpreadingFactor(0x07); - configSetBandwidth(0x04); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 7); - variable_item_set_current_value_text(alt_item, config_bw_names[7]); - model->config_bw_index = 7; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 2); - variable_item_set_current_value_text(alt_item, config_sf_names[2]); - model->config_sf_index = 2; - - break; - case 4: // SF8/500kHz - configSetSpreadingFactor(0x08); - configSetBandwidth(0x06); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 9); - variable_item_set_current_value_text(alt_item, config_bw_names[9]); - model->config_bw_index = 9; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 3); - variable_item_set_current_value_text(alt_item, config_sf_names[3]); - model->config_sf_index = 3; - - break; - case 5: // SF12/500kHz - configSetSpreadingFactor(0x0C); - configSetBandwidth(0x06); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 9); - variable_item_set_current_value_text(alt_item, config_bw_names[9]); - model->config_bw_index = 9; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 7); - variable_item_set_current_value_text(alt_item, config_sf_names[7]); - model->config_sf_index = 7; - - break; - case 6: // SF11/500kHz - configSetSpreadingFactor(0x0B); - configSetBandwidth(0x06); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 9); - variable_item_set_current_value_text(alt_item, config_bw_names[9]); - model->config_bw_index = 9; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 6); - variable_item_set_current_value_text(alt_item, config_sf_names[6]); - model->config_sf_index = 6; - - break; - case 7: // SF10/500kHz - configSetSpreadingFactor(0x0A); - configSetBandwidth(0x06); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 9); - variable_item_set_current_value_text(alt_item, config_bw_names[9]); - model->config_bw_index = 9; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 5); - variable_item_set_current_value_text(alt_item, config_sf_names[5]); - model->config_sf_index = 5; - - break; - case 8: // SF9/500kHz - configSetSpreadingFactor(0x09); - configSetBandwidth(0x06); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 9); - variable_item_set_current_value_text(alt_item, config_bw_names[9]); - model->config_bw_index = 9; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 4); - variable_item_set_current_value_text(alt_item, config_sf_names[4]); - model->config_sf_index = 4; - - break; - case 9: // SF8/500kHz - configSetSpreadingFactor(0x08); - configSetBandwidth(0x06); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 9); - variable_item_set_current_value_text(alt_item, config_bw_names[9]); - model->config_bw_index = 9; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 3); - variable_item_set_current_value_text(alt_item, config_sf_names[3]); - model->config_sf_index = 3; - - break; - case 10: // SF7/500kHz - configSetSpreadingFactor(0x07); - configSetBandwidth(0x06); - - alt_item = variable_item_list_get(app->variable_item_list_config, 1); - variable_item_list_set_selected_item(app->variable_item_list_config, 1); - variable_item_set_current_value_index(alt_item, 9); - variable_item_set_current_value_text(alt_item, config_bw_names[9]); - model->config_bw_index = 9; - - alt_item = variable_item_list_get(app->variable_item_list_config, 2); - variable_item_list_set_selected_item(app->variable_item_list_config, 2); - variable_item_set_current_value_index(alt_item, 2); - variable_item_set_current_value_text(alt_item, config_sf_names[2]); - model->config_sf_index = 2; - - break; - } + VariableItem* alt_item; + LoRaApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, config_us_dr_names[index]); + + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + model->config_us_dr_index = index; + + switch(index) { + case 0: // SF10/125kHz + configSetSpreadingFactor(0x0A); + configSetBandwidth(0x04); + + alt_item = variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 7); + variable_item_set_current_value_text(alt_item, config_bw_names[7]); + model->config_bw_index = 7; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 5); + variable_item_set_current_value_text(alt_item, config_sf_names[5]); + model->config_sf_index = 5; + + break; + case 1: // SF9/125kHz + configSetSpreadingFactor(0x09); + configSetBandwidth(0x04); + + alt_item = variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 7); + variable_item_set_current_value_text(alt_item, config_bw_names[7]); + model->config_bw_index = 7; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 4); + variable_item_set_current_value_text(alt_item, config_sf_names[4]); + model->config_sf_index = 4; + + break; + case 2: // SF8/125kHz + configSetSpreadingFactor(0x08); + configSetBandwidth(0x04); + + alt_item = variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 7); + variable_item_set_current_value_text(alt_item, config_bw_names[7]); + model->config_bw_index = 7; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 3); + variable_item_set_current_value_text(alt_item, config_sf_names[3]); + model->config_sf_index = 3; + + break; + case 3: // SF7/125kHz + configSetSpreadingFactor(0x07); + configSetBandwidth(0x04); + + alt_item = variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 7); + variable_item_set_current_value_text(alt_item, config_bw_names[7]); + model->config_bw_index = 7; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 2); + variable_item_set_current_value_text(alt_item, config_sf_names[2]); + model->config_sf_index = 2; + + break; + case 4: // SF8/500kHz + configSetSpreadingFactor(0x08); + configSetBandwidth(0x06); + + alt_item = variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 9); + variable_item_set_current_value_text(alt_item, config_bw_names[9]); + model->config_bw_index = 9; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 3); + variable_item_set_current_value_text(alt_item, config_sf_names[3]); + model->config_sf_index = 3; + + break; + case 5: // SF12/500kHz + configSetSpreadingFactor(0x0C); + configSetBandwidth(0x06); + + alt_item = variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 9); + variable_item_set_current_value_text(alt_item, config_bw_names[9]); + model->config_bw_index = 9; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 7); + variable_item_set_current_value_text(alt_item, config_sf_names[7]); + model->config_sf_index = 7; + + break; + case 6: // SF11/500kHz + configSetSpreadingFactor(0x0B); + configSetBandwidth(0x06); + + alt_item = variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 9); + variable_item_set_current_value_text(alt_item, config_bw_names[9]); + model->config_bw_index = 9; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 6); + variable_item_set_current_value_text(alt_item, config_sf_names[6]); + model->config_sf_index = 6; + + break; + case 7: // SF10/500kHz + configSetSpreadingFactor(0x0A); + configSetBandwidth(0x06); + + alt_item = variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 9); + variable_item_set_current_value_text(alt_item, config_bw_names[9]); + model->config_bw_index = 9; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 5); + variable_item_set_current_value_text(alt_item, config_sf_names[5]); + model->config_sf_index = 5; + + break; + case 8: // SF9/500kHz + configSetSpreadingFactor(0x09); + configSetBandwidth(0x06); + + alt_item = variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 9); + variable_item_set_current_value_text(alt_item, config_bw_names[9]); + model->config_bw_index = 9; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 4); + variable_item_set_current_value_text(alt_item, config_sf_names[4]); + model->config_sf_index = 4; + + break; + case 9: // SF8/500kHz + configSetSpreadingFactor(0x08); + configSetBandwidth(0x06); + + alt_item = variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 9); + variable_item_set_current_value_text(alt_item, config_bw_names[9]); + model->config_bw_index = 9; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 3); + variable_item_set_current_value_text(alt_item, config_sf_names[3]); + model->config_sf_index = 3; + + break; + case 10: // SF7/500kHz + configSetSpreadingFactor(0x07); + configSetBandwidth(0x06); + + alt_item = variable_item_list_get(app->variable_item_list_config, 1); + variable_item_list_set_selected_item(app->variable_item_list_config, 1); + variable_item_set_current_value_index(alt_item, 9); + variable_item_set_current_value_text(alt_item, config_bw_names[9]); + model->config_bw_index = 9; + + alt_item = variable_item_list_get(app->variable_item_list_config, 2); + variable_item_list_set_selected_item(app->variable_item_list_config, 2); + variable_item_set_current_value_index(alt_item, 2); + variable_item_set_current_value_text(alt_item, config_sf_names[2]); + model->config_sf_index = 2; + + break; + } } static const char* config_us915_ul_channels_125k_label = "Uplink 125 kHz"; static void lora_config_us915_ul_channels_125k_change(VariableItem* item) { - LoRaApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - - char text_buf[11] = {0}; - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - config_us915_ul_channels_125k[index] / 1000000, - (config_us915_ul_channels_125k[index] % 1000000) / 100000); - variable_item_set_current_value_text(item, text_buf); + LoRaApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + char text_buf[11] = {0}; + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + config_us915_ul_channels_125k[index] / 1000000, + (config_us915_ul_channels_125k[index] % 1000000) / 100000); + variable_item_set_current_value_text(item, text_buf); - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - model->config_us915_ul_channels_125k_index = index; + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + model->config_us915_ul_channels_125k_index = index; - app->config_frequency = (int) config_us915_ul_channels_125k[index]; - // setting text for configure frequency - furi_string_set(model->config_freq_name, text_buf); - variable_item_set_current_value_text(app->config_freq_item, text_buf); + app->config_frequency = (int)config_us915_ul_channels_125k[index]; + // setting text for configure frequency + furi_string_set(model->config_freq_name, text_buf); + variable_item_set_current_value_text(app->config_freq_item, text_buf); - FURI_LOG_E(TAG, "Frequency = %lu", app->config_frequency); + FURI_LOG_E(TAG, "Frequency = %lu", app->config_frequency); - configSetFrequency(app->config_frequency); + configSetFrequency(app->config_frequency); } static const char* config_us915_ul_channels_500k_label = "Uplink 500 kHz"; static void lora_config_us915_ul_channels_500k_change(VariableItem* item) { - LoRaApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - - char text_buf[11] = {0}; - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - config_us915_ul_channels_500k[index] / 1000000, - (config_us915_ul_channels_500k[index] % 1000000) / 100000); - variable_item_set_current_value_text(item, text_buf); + LoRaApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + char text_buf[11] = {0}; + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + config_us915_ul_channels_500k[index] / 1000000, + (config_us915_ul_channels_500k[index] % 1000000) / 100000); + variable_item_set_current_value_text(item, text_buf); - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - model->config_us915_ul_channels_500k_index = index; + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + model->config_us915_ul_channels_500k_index = index; - app->config_frequency = (int) config_us915_ul_channels_500k[index]; - // setting text for configure frequency - furi_string_set(model->config_freq_name, text_buf); - variable_item_set_current_value_text(app->config_freq_item, text_buf); + app->config_frequency = (int)config_us915_ul_channels_500k[index]; + // setting text for configure frequency + furi_string_set(model->config_freq_name, text_buf); + variable_item_set_current_value_text(app->config_freq_item, text_buf); - FURI_LOG_E(TAG, "Frequency = %lu", app->config_frequency); + FURI_LOG_E(TAG, "Frequency = %lu", app->config_frequency); - configSetFrequency(app->config_frequency); + configSetFrequency(app->config_frequency); } static const char* config_us915_dl_channels_500k_label = "Downlink 500 kHz"; static void lora_config_us915_dl_channels_500k_change(VariableItem* item) { - LoRaApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - - char text_buf[11] = {0}; - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - config_us915_dl_channels_500k[index] / 1000000, - (config_us915_dl_channels_500k[index] % 1000000) / 100000); - variable_item_set_current_value_text(item, text_buf); + LoRaApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + char text_buf[11] = {0}; + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + config_us915_dl_channels_500k[index] / 1000000, + (config_us915_dl_channels_500k[index] % 1000000) / 100000); + variable_item_set_current_value_text(item, text_buf); - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - model->config_us915_dl_channels_500k_index = index; + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + model->config_us915_dl_channels_500k_index = index; - app->config_frequency = (int) config_us915_dl_channels_500k[index]; - // setting text for configure frequency - furi_string_set(model->config_freq_name, text_buf); - variable_item_set_current_value_text(app->config_freq_item, text_buf); + app->config_frequency = (int)config_us915_dl_channels_500k[index]; + // setting text for configure frequency + furi_string_set(model->config_freq_name, text_buf); + variable_item_set_current_value_text(app->config_freq_item, text_buf); - FURI_LOG_E(TAG, "Frequency = %lu", app->config_frequency); + FURI_LOG_E(TAG, "Frequency = %lu", app->config_frequency); - configSetFrequency(app->config_frequency); + configSetFrequency(app->config_frequency); } static const char* config_eu868_ul_channels_125k_label = "Uplink 125 kHz"; static void lora_config_eu868_ul_channels_125k_change(VariableItem* item) { - LoRaApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - - char text_buf[11] = {0}; - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - config_eu868_ul_channels_125k[index] / 1000000, - (config_eu868_ul_channels_125k[index] % 1000000) / 100000); - variable_item_set_current_value_text(item, text_buf); + LoRaApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + char text_buf[11] = {0}; + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + config_eu868_ul_channels_125k[index] / 1000000, + (config_eu868_ul_channels_125k[index] % 1000000) / 100000); + variable_item_set_current_value_text(item, text_buf); - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - model->config_eu868_ul_channels_125k_index = index; + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + model->config_eu868_ul_channels_125k_index = index; - app->config_frequency = (int) config_eu868_ul_channels_125k[index]; - // setting text for configure frequency - furi_string_set(model->config_freq_name, text_buf); - variable_item_set_current_value_text(app->config_freq_item, text_buf); + app->config_frequency = (int)config_eu868_ul_channels_125k[index]; + // setting text for configure frequency + furi_string_set(model->config_freq_name, text_buf); + variable_item_set_current_value_text(app->config_freq_item, text_buf); - FURI_LOG_E(TAG, "Frequency = %lu", app->config_frequency); + FURI_LOG_E(TAG, "Frequency = %lu", app->config_frequency); - configSetFrequency(app->config_frequency); + configSetFrequency(app->config_frequency); } static const char* config_eu868_ul_channels_250k_label = "Uplink 250 kHz"; static void lora_config_eu868_ul_channels_250k_change(VariableItem* item) { - LoRaApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - - char text_buf[11] = {0}; - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - config_eu868_ul_channels_250k[index] / 1000000, - (config_eu868_ul_channels_250k[index] % 1000000) / 100000); - variable_item_set_current_value_text(item, text_buf); - - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - model->config_eu868_ul_channels_250k_index = index; - - app->config_frequency = (int) config_eu868_ul_channels_250k[index]; - // setting text for configure frequency - furi_string_set(model->config_freq_name, text_buf); - variable_item_set_current_value_text(app->config_freq_item, text_buf); - - FURI_LOG_E(TAG, "Frequency = %lu", app->config_frequency); - - configSetFrequency(app->config_frequency); -} - -static const char* config_eu868_dl_channels_rx1_label = "Downlink RX1"; - -static void lora_config_eu868_dl_channels_rx1_change(VariableItem* item) { - LoRaApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - - char text_buf[11] = {0}; - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - config_eu868_dl_channels_rx1[index] / 1000000, - (config_eu868_dl_channels_rx1[index] % 1000000) / 100000); - variable_item_set_current_value_text(item, text_buf); - - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - model->config_eu868_dl_channels_rx1_index = index; - - app->config_frequency = (int) config_eu868_dl_channels_rx1[index]; - // setting text for configure frequency - furi_string_set(model->config_freq_name, text_buf); - variable_item_set_current_value_text(app->config_freq_item, text_buf); - - FURI_LOG_E(TAG, "Frequency = %lu", app->config_frequency); - - configSetFrequency(app->config_frequency); -} - -static const char* config_region_label = "Frequency Plan"; - -static void lora_config_region_change(VariableItem* item) { - LoRaApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, config_region_names[index]); - - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - model->config_region_index = index; - - variable_item_list_reset(app->variable_item_list_lorawan); + LoRaApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + char text_buf[11] = {0}; + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + config_eu868_ul_channels_250k[index] / 1000000, + (config_eu868_ul_channels_250k[index] % 1000000) / 100000); + variable_item_set_current_value_text(item, text_buf); - char text_buf[11] = {0}; + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + model->config_eu868_ul_channels_250k_index = index; - if (index == 0) { - app->config_frequency = 868100000; + app->config_frequency = (int)config_eu868_ul_channels_250k[index]; // setting text for configure frequency - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - app->config_frequency / 1000000, - (app->config_frequency % 1000000) / 100000); + furi_string_set(model->config_freq_name, text_buf); variable_item_set_current_value_text(app->config_freq_item, text_buf); FURI_LOG_E(TAG, "Frequency = %lu", app->config_frequency); configSetFrequency(app->config_frequency); +} - // Frequency Plan - item = variable_item_list_add( - app->variable_item_list_lorawan, config_region_label, - COUNT_OF(config_region_values), lora_config_region_change, app); - uint8_t config_region_index = 0; - variable_item_set_current_value_index(item, config_region_index); - variable_item_set_current_value_text( - item, config_region_names[config_region_index]); - - // EU868 Data Rate - item = variable_item_list_add( - app->variable_item_list_lorawan, config_eu_dr_label, - COUNT_OF(config_eu_dr_values), lora_config_eu_dr_change, app); - uint8_t config_eu_dr_index = 0; - variable_item_set_current_value_index(item, config_eu_dr_index); - variable_item_set_current_value_text( - item, config_us_dr_names[config_eu_dr_index]); - - // Uplink EU868 Channel 125K - item = variable_item_list_add( - app->variable_item_list_lorawan, config_eu868_ul_channels_125k_label, - COUNT_OF(config_eu868_ul_channels_125k), - lora_config_eu868_ul_channels_125k_change, app); - uint8_t config_eu868_ul_channels_125k_index = 0; - variable_item_set_current_value_index(item, - config_eu868_ul_channels_125k_index); - - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - config_eu868_ul_channels_125k[index] / 1000000, - (config_eu868_ul_channels_125k[index] % 1000000) / 100000); - variable_item_set_current_value_text(item, text_buf); +static const char* config_eu868_dl_channels_rx1_label = "Downlink RX1"; - // Uplink EU868 Channel 250K - item = variable_item_list_add( - app->variable_item_list_lorawan, config_eu868_ul_channels_250k_label, - COUNT_OF(config_eu868_ul_channels_250k), - lora_config_eu868_ul_channels_250k_change, app); - uint8_t config_eu868_ul_channels_250k_index = 0; - variable_item_set_current_value_index(item, - config_eu868_ul_channels_250k_index); - - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - config_eu868_ul_channels_250k[index] / 1000000, - (config_eu868_ul_channels_250k[index] % 1000000) / 100000); +static void lora_config_eu868_dl_channels_rx1_change(VariableItem* item) { + LoRaApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + char text_buf[11] = {0}; + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + config_eu868_dl_channels_rx1[index] / 1000000, + (config_eu868_dl_channels_rx1[index] % 1000000) / 100000); variable_item_set_current_value_text(item, text_buf); - // Downlink EU868 Channel RX1 - item = variable_item_list_add( - app->variable_item_list_lorawan, config_eu868_dl_channels_rx1_label, - COUNT_OF(config_eu868_dl_channels_rx1), - lora_config_eu868_dl_channels_rx1_change, app); - uint8_t config_eu868_dl_channels_rx1_index = 0; - variable_item_set_current_value_index(item, - config_eu868_dl_channels_rx1_index); - - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - config_eu868_dl_channels_rx1[index] / 1000000, - (config_eu868_dl_channels_rx1[index] % 1000000) / 100000); - variable_item_set_current_value_text(item, text_buf); + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + model->config_eu868_dl_channels_rx1_index = index; - } else if (index == 1) { - app->config_frequency = 902300000; // first channel + app->config_frequency = (int)config_eu868_dl_channels_rx1[index]; // setting text for configure frequency - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - app->config_frequency / 1000000, - (app->config_frequency % 1000000) / 100000); + furi_string_set(model->config_freq_name, text_buf); variable_item_set_current_value_text(app->config_freq_item, text_buf); FURI_LOG_E(TAG, "Frequency = %lu", app->config_frequency); configSetFrequency(app->config_frequency); +} - // Frequency Plan - item = variable_item_list_add( - app->variable_item_list_lorawan, config_region_label, - COUNT_OF(config_region_values), lora_config_region_change, app); - uint8_t config_region_index = 1; - variable_item_set_current_value_index(item, config_region_index); - variable_item_set_current_value_text( - item, config_region_names[config_region_index]); +static const char* config_region_label = "Frequency Plan"; - // US915 Data Rate - item = variable_item_list_add( - app->variable_item_list_lorawan, config_us_dr_label, - COUNT_OF(config_us_dr_values), lora_config_us_dr_change, app); - uint8_t config_us_dr_index = 0; - variable_item_set_current_value_index(item, config_us_dr_index); - variable_item_set_current_value_text( - item, config_us_dr_names[config_us_dr_index]); +static void lora_config_region_change(VariableItem* item) { + LoRaApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, config_region_names[index]); - // Uplink US915 Channel 125K - item = variable_item_list_add( - app->variable_item_list_lorawan, config_us915_ul_channels_125k_label, - COUNT_OF(config_us915_ul_channels_125k), - lora_config_us915_ul_channels_125k_change, app); - uint8_t config_us915_ul_channels_125k_index = 0; - variable_item_set_current_value_index(item, - config_us915_ul_channels_125k_index); + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + model->config_region_index = index; - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - config_us915_ul_channels_125k[index] / 1000000, - (config_us915_ul_channels_125k[index] % 1000000) / 100000); - variable_item_set_current_value_text(item, text_buf); + variable_item_list_reset(app->variable_item_list_lorawan); - // Uplink US915 Channel 500K - item = variable_item_list_add( - app->variable_item_list_lorawan, config_us915_ul_channels_500k_label, - COUNT_OF(config_us915_ul_channels_500k), - lora_config_us915_ul_channels_500k_change, app); - uint8_t config_us915_ul_channels_500k_index = 0; - variable_item_set_current_value_index(item, - config_us915_ul_channels_500k_index); + char text_buf[11] = {0}; - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - config_us915_ul_channels_500k[index] / 1000000, - (config_us915_ul_channels_500k[index] % 1000000) / 100000); - variable_item_set_current_value_text(item, text_buf); + if(index == 0) { + app->config_frequency = 868100000; + // setting text for configure frequency + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + app->config_frequency / 1000000, + (app->config_frequency % 1000000) / 100000); + variable_item_set_current_value_text(app->config_freq_item, text_buf); - // Downlink US915 Channel 500K - item = variable_item_list_add( - app->variable_item_list_lorawan, config_us915_dl_channels_500k_label, - COUNT_OF(config_us915_dl_channels_500k), - lora_config_us915_dl_channels_500k_change, app); - uint8_t config_us915_dl_channels_500k_index = 0; - variable_item_set_current_value_index(item, - config_us915_dl_channels_500k_index); + FURI_LOG_E(TAG, "Frequency = %lu", app->config_frequency); - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - config_us915_dl_channels_500k[index] / 1000000, - (config_us915_dl_channels_500k[index] % 1000000) / 100000); - variable_item_set_current_value_text(item, text_buf); - } + configSetFrequency(app->config_frequency); + + // Frequency Plan + item = variable_item_list_add( + app->variable_item_list_lorawan, + config_region_label, + COUNT_OF(config_region_values), + lora_config_region_change, + app); + uint8_t config_region_index = 0; + variable_item_set_current_value_index(item, config_region_index); + variable_item_set_current_value_text(item, config_region_names[config_region_index]); + + // EU868 Data Rate + item = variable_item_list_add( + app->variable_item_list_lorawan, + config_eu_dr_label, + COUNT_OF(config_eu_dr_values), + lora_config_eu_dr_change, + app); + uint8_t config_eu_dr_index = 0; + variable_item_set_current_value_index(item, config_eu_dr_index); + variable_item_set_current_value_text(item, config_us_dr_names[config_eu_dr_index]); + + // Uplink EU868 Channel 125K + item = variable_item_list_add( + app->variable_item_list_lorawan, + config_eu868_ul_channels_125k_label, + COUNT_OF(config_eu868_ul_channels_125k), + lora_config_eu868_ul_channels_125k_change, + app); + uint8_t config_eu868_ul_channels_125k_index = 0; + variable_item_set_current_value_index(item, config_eu868_ul_channels_125k_index); + + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + config_eu868_ul_channels_125k[index] / 1000000, + (config_eu868_ul_channels_125k[index] % 1000000) / 100000); + variable_item_set_current_value_text(item, text_buf); + + // Uplink EU868 Channel 250K + item = variable_item_list_add( + app->variable_item_list_lorawan, + config_eu868_ul_channels_250k_label, + COUNT_OF(config_eu868_ul_channels_250k), + lora_config_eu868_ul_channels_250k_change, + app); + uint8_t config_eu868_ul_channels_250k_index = 0; + variable_item_set_current_value_index(item, config_eu868_ul_channels_250k_index); + + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + config_eu868_ul_channels_250k[index] / 1000000, + (config_eu868_ul_channels_250k[index] % 1000000) / 100000); + variable_item_set_current_value_text(item, text_buf); + + // Downlink EU868 Channel RX1 + item = variable_item_list_add( + app->variable_item_list_lorawan, + config_eu868_dl_channels_rx1_label, + COUNT_OF(config_eu868_dl_channels_rx1), + lora_config_eu868_dl_channels_rx1_change, + app); + uint8_t config_eu868_dl_channels_rx1_index = 0; + variable_item_set_current_value_index(item, config_eu868_dl_channels_rx1_index); + + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + config_eu868_dl_channels_rx1[index] / 1000000, + (config_eu868_dl_channels_rx1[index] % 1000000) / 100000); + variable_item_set_current_value_text(item, text_buf); + + } else if(index == 1) { + app->config_frequency = 902300000; //first channel + // setting text for configure frequency + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + app->config_frequency / 1000000, + (app->config_frequency % 1000000) / 100000); + variable_item_set_current_value_text(app->config_freq_item, text_buf); + + FURI_LOG_E(TAG, "Frequency = %lu", app->config_frequency); + + configSetFrequency(app->config_frequency); + + // Frequency Plan + item = variable_item_list_add( + app->variable_item_list_lorawan, + config_region_label, + COUNT_OF(config_region_values), + lora_config_region_change, + app); + uint8_t config_region_index = 1; + variable_item_set_current_value_index(item, config_region_index); + variable_item_set_current_value_text(item, config_region_names[config_region_index]); + + // US915 Data Rate + item = variable_item_list_add( + app->variable_item_list_lorawan, + config_us_dr_label, + COUNT_OF(config_us_dr_values), + lora_config_us_dr_change, + app); + uint8_t config_us_dr_index = 0; + variable_item_set_current_value_index(item, config_us_dr_index); + variable_item_set_current_value_text(item, config_us_dr_names[config_us_dr_index]); + + // Uplink US915 Channel 125K + item = variable_item_list_add( + app->variable_item_list_lorawan, + config_us915_ul_channels_125k_label, + COUNT_OF(config_us915_ul_channels_125k), + lora_config_us915_ul_channels_125k_change, + app); + uint8_t config_us915_ul_channels_125k_index = 0; + variable_item_set_current_value_index(item, config_us915_ul_channels_125k_index); + + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + config_us915_ul_channels_125k[index] / 1000000, + (config_us915_ul_channels_125k[index] % 1000000) / 100000); + variable_item_set_current_value_text(item, text_buf); + + // Uplink US915 Channel 500K + item = variable_item_list_add( + app->variable_item_list_lorawan, + config_us915_ul_channels_500k_label, + COUNT_OF(config_us915_ul_channels_500k), + lora_config_us915_ul_channels_500k_change, + app); + uint8_t config_us915_ul_channels_500k_index = 0; + variable_item_set_current_value_index(item, config_us915_ul_channels_500k_index); + + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + config_us915_ul_channels_500k[index] / 1000000, + (config_us915_ul_channels_500k[index] % 1000000) / 100000); + variable_item_set_current_value_text(item, text_buf); + + // Downlink US915 Channel 500K + item = variable_item_list_add( + app->variable_item_list_lorawan, + config_us915_dl_channels_500k_label, + COUNT_OF(config_us915_dl_channels_500k), + lora_config_us915_dl_channels_500k_change, + app); + uint8_t config_us915_dl_channels_500k_index = 0; + variable_item_set_current_value_index(item, config_us915_dl_channels_500k_index); + + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + config_us915_dl_channels_500k[index] / 1000000, + (config_us915_dl_channels_500k[index] % 1000000) / 100000); + variable_item_set_current_value_text(item, text_buf); + } - // configSetSpreadingFactor(config_sf_values[index]); + //configSetSpreadingFactor(config_sf_values[index]); } /** - * When the user clicks OK on the configuration frequencysetting we use a text - * input screen to allow the user to enter a frequency. This function is called - * when the user clicks OK on the text input screen. - */ + * When the user clicks OK on the configuration frequencysetting we use a text input screen to allow + * the user to enter a frequency. This function is called when the user clicks OK on the text input screen. +*/ static const char* config_freq_config_label = "Frequency"; static const char* config_freq_entry_text = "Enter frequency (MHz)"; static const char* config_freq_default_value = "915.0"; static void lora_config_freq_text_updated(void* context) { - LoRaApp* app = (LoRaApp*) context; - bool redraw = true; - with_view_model( - app->view_sniffer, LoRaSnifferModel * model, - { - furi_string_set(model->config_freq_name, app->temp_buffer); - variable_item_set_current_value_text( - app->config_freq_item, - furi_string_get_cstr(model->config_freq_name)); - - const char* freq_str = furi_string_get_cstr(model->config_freq_name); - app->config_frequency = (int) (strtof(freq_str, NULL) * 1000000); - FURI_LOG_E(TAG, "Frequency = %lu", app->config_frequency); - }, - redraw); + LoRaApp* app = (LoRaApp*)context; + bool redraw = true; + with_view_model( + app->view_sniffer, + LoRaSnifferModel * model, + { + furi_string_set(model->config_freq_name, app->temp_buffer); + variable_item_set_current_value_text( + app->config_freq_item, furi_string_get_cstr(model->config_freq_name)); + + const char* freq_str = furi_string_get_cstr(model->config_freq_name); + app->config_frequency = (int)(strtof(freq_str, NULL) * 1000000); + FURI_LOG_E(TAG, "Frequency = %lu", app->config_frequency); + }, + redraw); - view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewConfigure); - configSetFrequency(app->config_frequency); + view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewConfigure); + configSetFrequency(app->config_frequency); } static void set_value(void* context) { - LoRaApp* app = (LoRaApp*) context; + LoRaApp* app = (LoRaApp*)context; - FURI_LOG_E(TAG, "Byte buffer: %s", (char*) app->byte_buffer); - view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewSubmenu); - transmit(app->byte_buffer, app->byte_buffer_size); + FURI_LOG_E(TAG, "Byte buffer: %s", (char*)app->byte_buffer); + view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewSubmenu); + transmit(app->byte_buffer, app->byte_buffer_size); } /** * @brief Callback when item in configuration screen is clicked. - * @details This function is called when user clicks OK on an item in the - * configuration screen. If the item clicked is our text field then we switch to - * the text input screen. + * @details This function is called when user clicks OK on an item in the configuration screen. + * If the item clicked is our text field then we switch to the text input screen. * @param context The context - LoRaApp object. * @param index - The index of the item that was clicked. - */ +*/ static void lora_setting_item_clicked(void* context, uint32_t index) { - LoRaApp* app = (LoRaApp*) context; - index++; // The index starts at zero, but we want to start at 1. + LoRaApp* app = (LoRaApp*)context; + index++; // The index starts at zero, but we want to start at 1. - // Our configuration UI has the 2nd item as a text field. - if (index == 1) { - // Header to display on the text input screen. - text_input_set_header_text(app->frequency_input, config_freq_entry_text); + // Our configuration UI has the 2nd item as a text field. + if(index == 1) { + // Header to display on the text input screen. + text_input_set_header_text(app->frequency_input, config_freq_entry_text); - // Copy the current name into the temporary buffer. - bool redraw = false; - with_view_model( - app->view_sniffer, LoRaSnifferModel * model, - { - strncpy(app->temp_buffer, - furi_string_get_cstr(model->config_freq_name), - app->temp_buffer_size); - }, - redraw); + // Copy the current name into the temporary buffer. + bool redraw = false; + with_view_model( + app->view_sniffer, + LoRaSnifferModel * model, + { + strncpy( + app->temp_buffer, + furi_string_get_cstr(model->config_freq_name), + app->temp_buffer_size); + }, + redraw); - // Configure the text input. When user enters text and clicks OK, - // lora_setting_text_updated be called. - bool clear_previous_text = false; - text_input_set_result_callback( - app->frequency_input, lora_config_freq_text_updated, app, - app->temp_buffer, app->temp_buffer_size, clear_previous_text); - - // Pressing the BACK button will reload the configure screen. - view_set_previous_callback(text_input_get_view(app->frequency_input), - lora_navigation_configure_callback); - - // Show text input dialog. - view_dispatcher_switch_to_view(app->view_dispatcher, - LoRaViewFrequencyInput); - } + // Configure the text input. When user enters text and clicks OK, lora_setting_text_updated be called. + bool clear_previous_text = false; + text_input_set_result_callback( + app->frequency_input, + lora_config_freq_text_updated, + app, + app->temp_buffer, + app->temp_buffer_size, + clear_previous_text); + + // Pressing the BACK button will reload the configure screen. + view_set_previous_callback( + text_input_get_view(app->frequency_input), lora_navigation_configure_callback); + + // Show text input dialog. + view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewFrequencyInput); + } } void bytesToAsciiHex(uint8_t* buffer, uint8_t length) { - uint8_t i; - for (i = 0; i < length; ++i) { - asciiBuff[i * 2] = "0123456789ABCDEF"[buffer[i] >> 4]; // High nibble - asciiBuff[i * 2 + 1] = "0123456789ABCDEF"[buffer[i] & 0x0F]; // Low nibble - } - asciiBuff[length * 2] = '\0'; // Null-terminate the string - FURI_LOG_E(TAG, "OUT bytesToAsciiHex "); + uint8_t i; + for(i = 0; i < length; ++i) { + asciiBuff[i * 2] = "0123456789ABCDEF"[buffer[i] >> 4]; // High nibble + asciiBuff[i * 2 + 1] = "0123456789ABCDEF"[buffer[i] & 0x0F]; // Low nibble + } + asciiBuff[length * 2] = '\0'; // Null-terminate the string + FURI_LOG_E(TAG, "OUT bytesToAsciiHex "); } void asciiHexToBytes(const char* hex, uint8_t* bytes, size_t length) { - for (size_t i = 0; i < length; i++) { - sscanf(hex + 2 * i, "%02hhx", &bytes[i]); - } + for(size_t i = 0; i < length; i++) { + sscanf(hex + 2 * i, "%02hhx", &bytes[i]); + } } /** * @brief Callback for drawing the sniffer screen. - * @details This function is called when the screen needs to be redrawn, like - * when the model gets updated. + * @details This function is called when the screen needs to be redrawn, like when the model gets updated. * @param canvas The canvas to draw on. * @param model The model - MyModel object. - */ +*/ static void lora_view_sniffer_draw_callback(Canvas* canvas, void* model) { - LoRaSnifferModel* my_model = (LoRaSnifferModel*) model; - - bool flag_file = my_model->flag_file; - - canvas_draw_icon(canvas, 0, 17, &I_flippers_cat); - - // Receive a packet over radio - int bytesRead = lora_receive_async(receiveBuff, sizeof(receiveBuff)); - - if (bytesRead > -1) { - FURI_LOG_E(TAG, "Packet received... "); - receiveBuff[bytesRead] = '\0'; - bytesToAsciiHex(receiveBuff, bytesRead); - - if (flag_file) { - FuriHalRtcDateTime curr_dt; - furi_hal_rtc_get_datetime(&curr_dt); - - char time_string[TIME_LEN]; - char date_string[DATE_LEN]; - - snprintf(time_string, TIME_LEN, CLOCK_TIME_FORMAT, curr_dt.hour, - curr_dt.minute, curr_dt.second); - snprintf(date_string, DATE_LEN, CLOCK_ISO_DATE_FORMAT, curr_dt.year, - curr_dt.month, curr_dt.day); - - char final_string[400]; - const char* freq_str = furi_string_get_cstr(my_model->config_freq_name); - - // JSON format - snprintf( - final_string, 666, - "{\"date\":\"%s\", \"time\":\"%s\", \"frequency\":\"%s\", " - "\"bw\":\"%s\", \"sf\":\"%s\", \"RSSI\":\"%d\", \"payload\":\"%s\"}", - date_string, time_string, freq_str, - config_bw_names[my_model->config_bw_index], - config_sf_names[my_model->config_sf_index], getRSSI(), - asciiBuff); // receiveBuff); - - FURI_LOG_E(TAG, "TS: %s", final_string); - FURI_LOG_E(TAG, "Length: %d", strlen(final_string) + 1); - - storage_file_write(my_model->file_rx, final_string, strlen(final_string)); - storage_file_write(my_model->file_rx, "\n", 1); + LoRaSnifferModel* my_model = (LoRaSnifferModel*)model; + + bool flag_file = my_model->flag_file; + + canvas_draw_icon(canvas, 0, 17, &I_flippers_cat); + + //Receive a packet over radio + int bytesRead = lora_receive_async(receiveBuff, sizeof(receiveBuff)); + + if(bytesRead > -1) { + FURI_LOG_E(TAG, "Packet received... "); + receiveBuff[bytesRead] = '\0'; + bytesToAsciiHex(receiveBuff, bytesRead); + + if(flag_file) { + DateTime curr_dt; + furi_hal_rtc_get_datetime(&curr_dt); + + char time_string[TIME_LEN]; + char date_string[DATE_LEN]; + + snprintf( + time_string, + TIME_LEN, + CLOCK_TIME_FORMAT, + curr_dt.hour, + curr_dt.minute, + curr_dt.second); + snprintf( + date_string, + DATE_LEN, + CLOCK_ISO_DATE_FORMAT, + curr_dt.year, + curr_dt.month, + curr_dt.day); + + char final_string[400]; + const char* freq_str = furi_string_get_cstr(my_model->config_freq_name); + + //JSON format + snprintf( + final_string, + 666, + "{\"date\":\"%s\", \"time\":\"%s\", \"frequency\":\"%s\", \"bw\":\"%s\", \"sf\":\"%s\", \"RSSI\":\"%d\", \"payload\":\"%s\"}", + date_string, + time_string, + freq_str, + config_bw_names[my_model->config_bw_index], + config_sf_names[my_model->config_sf_index], + getRSSI(), + asciiBuff); + + FURI_LOG_E(TAG, "TS: %s", final_string); + FURI_LOG_E(TAG, "Length: %d", strlen(final_string) + 1); + + storage_file_write(my_model->file_rx, final_string, strlen(final_string)); + storage_file_write(my_model->file_rx, "\n", 1); + } + FURI_LOG_E(TAG, "%s", receiveBuff); } - FURI_LOG_E(TAG, "%s", receiveBuff); - } - - FuriString* xstr = furi_string_alloc(); - if (flag_file) { - canvas_draw_icon(canvas, 110, 1, &I_write); - furi_string_printf(xstr, "Recording..."); - canvas_draw_str(canvas, 60, 20, furi_string_get_cstr(xstr)); - } else { - canvas_draw_icon(canvas, 110, 1, &I_no_write); - furi_string_printf(xstr, " "); - canvas_draw_str(canvas, 60, 20, furi_string_get_cstr(xstr)); - } + FuriString* xstr = furi_string_alloc(); - receiveBuff[17] = '.'; - receiveBuff[18] = '.'; - receiveBuff[19] = '.'; - receiveBuff[20] = '\0'; + if(flag_file) { + canvas_draw_icon(canvas, 110, 1, &I_write); + furi_string_printf(xstr, "Recording..."); + canvas_draw_str(canvas, 60, 20, furi_string_get_cstr(xstr)); + } else { + canvas_draw_icon(canvas, 110, 1, &I_no_write); + furi_string_printf(xstr, " "); + canvas_draw_str(canvas, 60, 20, furi_string_get_cstr(xstr)); + } - canvas_draw_str(canvas, 1, 10, (const char*) receiveBuff); + receiveBuff[17] = '.'; + receiveBuff[18] = '.'; + receiveBuff[19] = '.'; + receiveBuff[20] = '\0'; - furi_string_printf(xstr, "RSSI: %d ", getRSSI()); - canvas_draw_str(canvas, 1, 19, furi_string_get_cstr(xstr)); + canvas_draw_str(canvas, 1, 10, (const char*)receiveBuff); - // furi_string_printf(xstr, "x: %u OK=play tone", my_model->x); - // canvas_draw_str(canvas, 44, 24, furi_string_get_cstr(xstr)); + furi_string_printf(xstr, "RSSI: %d ", getRSSI()); + canvas_draw_str(canvas, 1, 19, furi_string_get_cstr(xstr)); - furi_string_printf(xstr, "BW:%s", config_bw_names[my_model->config_bw_index]); - canvas_draw_str(canvas, 1, 28, furi_string_get_cstr(xstr)); + furi_string_printf(xstr, "BW:%s", config_bw_names[my_model->config_bw_index]); + canvas_draw_str(canvas, 1, 28, furi_string_get_cstr(xstr)); - furi_string_printf(xstr, "FQ:%s MHz", - furi_string_get_cstr(my_model->config_freq_name)); - canvas_draw_str(canvas, 60, 28, furi_string_get_cstr(xstr)); + furi_string_printf(xstr, "FQ:%s MHz", furi_string_get_cstr(my_model->config_freq_name)); + canvas_draw_str(canvas, 60, 28, furi_string_get_cstr(xstr)); - furi_string_free(xstr); + furi_string_free(xstr); } /** * @brief Callback for drawing the transmitter screen. - * @details This function is called when the screen needs to be redrawn, like - * when the model gets updated. + * @details This function is called when the screen needs to be redrawn, like when the model gets updated. * @param canvas The canvas to draw on. * @param model The model - MyModel object. - */ +*/ static void lora_view_transmitter_draw_callback(Canvas* canvas, void* model) { - LoRaTransmitterModel* my_model = (LoRaTransmitterModel*) model; - - my_model->x = 0; + LoRaTransmitterModel* my_model = (LoRaTransmitterModel*)model; - canvas_draw_icon(canvas, 1, 3, &I_kitty_tx); + my_model->x = 0; - canvas_draw_str(canvas, 1, 10, "Press central"); - canvas_draw_str(canvas, 1, 20, "button to"); - canvas_draw_str(canvas, 1, 30, "browser"); + canvas_draw_icon(canvas, 1, 3, &I_kitty_tx); - FuriString* xstr = furi_string_alloc(); + canvas_draw_str(canvas, 1, 10, "Press central"); + canvas_draw_str(canvas, 1, 20, "button to"); + canvas_draw_str(canvas, 1, 30, "browser"); - // furi_string_printf(xstr, "TX: %u", (uint8_t)(furi_hal_random_get() % 256)); - canvas_draw_str(canvas, 1, 50, furi_string_get_cstr(xstr)); - - furi_string_free(xstr); - // furi_delay_ms(500); + FuriString* xstr = furi_string_alloc(); + canvas_draw_str(canvas, 1, 50, furi_string_get_cstr(xstr)); + furi_string_free(xstr); } /** * @brief Callback for timer elapsed. - * @details This function is called when the timer is elapsed. We use this - * to queue a redraw event. + * @details This function is called when the timer is elapsed. We use this to queue a redraw event. * @param context The context - LoRaApp object. - */ +*/ static void lora_view_sniffer_timer_callback(void* context) { - LoRaApp* app = (LoRaApp*) context; - view_dispatcher_send_custom_event(app->view_dispatcher, - LoRaEventIdRedrawScreen); + LoRaApp* app = (LoRaApp*)context; + view_dispatcher_send_custom_event(app->view_dispatcher, LoRaEventIdRedrawScreen); } /** * @brief Callback for timer elapsed. - * @details This function is called when the timer is elapsed. We use this - * to queue a redraw event. + * @details This function is called when the timer is elapsed. We use this to queue a redraw event. * @param context The context - LoRaApp object. - */ +*/ static void lora_view_transmitter_timer_callback(void* context) { - LoRaApp* app = (LoRaApp*) context; - view_dispatcher_send_custom_event(app->view_dispatcher, - LoRaEventIdRedrawScreen); - // HERE!!! + LoRaApp* app = (LoRaApp*)context; + view_dispatcher_send_custom_event(app->view_dispatcher, LoRaEventIdRedrawScreen); + // HERE!!! } /** * @brief Callback when the user starts the sniffer screen. - * @details This function is called when the user enters the sniffer screen. - * We start a timer to redraw the screen periodically (so the random number is - * refreshed). + * @details This function is called when the user enters the sniffer screen. We start a timer to + * redraw the screen periodically (so the random number is refreshed). * @param context The context - LoRaApp object. - */ +*/ static void lora_view_sniffer_enter_callback(void* context) { - uint32_t period = furi_ms_to_ticks(1000); - LoRaApp* app = (LoRaApp*) context; - furi_assert(app->timer_rx == NULL); - app->timer_rx = furi_timer_alloc(lora_view_sniffer_timer_callback, - FuriTimerTypePeriodic, context); - furi_timer_start(app->timer_rx, period); + uint32_t period = furi_ms_to_ticks(1000); + LoRaApp* app = (LoRaApp*)context; + furi_assert(app->timer_rx == NULL); + app->timer_rx = + furi_timer_alloc(lora_view_sniffer_timer_callback, FuriTimerTypePeriodic, context); + furi_timer_start(app->timer_rx, period); } /** * @brief Callback when the user starts the transmitter screen. - * @details This function is called when the user enters the transmitter - * screen. We start a timer to redraw the screen periodically (so the random - * number is refreshed). + * @details This function is called when the user enters the transmitter screen. We start a timer to + * redraw the screen periodically (so the random number is refreshed). * @param context The context - LoRaApp object. - */ +*/ static void lora_view_transmitter_enter_callback(void* context) { - uint32_t period = furi_ms_to_ticks(1000); - LoRaApp* app = (LoRaApp*) context; - furi_assert(app->timer_tx == NULL); - app->timer_tx = furi_timer_alloc(lora_view_transmitter_timer_callback, - FuriTimerTypePeriodic, context); - furi_timer_start(app->timer_tx, period); + uint32_t period = furi_ms_to_ticks(1000); + LoRaApp* app = (LoRaApp*)context; + furi_assert(app->timer_tx == NULL); + app->timer_tx = + furi_timer_alloc(lora_view_transmitter_timer_callback, FuriTimerTypePeriodic, context); + furi_timer_start(app->timer_tx, period); } /** * @brief Callback when the user exits the sniffer screen. - * @details This function is called when the user exits the sniffer screen. - * We stop the timer. + * @details This function is called when the user exits the sniffer screen. We stop the timer. * @param context The context - LoRaApp object. - */ +*/ static void lora_view_sniffer_exit_callback(void* context) { - LoRaApp* app = (LoRaApp*) context; - furi_timer_stop(app->timer_rx); - furi_timer_free(app->timer_rx); - app->timer_rx = NULL; - FURI_LOG_E(TAG, "Stop timer rx"); + LoRaApp* app = (LoRaApp*)context; + furi_timer_stop(app->timer_rx); + furi_timer_free(app->timer_rx); + app->timer_rx = NULL; + FURI_LOG_E(TAG, "Stop timer rx"); } /** * @brief Callback when the user exits the transmitter screen. - * @details This function is called when the user exits the transmitter - * screen. We stop the timer. + * @details This function is called when the user exits the transmitter screen. We stop the timer. * @param context The context - LoRaApp object. - */ +*/ static void lora_view_transmitter_exit_callback(void* context) { - LoRaApp* app = (LoRaApp*) context; - furi_timer_stop(app->timer_tx); - furi_timer_free(app->timer_tx); - app->timer_tx = NULL; - FURI_LOG_E(TAG, "Stop timer tx"); + LoRaApp* app = (LoRaApp*)context; + furi_timer_stop(app->timer_tx); + furi_timer_free(app->timer_tx); + app->timer_tx = NULL; + FURI_LOG_E(TAG, "Stop timer tx"); } /** * @brief Callback for custom events. - * @details This function is called when a custom event is sent to the view - * dispatcher. + * @details This function is called when a custom event is sent to the view dispatcher. * @param event The event id - LoRaEventId value. * @param context The context - LoRaApp object. - */ -static bool lora_view_sniffer_custom_event_callback(uint32_t event, - void* context) { - LoRaApp* app = (LoRaApp*) context; - switch (event) { +*/ +static bool lora_view_sniffer_custom_event_callback(uint32_t event, void* context) { + LoRaApp* app = (LoRaApp*)context; + switch(event) { case LoRaEventIdRedrawScreen: - // Redraw screen by passing true to last parameter of with_view_model. - { - bool redraw = true; - with_view_model( - app->view_sniffer, LoRaSnifferModel * _model, { UNUSED(_model); }, - redraw); - return true; - } + // Redraw screen by passing true to last parameter of with_view_model. + { + bool redraw = true; + with_view_model( + app->view_sniffer, LoRaSnifferModel * _model, { UNUSED(_model); }, redraw); + return true; + } case LoRaEventIdOkPressed: - // Process the OK button. We play a tone based on the x coordinate. - if (furi_hal_speaker_acquire(500)) { - float frequency; - bool redraw = false; - with_view_model( - app->view_sniffer, LoRaSnifferModel * model, - { frequency = model->x * 100 + 100; }, redraw); - furi_hal_speaker_start(frequency, 1.0); - furi_delay_ms(100); - furi_hal_speaker_stop(); - furi_hal_speaker_release(); - } - return true; + // Process the OK button. We play a tone based on the x coordinate. + if(furi_hal_speaker_acquire(500)) { + float frequency; + bool redraw = false; + with_view_model( + app->view_sniffer, + LoRaSnifferModel * model, + { frequency = model->x * 100 + 100; }, + redraw); + furi_hal_speaker_start(frequency, 1.0); + furi_delay_ms(100); + furi_hal_speaker_stop(); + furi_hal_speaker_release(); + } + return true; default: - return false; - } + return false; + } } /** * @brief Callback for custom events. - * @details This function is called when a custom event is sent to the view - * dispatcher. + * @details This function is called when a custom event is sent to the view dispatcher. * @param event The event id - LoRaEventId value. * @param context The context - LoRaApp object. - */ -static bool lora_view_transmitter_custom_event_callback(uint32_t event, - void* context) { - LoRaApp* app = (LoRaApp*) context; - switch (event) { +*/ +static bool lora_view_transmitter_custom_event_callback(uint32_t event, void* context) { + LoRaApp* app = (LoRaApp*)context; + switch(event) { case LoRaEventIdRedrawScreen: - // Redraw screen by passing true to last parameter of with_view_model. - { - bool redraw = true; - with_view_model( - app->view_transmitter, LoRaTransmitterModel * _model, - { UNUSED(_model); }, redraw); - return true; - } + // Redraw screen by passing true to last parameter of with_view_model. + { + bool redraw = true; + with_view_model( + app->view_transmitter, LoRaTransmitterModel * _model, { UNUSED(_model); }, redraw); + return true; + } case LoRaEventIdOkPressed: - // Process the OK button. We play a tone based on the x coordinate. - if (furi_hal_speaker_acquire(500)) { - float frequency; - bool redraw = false; - with_view_model( - app->view_transmitter, LoRaTransmitterModel * model, - { frequency = model->x * 100 + 100; }, redraw); - furi_hal_speaker_start(frequency, 1.0); - furi_delay_ms(100); - furi_hal_speaker_stop(); - furi_hal_speaker_release(); - } - return true; + // Process the OK button. We play a tone based on the x coordinate. + if(furi_hal_speaker_acquire(500)) { + float frequency; + bool redraw = false; + with_view_model( + app->view_transmitter, + LoRaTransmitterModel * model, + { frequency = model->x * 100 + 100; }, + redraw); + furi_hal_speaker_start(frequency, 1.0); + furi_delay_ms(100); + furi_hal_speaker_stop(); + furi_hal_speaker_release(); + } + return true; default: - return false; - } + return false; + } } /** * @brief Callback for sniffer screen input. - * @details This function is called when the user presses a button while on - * the sniffer screen. + * @details This function is called when the user presses a button while on the sniffer screen. * @param event The event - InputEvent object. * @param context The context - LoRaApp object. * @return true if the event was handled, false otherwise. - */ +*/ static bool lora_view_sniffer_input_callback(InputEvent* event, void* context) { - LoRaApp* app = (LoRaApp*) context; - if (event->type == InputTypeShort) { - if (event->key == InputKeyLeft) { - // Left button clicked, reduce x coordinate. - bool redraw = true; - with_view_model( - app->view_sniffer, LoRaSnifferModel * model, - { - if (model->x > 0) { - model->x--; - } - }, - redraw); - } else if (event->key == InputKeyRight) { - // Right button clicked, increase x coordinate. - bool redraw = true; - with_view_model( - app->view_sniffer, LoRaSnifferModel * model, - { - // Should we have some maximum value? - model->x++; - }, - redraw); + LoRaApp* app = (LoRaApp*)context; + if(event->type == InputTypeShort) { + if(event->key == InputKeyLeft) { + // Left button clicked, reduce x coordinate. + bool redraw = true; + with_view_model( + app->view_sniffer, + LoRaSnifferModel * model, + { + if(model->x > 0) { + model->x--; + } + }, + redraw); + } else if(event->key == InputKeyRight) { + // Right button clicked, increase x coordinate. + bool redraw = true; + with_view_model( + app->view_sniffer, + LoRaSnifferModel * model, + { + // Should we have some maximum value? + model->x++; + }, + redraw); + } + } else if(event->type == InputTypePress) { + if(event->key == InputKeyOk) { + // We choose to send a custom event when user presses OK button. lora_custom_event_callback will + // handle our LoRaEventIdOkPressed event. We could have just put the code from + // lora_custom_event_callback here, it's a matter of preference. + + bool redraw = true; + with_view_model( + app->view_sniffer, + LoRaSnifferModel * model, + { + // Start/Stop recording + model->flag_file = !model->flag_file; + + if(model->flag_file) { + // if(!storage_simply_mkdir(model->storage_rx, PATHAPPEXT)) { + // FURI_LOG_E(TAG, "Failed to create directory %s", PATHAPPEXT); + // return; + // } + + char filename[256]; + int file_index = 0; + + do { + snprintf(filename, sizeof(filename), PATHLORA, file_index); + file_index++; + } while(storage_file_exists(model->storage_rx, filename)); + + if(!storage_file_open( + model->file_rx, filename, FSAM_WRITE, FSOM_CREATE_ALWAYS)) { + FURI_LOG_E(TAG, "Failed to open file %s", filename); + return 0; + } + FURI_LOG_E(TAG, "OPEN FILE "); + + } else { + storage_file_close(model->file_rx); + FURI_LOG_E(TAG, "CLOSE FILE "); + } + }, + redraw); + + view_dispatcher_send_custom_event(app->view_dispatcher, LoRaEventIdOkPressed); + return true; + } } - } else if (event->type == InputTypePress) { - if (event->key == InputKeyOk) { - // We choose to send a custom event when user presses OK button. - // lora_custom_event_callback will handle our LoRaEventIdOkPressed event. - // We could have just put the code from lora_custom_event_callback here, - // it's a matter of preference. - - bool redraw = true; - with_view_model( - app->view_sniffer, LoRaSnifferModel * model, - { - // Start/Stop recording - model->flag_file = !model->flag_file; - - if (model->flag_file) { - char filename[256]; - int file_index = 0; - - do { - snprintf(filename, sizeof(filename), PATHLORA, file_index); - file_index++; - } while (storage_file_exists(model->storage_rx, filename)); - - if (!storage_file_open(model->file_rx, filename, FSAM_WRITE, - FSOM_CREATE_ALWAYS)) { - FURI_LOG_E(TAG, "Failed to open file %s", filename); - return 0; - } - FURI_LOG_E(TAG, "OPEN FILE "); - } else { - storage_file_close(model->file_rx); - FURI_LOG_E(TAG, "CLOSE FILE "); - } - }, - redraw); - - view_dispatcher_send_custom_event(app->view_dispatcher, - LoRaEventIdOkPressed); - return true; - } - } - - return false; + return false; } void tx_payload(const char* line) { - const char* key = "\"payload\":\""; - char* start = strstr(line, key); - if (start) { - start += strlen(key); // Advance the pointer to the end of “payload”: - char* end = strchr(start, '"'); // find next " - if (end) { - // Calculates the length of the substring - size_t length = end - start; - char payload[length + 1]; // +1 to end in NULL - strncpy(payload, start, length); - payload[length] = '\0'; // adds the NULL - - FURI_LOG_E(TAG, "%s\n", payload); - - size_t byte_length = length / 2; - uint8_t bytes[byte_length]; - - // Convert hex string to bytes - asciiHexToBytes(payload, bytes, byte_length); - - FURI_LOG_E(TAG, "%s\n", payload); - transmit(bytes, byte_length); - furi_delay_ms(10); + const char* key = "\"payload\":\""; + char* start = strstr(line, key); + if(start) { + start += strlen(key); // Advance the pointer to the end of “payload”: + char* end = strchr(start, '"'); // find next " + if(end) { + // Calculates the length of the substring + size_t length = end - start; + char payload[length + 1]; // +1 to end in NULL + strncpy(payload, start, length); + payload[length] = '\0'; // adds the NULL + + FURI_LOG_E(TAG, "%s\n", payload); + + size_t byte_length = length / 2; + uint8_t bytes[byte_length]; + + // Convert hex string to bytes + asciiHexToBytes(payload, bytes, byte_length); + + FURI_LOG_E(TAG, "%s\n", payload); + transmit(bytes, byte_length); + furi_delay_ms(10); + } } - } } void send_data(void* context) { - LoRaApp* app = (LoRaApp*) context; - LoRaTransmitterModel* model = view_get_model(app->view_transmitter); - - // uint8_t transmitBuff[64]; - FuriString* predefined_filepath = furi_string_alloc_set_str(PATHAPP); - FuriString* selected_filepath = furi_string_alloc(); - DialogsFileBrowserOptions browser_options; - dialog_file_browser_set_basic_options(&browser_options, - LORA_LOG_FILE_EXTENSION, NULL); - browser_options.base_path = PATHAPP; - - dialog_file_browser_show(model->dialogs_tx, selected_filepath, - predefined_filepath, &browser_options); - - if (storage_file_open(model->file_tx, furi_string_get_cstr(selected_filepath), - FSAM_READ, FSOM_OPEN_EXISTING)) { - model->flag_tx_file = true; - model->test = 1; - - char buffer[256]; - size_t buffer_index = 0; - size_t bytes_read; - char c; - - while ((bytes_read = storage_file_read(model->file_tx, &c, 1)) > 0 && - model->flag_signal) { - if (c == '\n' || buffer_index >= 256 - 1) { - buffer[buffer_index] = '\0'; - - FURI_LOG_E(TAG, "%s\n", buffer); - - tx_payload(buffer); - buffer_index = 0; - } else { - buffer[buffer_index++] = c; - } - } + LoRaApp* app = (LoRaApp*)context; + LoRaTransmitterModel* model = view_get_model(app->view_transmitter); + + //uint8_t transmitBuff[64]; + FuriString* predefined_filepath = furi_string_alloc_set_str(PATHAPP); + FuriString* selected_filepath = furi_string_alloc(); + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options(&browser_options, LORA_LOG_FILE_EXTENSION, NULL); + browser_options.base_path = PATHAPP; + + dialog_file_browser_show( + model->dialogs_tx, selected_filepath, predefined_filepath, &browser_options); + + if(storage_file_open( + model->file_tx, + furi_string_get_cstr(selected_filepath), + FSAM_READ, + FSOM_OPEN_EXISTING)) { + model->flag_tx_file = true; + model->test = 1; + + char buffer[256]; + size_t buffer_index = 0; + size_t bytes_read; + char c; + + while((bytes_read = storage_file_read(model->file_tx, &c, 1)) > 0 && model->flag_signal) { + if(c == '\n' || buffer_index >= 256 - 1) { + buffer[buffer_index] = '\0'; + + FURI_LOG_E(TAG, "%s\n", buffer); + + tx_payload(buffer); + buffer_index = 0; + } else { + buffer[buffer_index++] = c; + } + } - } else { - dialog_message_show_storage_error(model->dialogs_tx, "Cannot open File"); - } - storage_file_close(model->file_tx); - model->test = 0; - furi_string_free(selected_filepath); - furi_string_free(predefined_filepath); + } else { + dialog_message_show_storage_error(model->dialogs_tx, "Cannot open File"); + } + storage_file_close(model->file_tx); + model->test = 0; + furi_string_free(selected_filepath); + furi_string_free(predefined_filepath); - furi_hal_gpio_write(pin_led, true); - furi_delay_ms(50); - furi_hal_gpio_write(pin_led, false); + furi_hal_gpio_write(pin_led, true); + furi_delay_ms(50); + furi_hal_gpio_write(pin_led, false); - model->flag_tx_file = false; + model->flag_tx_file = false; } /** * @brief Callback for sniffer screen input. - * @details This function is called when the user presses a button while on - * the transmitter screen. + * @details This function is called when the user presses a button while on the transmitter screen. * @param event The event - InputEvent object. * @param context The context - LoRaApp object. * @return true if the event was handled, false otherwise. - */ -static bool lora_view_transmitter_input_callback(InputEvent* event, - void* context) { - LoRaApp* app = (LoRaApp*) context; +*/ +static bool lora_view_transmitter_input_callback(InputEvent* event, void* context) { + LoRaApp* app = (LoRaApp*)context; - bool consumed = false; - if (event->type == InputTypeShort || event->type == InputTypeRepeat) { - with_view_model( - app->view_transmitter, LoRaTransmitterModel * model, - { - if (event->key == InputKeyLeft && model->test > 0) { - // model->test--; - consumed = true; - } else if (event->key == InputKeyRight) { //&& - // model->test < (COUNT_OF(view_lora_tx_tests) - 1)) { - // model->test++; - consumed = true; - } else if (event->key == InputKeyDown) { //&& model->size > 0) { - // model->size--; - consumed = true; - } else if (event->key == InputKeyUp) { //&& model->size < 24) { - // model->size++; - consumed = true; - } else if (event->key == InputKeyOk) { - uint32_t period = furi_ms_to_ticks(1000); - furi_timer_stop(app->timer_tx); - model->flag_signal = 1; - send_data(app); - furi_timer_start(app->timer_tx, period); - consumed = true; - } else if (event->key == InputKeyBack) { - // FLAG TO STOP TRANSMISSION - model->flag_signal = 0; - view_dispatcher_switch_to_view(app->view_dispatcher, - LoRaViewSubmenu); - consumed = true; - } - }, - consumed); - } + bool consumed = false; + if(event->type == InputTypeShort || event->type == InputTypeRepeat) { + with_view_model( + app->view_transmitter, + LoRaTransmitterModel * model, + { + if(event->key == InputKeyLeft && model->test > 0) { + //model->test--; + consumed = true; + } else if(event->key == InputKeyRight) { //&& + //model->test < (COUNT_OF(view_lora_tx_tests) - 1)) { + //model->test++; + consumed = true; + } else if(event->key == InputKeyDown) { //&& model->size > 0) { + //model->size--; + consumed = true; + } else if(event->key == InputKeyUp) { //&& model->size < 24) { + //model->size++; + consumed = true; + } else if(event->key == InputKeyOk) { + uint32_t period = furi_ms_to_ticks(1000); + furi_timer_stop(app->timer_tx); + model->flag_signal = 1; + send_data(app); + furi_timer_start(app->timer_tx, period); + consumed = true; + } else if(event->key == InputKeyBack) { + // FLAG TO STOP TRANSMISSION + model->flag_signal = 0; + view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewSubmenu); + consumed = true; + } + }, + consumed); + } - return consumed; + return consumed; } static void lora_app_config_set_payload_length(VariableItem* item) { - LoRaApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - FuriString* temp; - temp = furi_string_alloc(); - furi_string_cat_printf(temp, "%d", index); - variable_item_set_current_value_text(item, furi_string_get_cstr(temp)); - furi_string_free(temp); - app->packetPayloadLength = index; - - app->byte_buffer_size = index; - free(app->byte_buffer); - app->byte_buffer = (uint8_t*) malloc(app->byte_buffer_size); - - byte_input_set_result_callback(app->byte_input, set_value, NULL, app, - app->byte_buffer, app->byte_buffer_size); - - // Order is preamble, header type, packet length, CRC, IQ - setPacketParams(app->packetPreamble, app->packetHeaderType, - app->packetPayloadLength, app->packetCRC, - app->packetInvertIQ); + LoRaApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + FuriString* temp; + temp = furi_string_alloc(); + furi_string_cat_printf(temp, "%d", index); + variable_item_set_current_value_text(item, furi_string_get_cstr(temp)); + furi_string_free(temp); + app->packetPayloadLength = index; + + app->byte_buffer_size = index; + free(app->byte_buffer); + app->byte_buffer = (uint8_t*)malloc(app->byte_buffer_size); + + byte_input_set_result_callback( + app->byte_input, set_value, NULL, app, app->byte_buffer, app->byte_buffer_size); + + // Order is preamble, header type, packet length, CRC, IQ + setPacketParams( + app->packetPreamble, + app->packetHeaderType, + app->packetPayloadLength, + app->packetCRC, + app->packetInvertIQ); } /** * @brief Allocate the LoRa application. * @details This function allocates the LoRa application resources. * @return LoRaApp object. - */ +*/ static LoRaApp* lora_app_alloc() { - UNUSED(lora_config_eu_dr_change); - UNUSED(config_eu_dr_label); - - LoRaApp* app = (LoRaApp*) malloc(sizeof(LoRaApp)); - VariableItem* item; - Gui* gui = furi_record_open(RECORD_GUI); - - app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); - view_dispatcher_attach_to_gui(app->view_dispatcher, gui, - ViewDispatcherTypeFullscreen); - view_dispatcher_set_event_callback_context(app->view_dispatcher, app); - - app->submenu = submenu_alloc(); - submenu_add_item(app->submenu, "Config", LoRaSubmenuIndexConfigure, - lora_submenu_callback, app); - submenu_add_item(app->submenu, "LoRaWAN", LoRaSubmenuIndexLoRaWAN, - lora_submenu_callback, app); - submenu_add_item(app->submenu, "Sniffer", LoRaSubmenuIndexSniffer, - lora_submenu_callback, app); - submenu_add_item(app->submenu, "Transmitter", LoRaSubmenuIndexTransmitter, - lora_submenu_callback, app); - submenu_add_item(app->submenu, "Send LoRa byte", LoRaSubmenuIndexManualTX, - lora_submenu_callback, app); - submenu_add_item(app->submenu, "About", LoRaSubmenuIndexAbout, - lora_submenu_callback, app); - view_set_previous_callback(submenu_get_view(app->submenu), - lora_navigation_exit_callback); - view_dispatcher_add_view(app->view_dispatcher, LoRaViewSubmenu, - submenu_get_view(app->submenu)); - view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewSubmenu); - - app->frequency_input = text_input_alloc(); - view_dispatcher_add_view(app->view_dispatcher, LoRaViewFrequencyInput, - text_input_get_view(app->frequency_input)); - app->temp_buffer_size = 32; - app->temp_buffer = (char*) malloc(app->temp_buffer_size); - - app->byte_buffer_size = 16; - app->byte_buffer = (uint8_t*) malloc(app->byte_buffer_size); - - app->byte_input = byte_input_alloc(); - - view_dispatcher_add_view(app->view_dispatcher, LoRaViewByteInput, - byte_input_get_view(app->byte_input)); - - byte_input_set_header_text(app->byte_input, "Set byte to LoRa TX"); - byte_input_set_result_callback(app->byte_input, set_value, NULL, app, - app->byte_buffer, app->byte_buffer_size); - - view_set_previous_callback(byte_input_get_view(app->byte_input), - lora_navigation_submenu_callback); - - app->packetPayloadLength = 16; - - app->variable_item_list_config = variable_item_list_alloc(); - variable_item_list_reset(app->variable_item_list_config); - - app->variable_item_list_lorawan = variable_item_list_alloc(); - variable_item_list_reset(app->variable_item_list_lorawan); - - // frequency - FuriString* config_freq_name = furi_string_alloc(); - furi_string_set_str(config_freq_name, config_freq_default_value); - app->config_freq_item = variable_item_list_add( - app->variable_item_list_config, config_freq_config_label, 1, NULL, NULL); - variable_item_set_current_value_text(app->config_freq_item, - furi_string_get_cstr(config_freq_name)); - - // bw - item = variable_item_list_add(app->variable_item_list_config, config_bw_label, - COUNT_OF(config_bw_values), - lora_config_bw_change, app); - uint8_t config_bw_index = 7; - variable_item_set_current_value_index(item, config_bw_index); - variable_item_set_current_value_text(item, config_bw_names[config_bw_index]); - - // sf - item = variable_item_list_add(app->variable_item_list_config, config_sf_label, - COUNT_OF(config_sf_values), - lora_config_sf_change, app); - uint8_t config_sf_index = 3; - variable_item_set_current_value_index(item, config_sf_index); - variable_item_set_current_value_text(item, config_sf_names[config_sf_index]); - - // cr - item = variable_item_list_add(app->variable_item_list_config, config_cr_label, - COUNT_OF(config_cr_values), - lora_config_cr_change, app); - uint8_t config_cr_index = 0; - variable_item_set_current_value_index(item, config_cr_index); - variable_item_set_current_value_text(item, config_cr_names[config_cr_index]); - - // Payload length - item = - variable_item_list_add(app->variable_item_list_config, "Payload length", - 64, lora_app_config_set_payload_length, app); - variable_item_set_current_value_index(item, 16); - variable_item_set_current_value_text(item, "16"); - - // Header Type - item = variable_item_list_add( - app->variable_item_list_config, config_header_type_label, - COUNT_OF(config_header_type_values), lora_config_header_type_change, app); - uint8_t config_header_type_index = 0; - variable_item_set_current_value_index(item, config_header_type_index); - variable_item_set_current_value_text( - item, config_header_type_names[config_header_type_index]); - - // CRC - item = variable_item_list_add(app->variable_item_list_config, - config_crc_label, COUNT_OF(config_crc_values), - lora_config_crc_change, app); - uint8_t config_crc_index = 0; - variable_item_set_current_value_index(item, config_crc_index); - variable_item_set_current_value_text(item, - config_crc_names[config_crc_index]); - - // Inverted IQ - item = variable_item_list_add(app->variable_item_list_config, config_iq_label, - COUNT_OF(config_iq_values), - lora_config_iq_change, app); - uint8_t config_iq_index = 0; - variable_item_set_current_value_index(item, config_iq_index); - variable_item_set_current_value_text(item, config_iq_names[config_iq_index]); - - // Frequency Plan - item = variable_item_list_add( - app->variable_item_list_lorawan, config_region_label, - COUNT_OF(config_region_values), lora_config_region_change, app); - uint8_t config_region_index = 1; - variable_item_set_current_value_index(item, config_region_index); - variable_item_set_current_value_text( - item, config_region_names[config_region_index]); - - // Data Rate - item = variable_item_list_add( - app->variable_item_list_lorawan, config_us_dr_label, - COUNT_OF(config_us_dr_values), lora_config_us_dr_change, app); - uint8_t config_us_dr_index = 0; - variable_item_set_current_value_index(item, config_us_dr_index); - variable_item_set_current_value_text(item, - config_us_dr_names[config_us_dr_index]); - - char text_buf[11] = {0}; - - // Uplink Channel 125K - item = variable_item_list_add(app->variable_item_list_lorawan, - config_us915_ul_channels_125k_label, - COUNT_OF(config_us915_ul_channels_125k), - lora_config_us915_ul_channels_125k_change, app); - uint8_t config_us915_ul_channels_125k_index = 0; - variable_item_set_current_value_index(item, - config_us915_ul_channels_125k_index); - - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - config_us915_ul_channels_125k[config_us915_ul_channels_125k_index] / - 1000000, - (config_us915_ul_channels_125k[config_us915_ul_channels_125k_index] % - 1000000) / - 100000); - variable_item_set_current_value_text(item, text_buf); - - // Uplink Channel 500K - item = variable_item_list_add(app->variable_item_list_lorawan, - config_us915_ul_channels_500k_label, - COUNT_OF(config_us915_ul_channels_500k), - lora_config_us915_ul_channels_500k_change, app); - uint8_t config_us915_ul_channels_500k_index = 0; - variable_item_set_current_value_index(item, - config_us915_ul_channels_500k_index); - - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - config_us915_ul_channels_500k[config_us915_ul_channels_500k_index] / - 1000000, - (config_us915_ul_channels_500k[config_us915_ul_channels_500k_index] % - 1000000) / - 100000); - variable_item_set_current_value_text(item, text_buf); - - // Downlink Channel 500K - item = variable_item_list_add(app->variable_item_list_lorawan, - config_us915_dl_channels_500k_label, - COUNT_OF(config_us915_dl_channels_500k), - lora_config_us915_dl_channels_500k_change, app); - uint8_t config_us915_dl_channels_500k_index = 0; - variable_item_set_current_value_index(item, - config_us915_dl_channels_500k_index); - - snprintf(text_buf, sizeof(text_buf), "%3lu.%1lu MHz", - config_us915_dl_channels_500k[config_us915_dl_channels_500k_index] / - 1000000, - (config_us915_dl_channels_500k[config_us915_dl_channels_500k_index] % - 1000000) / - 100000); - variable_item_set_current_value_text(item, text_buf); - - variable_item_list_set_enter_callback(app->variable_item_list_config, - lora_setting_item_clicked, app); - - view_set_previous_callback( - variable_item_list_get_view(app->variable_item_list_config), - lora_navigation_submenu_callback); - - view_set_previous_callback( - variable_item_list_get_view(app->variable_item_list_lorawan), - lora_navigation_submenu_callback); - - view_dispatcher_add_view( - app->view_dispatcher, LoRaViewConfigure, - variable_item_list_get_view(app->variable_item_list_config)); - - view_dispatcher_add_view( - app->view_dispatcher, LoRaViewLoRaWAN, - variable_item_list_get_view(app->variable_item_list_lorawan)); - - app->view_sniffer = view_alloc(); - view_set_draw_callback(app->view_sniffer, lora_view_sniffer_draw_callback); - view_set_input_callback(app->view_sniffer, lora_view_sniffer_input_callback); - view_set_previous_callback(app->view_sniffer, - lora_navigation_submenu_callback); - view_set_enter_callback(app->view_sniffer, lora_view_sniffer_enter_callback); - view_set_exit_callback(app->view_sniffer, lora_view_sniffer_exit_callback); - view_set_context(app->view_sniffer, app); - view_set_custom_callback(app->view_sniffer, - lora_view_sniffer_custom_event_callback); - view_allocate_model(app->view_sniffer, ViewModelTypeLockFree, - sizeof(LoRaSnifferModel)); - LoRaSnifferModel* model_s = view_get_model(app->view_sniffer); - - model_s->config_freq_name = config_freq_name; - model_s->config_bw_index = config_bw_index; - model_s->config_sf_index = config_sf_index; - model_s->config_cr_index = config_sf_index; - - model_s->config_header_type_index = config_header_type_index; - model_s->config_crc_index = config_crc_index; - model_s->config_iq_index = config_iq_index; - - model_s->x = 0; - - model_s->dialogs_rx = furi_record_open(RECORD_DIALOGS); - model_s->storage_rx = furi_record_open(RECORD_STORAGE); - model_s->file_rx = storage_file_alloc(model_s->storage_rx); - - view_dispatcher_add_view(app->view_dispatcher, LoRaViewSniffer, - app->view_sniffer); - - app->view_transmitter = view_alloc(); - view_set_draw_callback(app->view_transmitter, - lora_view_transmitter_draw_callback); - view_set_input_callback(app->view_transmitter, - lora_view_transmitter_input_callback); - view_set_previous_callback(app->view_transmitter, - lora_navigation_submenu_callback); - view_set_enter_callback(app->view_transmitter, - lora_view_transmitter_enter_callback); - view_set_exit_callback(app->view_transmitter, - lora_view_transmitter_exit_callback); - view_set_context(app->view_transmitter, app); - view_set_custom_callback(app->view_transmitter, - lora_view_transmitter_custom_event_callback); - view_allocate_model(app->view_transmitter, ViewModelTypeLockFree, - sizeof(LoRaTransmitterModel)); - LoRaTransmitterModel* model_t = view_get_model(app->view_transmitter); - - model_t->x = 0; - - model_t->dialogs_tx = furi_record_open(RECORD_DIALOGS); - model_t->storage_tx = furi_record_open(RECORD_STORAGE); - model_t->file_tx = storage_file_alloc(model_t->storage_tx); - - makePaths(app); - - view_dispatcher_add_view(app->view_dispatcher, LoraViewTransmitter, - app->view_transmitter); - - app->widget_about = widget_alloc(); - widget_add_text_scroll_element( - app->widget_about, 0, 0, 128, 64, - "This is a LoRa sniffer app.\n---\nBrought to you " - "by\nElectronicCats!\n\nauthor: " - "@pigpen\nhttps://github.com/ElectronicCats/flipper-SX1262-LoRa"); - view_set_previous_callback(widget_get_view(app->widget_about), - lora_navigation_submenu_callback); - view_dispatcher_add_view(app->view_dispatcher, LoRaViewAbout, - widget_get_view(app->widget_about)); - - app->notifications = furi_record_open(RECORD_NOTIFICATION); + UNUSED(lora_config_eu_dr_change); + UNUSED(config_eu_dr_label); + + LoRaApp* app = (LoRaApp*)malloc(sizeof(LoRaApp)); + VariableItem* item; + Gui* gui = furi_record_open(RECORD_GUI); + + app->view_dispatcher = view_dispatcher_alloc(); + //view_dispatcher_enable_queue(app->view_dispatcher); + view_dispatcher_attach_to_gui(app->view_dispatcher, gui, ViewDispatcherTypeFullscreen); + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + + app->submenu = submenu_alloc(); + submenu_add_item( + app->submenu, "Config", LoRaSubmenuIndexConfigure, lora_submenu_callback, app); + submenu_add_item(app->submenu, "LoRaWAN", LoRaSubmenuIndexLoRaWAN, lora_submenu_callback, app); + submenu_add_item(app->submenu, "Sniffer", LoRaSubmenuIndexSniffer, lora_submenu_callback, app); + submenu_add_item( + app->submenu, "Transmitter", LoRaSubmenuIndexTransmitter, lora_submenu_callback, app); + submenu_add_item( + app->submenu, "Send LoRa byte", LoRaSubmenuIndexManualTX, lora_submenu_callback, app); + submenu_add_item(app->submenu, "About", LoRaSubmenuIndexAbout, lora_submenu_callback, app); + view_set_previous_callback(submenu_get_view(app->submenu), lora_navigation_exit_callback); + view_dispatcher_add_view( + app->view_dispatcher, LoRaViewSubmenu, submenu_get_view(app->submenu)); + view_dispatcher_switch_to_view(app->view_dispatcher, LoRaViewSubmenu); + + app->frequency_input = text_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, LoRaViewFrequencyInput, text_input_get_view(app->frequency_input)); + app->temp_buffer_size = 32; + app->temp_buffer = (char*)malloc(app->temp_buffer_size); + + app->byte_buffer_size = 16; + app->byte_buffer = (uint8_t*)malloc(app->byte_buffer_size); + + app->byte_input = byte_input_alloc(); + + view_dispatcher_add_view( + app->view_dispatcher, LoRaViewByteInput, byte_input_get_view(app->byte_input)); + + byte_input_set_header_text(app->byte_input, "Set byte to LoRa TX"); + byte_input_set_result_callback( + app->byte_input, set_value, NULL, app, app->byte_buffer, app->byte_buffer_size); + + view_set_previous_callback( + byte_input_get_view(app->byte_input), lora_navigation_submenu_callback); + + app->packetPayloadLength = 16; + + app->variable_item_list_config = variable_item_list_alloc(); + variable_item_list_reset(app->variable_item_list_config); + + app->variable_item_list_lorawan = variable_item_list_alloc(); + variable_item_list_reset(app->variable_item_list_lorawan); + + // frequency + FuriString* config_freq_name = furi_string_alloc(); + furi_string_set_str(config_freq_name, config_freq_default_value); + app->config_freq_item = variable_item_list_add( + app->variable_item_list_config, config_freq_config_label, 1, NULL, NULL); + variable_item_set_current_value_text( + app->config_freq_item, furi_string_get_cstr(config_freq_name)); + + // bw + item = variable_item_list_add( + app->variable_item_list_config, + config_bw_label, + COUNT_OF(config_bw_values), + lora_config_bw_change, + app); + uint8_t config_bw_index = 7; + variable_item_set_current_value_index(item, config_bw_index); + variable_item_set_current_value_text(item, config_bw_names[config_bw_index]); + + // sf + item = variable_item_list_add( + app->variable_item_list_config, + config_sf_label, + COUNT_OF(config_sf_values), + lora_config_sf_change, + app); + uint8_t config_sf_index = 3; + variable_item_set_current_value_index(item, config_sf_index); + variable_item_set_current_value_text(item, config_sf_names[config_sf_index]); + + // cr + item = variable_item_list_add( + app->variable_item_list_config, + config_cr_label, + COUNT_OF(config_cr_values), + lora_config_cr_change, + app); + uint8_t config_cr_index = 0; + variable_item_set_current_value_index(item, config_cr_index); + variable_item_set_current_value_text(item, config_cr_names[config_cr_index]); + + // Payload length + item = variable_item_list_add( + app->variable_item_list_config, + "Payload length", + 64, + lora_app_config_set_payload_length, + app); + variable_item_set_current_value_index(item, 16); + variable_item_set_current_value_text(item, "16"); + + // Header Type + item = variable_item_list_add( + app->variable_item_list_config, + config_header_type_label, + COUNT_OF(config_header_type_values), + lora_config_header_type_change, + app); + uint8_t config_header_type_index = 0; + variable_item_set_current_value_index(item, config_header_type_index); + variable_item_set_current_value_text(item, config_header_type_names[config_header_type_index]); + + // CRC + item = variable_item_list_add( + app->variable_item_list_config, + config_crc_label, + COUNT_OF(config_crc_values), + lora_config_crc_change, + app); + uint8_t config_crc_index = 0; + variable_item_set_current_value_index(item, config_crc_index); + variable_item_set_current_value_text(item, config_crc_names[config_crc_index]); + + // Inverted IQ + item = variable_item_list_add( + app->variable_item_list_config, + config_iq_label, + COUNT_OF(config_iq_values), + lora_config_iq_change, + app); + uint8_t config_iq_index = 0; + variable_item_set_current_value_index(item, config_iq_index); + variable_item_set_current_value_text(item, config_iq_names[config_iq_index]); + + // Frequency Plan + item = variable_item_list_add( + app->variable_item_list_lorawan, + config_region_label, + COUNT_OF(config_region_values), + lora_config_region_change, + app); + uint8_t config_region_index = 1; + variable_item_set_current_value_index(item, config_region_index); + variable_item_set_current_value_text(item, config_region_names[config_region_index]); + + // Data Rate + item = variable_item_list_add( + app->variable_item_list_lorawan, + config_us_dr_label, + COUNT_OF(config_us_dr_values), + lora_config_us_dr_change, + app); + uint8_t config_us_dr_index = 0; + variable_item_set_current_value_index(item, config_us_dr_index); + variable_item_set_current_value_text(item, config_us_dr_names[config_us_dr_index]); + + char text_buf[11] = {0}; + + // Uplink Channel 125K + item = variable_item_list_add( + app->variable_item_list_lorawan, + config_us915_ul_channels_125k_label, + COUNT_OF(config_us915_ul_channels_125k), + lora_config_us915_ul_channels_125k_change, + app); + uint8_t config_us915_ul_channels_125k_index = 0; + variable_item_set_current_value_index(item, config_us915_ul_channels_125k_index); + + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + config_us915_ul_channels_125k[config_us915_ul_channels_125k_index] / 1000000, + (config_us915_ul_channels_125k[config_us915_ul_channels_125k_index] % 1000000) / 100000); + variable_item_set_current_value_text(item, text_buf); + + // Uplink Channel 500K + item = variable_item_list_add( + app->variable_item_list_lorawan, + config_us915_ul_channels_500k_label, + COUNT_OF(config_us915_ul_channels_500k), + lora_config_us915_ul_channels_500k_change, + app); + uint8_t config_us915_ul_channels_500k_index = 0; + variable_item_set_current_value_index(item, config_us915_ul_channels_500k_index); + + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + config_us915_ul_channels_500k[config_us915_ul_channels_500k_index] / 1000000, + (config_us915_ul_channels_500k[config_us915_ul_channels_500k_index] % 1000000) / 100000); + variable_item_set_current_value_text(item, text_buf); + + // Downlink Channel 500K + item = variable_item_list_add( + app->variable_item_list_lorawan, + config_us915_dl_channels_500k_label, + COUNT_OF(config_us915_dl_channels_500k), + lora_config_us915_dl_channels_500k_change, + app); + uint8_t config_us915_dl_channels_500k_index = 0; + variable_item_set_current_value_index(item, config_us915_dl_channels_500k_index); + + snprintf( + text_buf, + sizeof(text_buf), + "%3lu.%1lu MHz", + config_us915_dl_channels_500k[config_us915_dl_channels_500k_index] / 1000000, + (config_us915_dl_channels_500k[config_us915_dl_channels_500k_index] % 1000000) / 100000); + variable_item_set_current_value_text(item, text_buf); + + variable_item_list_set_enter_callback( + app->variable_item_list_config, lora_setting_item_clicked, app); + + view_set_previous_callback( + variable_item_list_get_view(app->variable_item_list_config), + lora_navigation_submenu_callback); + + view_set_previous_callback( + variable_item_list_get_view(app->variable_item_list_lorawan), + lora_navigation_submenu_callback); + + view_dispatcher_add_view( + app->view_dispatcher, + LoRaViewConfigure, + variable_item_list_get_view(app->variable_item_list_config)); + + view_dispatcher_add_view( + app->view_dispatcher, + LoRaViewLoRaWAN, + variable_item_list_get_view(app->variable_item_list_lorawan)); + + app->view_sniffer = view_alloc(); + view_set_draw_callback(app->view_sniffer, lora_view_sniffer_draw_callback); + view_set_input_callback(app->view_sniffer, lora_view_sniffer_input_callback); + view_set_previous_callback(app->view_sniffer, lora_navigation_submenu_callback); + view_set_enter_callback(app->view_sniffer, lora_view_sniffer_enter_callback); + view_set_exit_callback(app->view_sniffer, lora_view_sniffer_exit_callback); + view_set_context(app->view_sniffer, app); + view_set_custom_callback(app->view_sniffer, lora_view_sniffer_custom_event_callback); + view_allocate_model(app->view_sniffer, ViewModelTypeLockFree, sizeof(LoRaSnifferModel)); + LoRaSnifferModel* model_s = view_get_model(app->view_sniffer); + + model_s->config_freq_name = config_freq_name; + model_s->config_bw_index = config_bw_index; + model_s->config_sf_index = config_sf_index; + model_s->config_cr_index = config_sf_index; + + model_s->config_header_type_index = config_header_type_index; + model_s->config_crc_index = config_crc_index; + model_s->config_iq_index = config_iq_index; + + model_s->x = 0; + + model_s->dialogs_rx = furi_record_open(RECORD_DIALOGS); + model_s->storage_rx = furi_record_open(RECORD_STORAGE); + model_s->file_rx = storage_file_alloc(model_s->storage_rx); + + view_dispatcher_add_view(app->view_dispatcher, LoRaViewSniffer, app->view_sniffer); + + app->view_transmitter = view_alloc(); + view_set_draw_callback(app->view_transmitter, lora_view_transmitter_draw_callback); + view_set_input_callback(app->view_transmitter, lora_view_transmitter_input_callback); + view_set_previous_callback(app->view_transmitter, lora_navigation_submenu_callback); + view_set_enter_callback(app->view_transmitter, lora_view_transmitter_enter_callback); + view_set_exit_callback(app->view_transmitter, lora_view_transmitter_exit_callback); + view_set_context(app->view_transmitter, app); + view_set_custom_callback(app->view_transmitter, lora_view_transmitter_custom_event_callback); + view_allocate_model( + app->view_transmitter, ViewModelTypeLockFree, sizeof(LoRaTransmitterModel)); + LoRaTransmitterModel* model_t = view_get_model(app->view_transmitter); + + model_t->x = 0; + + model_t->dialogs_tx = furi_record_open(RECORD_DIALOGS); + model_t->storage_tx = furi_record_open(RECORD_STORAGE); + model_t->file_tx = storage_file_alloc(model_t->storage_tx); + + makePaths(app); + + view_dispatcher_add_view(app->view_dispatcher, LoraViewTransmitter, app->view_transmitter); + + app->widget_about = widget_alloc(); + widget_add_text_scroll_element( + app->widget_about, + 0, + 0, + 128, + 64, + "This is a LoRa sniffer app.\n---\nBrought to you by\nElectronicCats!\n\nauthor: @pigpen\nhttps://github.com/ElectronicCats/flipper-SX1262-LoRa"); + view_set_previous_callback( + widget_get_view(app->widget_about), lora_navigation_submenu_callback); + view_dispatcher_add_view( + app->view_dispatcher, LoRaViewAbout, widget_get_view(app->widget_about)); + + app->notifications = furi_record_open(RECORD_NOTIFICATION); #ifdef BACKLIGHT_ON - notification_message(app->notifications, - &sequence_display_backlight_enforce_on); + notification_message(app->notifications, &sequence_display_backlight_enforce_on); #endif - return app; + return app; } /** * @brief Free the LoRa application. * @details This function frees the LoRa application resources. * @param app The LoRa application object. - */ +*/ static void lora_app_free(LoRaApp* app) { #ifdef BACKLIGHT_ON - notification_message(app->notifications, - &sequence_display_backlight_enforce_auto); + notification_message(app->notifications, &sequence_display_backlight_enforce_auto); #endif - furi_record_close(RECORD_NOTIFICATION); - - LoRaSnifferModel* model = view_get_model(app->view_sniffer); - storage_file_free(model->file_rx); - furi_record_close(RECORD_STORAGE); - furi_record_close(RECORD_DIALOGS); - - LoRaTransmitterModel* model_t = view_get_model(app->view_transmitter); - storage_file_free(model_t->file_tx); - furi_record_close(RECORD_STORAGE); - furi_record_close(RECORD_DIALOGS); - - view_dispatcher_remove_view(app->view_dispatcher, LoRaViewFrequencyInput); - text_input_free(app->frequency_input); - - view_dispatcher_remove_view(app->view_dispatcher, LoRaViewByteInput); - byte_input_free(app->byte_input); - - free(app->temp_buffer); - free(app->byte_buffer); - - view_dispatcher_remove_view(app->view_dispatcher, LoRaViewAbout); - widget_free(app->widget_about); - view_dispatcher_remove_view(app->view_dispatcher, LoRaViewSniffer); - view_free(app->view_sniffer); - view_dispatcher_remove_view(app->view_dispatcher, LoraViewTransmitter); - view_free(app->view_transmitter); - view_dispatcher_remove_view(app->view_dispatcher, LoRaViewConfigure); - variable_item_list_free(app->variable_item_list_config); - view_dispatcher_remove_view(app->view_dispatcher, LoRaViewLoRaWAN); - variable_item_list_free(app->variable_item_list_lorawan); - view_dispatcher_remove_view(app->view_dispatcher, LoRaViewSubmenu); - submenu_free(app->submenu); - view_dispatcher_free(app->view_dispatcher); - furi_record_close(RECORD_GUI); - - free(app); + furi_record_close(RECORD_NOTIFICATION); + + LoRaSnifferModel* model = view_get_model(app->view_sniffer); + storage_file_free(model->file_rx); + furi_record_close(RECORD_STORAGE); + furi_record_close(RECORD_DIALOGS); + + LoRaTransmitterModel* model_t = view_get_model(app->view_transmitter); + storage_file_free(model_t->file_tx); + furi_record_close(RECORD_STORAGE); + furi_record_close(RECORD_DIALOGS); + + view_dispatcher_remove_view(app->view_dispatcher, LoRaViewFrequencyInput); + text_input_free(app->frequency_input); + + view_dispatcher_remove_view(app->view_dispatcher, LoRaViewByteInput); + byte_input_free(app->byte_input); + + free(app->temp_buffer); + free(app->byte_buffer); + + view_dispatcher_remove_view(app->view_dispatcher, LoRaViewAbout); + widget_free(app->widget_about); + view_dispatcher_remove_view(app->view_dispatcher, LoRaViewSniffer); + view_free(app->view_sniffer); + view_dispatcher_remove_view(app->view_dispatcher, LoraViewTransmitter); + view_free(app->view_transmitter); + view_dispatcher_remove_view(app->view_dispatcher, LoRaViewConfigure); + variable_item_list_free(app->variable_item_list_config); + view_dispatcher_remove_view(app->view_dispatcher, LoRaViewLoRaWAN); + variable_item_list_free(app->variable_item_list_lorawan); + view_dispatcher_remove_view(app->view_dispatcher, LoRaViewSubmenu); + submenu_free(app->submenu); + view_dispatcher_free(app->view_dispatcher); + furi_record_close(RECORD_GUI); + + free(app); } /** * @brief Main function for LoRa application. - * @details This function is the entry point for the LoRa application. It - * should be defined in application.fam as the entry_point setting. + * @details This function is the entry point for the LoRa application. It should be defined in + * application.fam as the entry_point setting. * @param _p Input parameter - unused * @return 0 - Success - */ +*/ int32_t main_lora_app(void* _p) { - UNUSED(_p); - - spi->cs = &gpio_ext_pc0; - - furi_hal_spi_bus_handle_init(spi); - - abandone(); - - if (!begin()) { - DialogsApp* dialogs_msg = furi_record_open(RECORD_DIALOGS); - DialogMessage* message = dialog_message_alloc(); - dialog_message_set_text(message, - "Error!\nSubGHz add-on module failed to " - "start\n\nCheck that the module is plugged in", - 0, 0, AlignLeft, AlignTop); - dialog_message_show(dialogs_msg, message); - dialog_message_free(message); - furi_record_close(RECORD_DIALOGS); - return 0; - } + UNUSED(_p); + + spi->cs = &gpio_ext_pc0; + + furi_hal_spi_bus_handle_init(spi); + + abandone(); + + if(!begin()) { + DialogsApp* dialogs_msg = furi_record_open(RECORD_DIALOGS); + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_text( + message, + "Error!\nSubGHz add-on module failed to start\n\nCheck that the module is plugged in", + 0, + 0, + AlignLeft, + AlignTop); + dialog_message_show(dialogs_msg, message); + dialog_message_free(message); + furi_record_close(RECORD_DIALOGS); + return 0; + } - LoRaApp* app = lora_app_alloc(); + LoRaApp* app = lora_app_alloc(); - app->packetPreamble = 0x000C; - app->packetHeaderType = 0x00; - app->packetPayloadLength = 0xFF; - app->packetCRC = 0x00; - app->packetInvertIQ = 0x00; + app->packetPreamble = 0x000C; + app->packetHeaderType = 0x00; + app->packetPayloadLength = 0xFF; + app->packetCRC = 0x00; + app->packetInvertIQ = 0x00; - view_dispatcher_run(app->view_dispatcher); + view_dispatcher_run(app->view_dispatcher); - lora_app_free(app); + lora_app_free(app); - furi_hal_spi_bus_handle_deinit(spi); - spi->cs = &gpio_ext_pa4; + furi_hal_spi_bus_handle_deinit(spi); + spi->cs = &gpio_ext_pa4; - // Typically when a pin is no longer in use, it is set to analog mode. - furi_hal_gpio_init_simple(pin_led, GpioModeAnalog); + // Typically when a pin is no longer in use, it is set to analog mode. + furi_hal_gpio_init_simple(pin_led, GpioModeAnalog); - return 0; + return 0; } diff --git a/applications_user/lora_relay/application.fam b/applications_user/lora_relay/application.fam deleted file mode 100644 index ab3f743..0000000 --- a/applications_user/lora_relay/application.fam +++ /dev/null @@ -1,14 +0,0 @@ -App( - appid="lora_relay", - name="LoRa Relay", - apptype=FlipperAppType.DEBUG, - entry_point="lora_relay_app", - requires=["gui"], - fap_libs=["u8g2"], - stack_size=1 * 1024, - order=120, - fap_category="Misc", - fap_icon="cat.png", - fap_icon_assets="assets", - fap_description="LoRa Relay App. This is a LoRa sniffer using Electronic Cats flipper add-on", -) diff --git a/applications_user/lora_relay/assets/flippers_cat.png b/applications_user/lora_relay/assets/flippers_cat.png deleted file mode 100755 index fd5542b..0000000 Binary files a/applications_user/lora_relay/assets/flippers_cat.png and /dev/null differ diff --git a/applications_user/lora_relay/assets/glyph_1_14x40.png b/applications_user/lora_relay/assets/glyph_1_14x40.png deleted file mode 100644 index 39687b0..0000000 Binary files a/applications_user/lora_relay/assets/glyph_1_14x40.png and /dev/null differ diff --git a/applications_user/lora_relay/assets/kitty_tx.png b/applications_user/lora_relay/assets/kitty_tx.png deleted file mode 100644 index c7ecb33..0000000 Binary files a/applications_user/lora_relay/assets/kitty_tx.png and /dev/null differ diff --git a/applications_user/lora_relay/assets/log.png b/applications_user/lora_relay/assets/log.png deleted file mode 100644 index 0e2642d..0000000 Binary files a/applications_user/lora_relay/assets/log.png and /dev/null differ diff --git a/applications_user/lora_relay/assets/no_signal.png b/applications_user/lora_relay/assets/no_signal.png deleted file mode 100644 index 743627f..0000000 Binary files a/applications_user/lora_relay/assets/no_signal.png and /dev/null differ diff --git a/applications_user/lora_relay/assets/no_write.png b/applications_user/lora_relay/assets/no_write.png deleted file mode 100644 index bbb92da..0000000 Binary files a/applications_user/lora_relay/assets/no_write.png and /dev/null differ diff --git a/applications_user/lora_relay/assets/paper.png b/applications_user/lora_relay/assets/paper.png deleted file mode 100644 index 69cb5ba..0000000 Binary files a/applications_user/lora_relay/assets/paper.png and /dev/null differ diff --git a/applications_user/lora_relay/assets/sam_flipper.png b/applications_user/lora_relay/assets/sam_flipper.png deleted file mode 100644 index a140432..0000000 Binary files a/applications_user/lora_relay/assets/sam_flipper.png and /dev/null differ diff --git a/applications_user/lora_relay/assets/signal.png b/applications_user/lora_relay/assets/signal.png deleted file mode 100644 index 0e31f5c..0000000 Binary files a/applications_user/lora_relay/assets/signal.png and /dev/null differ diff --git a/applications_user/lora_relay/assets/write.png b/applications_user/lora_relay/assets/write.png deleted file mode 100755 index 229694d..0000000 Binary files a/applications_user/lora_relay/assets/write.png and /dev/null differ diff --git a/applications_user/lora_relay/cat.png b/applications_user/lora_relay/cat.png deleted file mode 100755 index 1911bfd..0000000 Binary files a/applications_user/lora_relay/cat.png and /dev/null differ diff --git a/applications_user/lora_relay/lora.c b/applications_user/lora_relay/lora.c deleted file mode 100644 index c943154..0000000 --- a/applications_user/lora_relay/lora.c +++ /dev/null @@ -1,1041 +0,0 @@ -/* -Code porting from LoRa library -https://github.dev/thekakester/Arduino-LoRa-Sx1262 -*/ - -#include -#include - -#define TAG "LORA" - -// Presets. These help make radio config easier -#define PRESET_DEFAULT 0 -#define PRESET_LONGRANGE 1 -#define PRESET_FAST 2 - -#define REG_LR_SYNCWORD 0x0740 -#define RADIO_READ_REGISTER 0x1D - -#define REG_RFFrequency31_24 0x088B -#define REG_RFFrequency23_16 0x088C -#define REG_RFFrequency15_8 0x088D -#define REG_RFFrequency7_0 0x088E - -#define FREQ_STEP 0.95367431640625 - -static uint32_t timeout = 1000; -// static uint32_t timeout = 100; -static FuriHalSpiBusHandle* spi = &furi_hal_spi_bus_handle_external; - -const GpioPin* const pin_beacon = &gpio_swclk; -const GpioPin* const pin_nss1 = &gpio_ext_pc0; -const GpioPin* const pin_reset = &gpio_ext_pc1; -const GpioPin* const pin_ant_sw = &gpio_usart_tx; -const GpioPin* const pin_busy = &gpio_usart_rx; -const GpioPin* const pin_dio1 = &gpio_ext_pc3; - -bool inReceiveMode = false; -uint8_t spiBuff[32]; // Buffer for sending SPI commands to radio - -// Config variables (set to PRESET_DEFAULT on init) -uint32_t pllFrequency; -uint8_t bandwidth; -uint8_t codingRate; -uint8_t spreadingFactor; -uint8_t lowDataRateOptimize; -uint32_t transmitTimeout; // Worst-case transmit time depends on some factors - -int rssi = 0; -int snr = 0; -int signalRssi = 0; - -// test -void abandone() { - FURI_LOG_E(TAG, "abandon hope all ye who enter here"); -} - -void checkBusy() { - uint8_t busy_timeout_cnt; - busy_timeout_cnt = 0; - - furi_hal_gpio_init_simple(pin_busy, GpioModeInput); - - while (furi_hal_gpio_read(pin_busy)) { - furi_delay_ms(1); - busy_timeout_cnt++; - - if (busy_timeout_cnt > 10) // wait 10mS for busy to complete - { - busy_timeout_cnt = 0; - FURI_LOG_E(TAG, "ERROR - Busy Timeout!"); - break; - } - } -} - -void readRegisters(uint16_t address, uint8_t* buffer, uint16_t size) { - uint16_t index; - uint8_t addr_l, addr_h; - - addr_h = address >> 8; - addr_l = address & 0x00FF; - checkBusy(); - - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - - furi_hal_spi_acquire(spi); - - spiBuff[0] = RADIO_READ_REGISTER; - spiBuff[1] = addr_h; - spiBuff[2] = addr_l; - spiBuff[3] = 0x00; - - furi_hal_spi_bus_tx(spi, spiBuff, 4, timeout); - - for (index = 0; index < size; index++) { - furi_hal_spi_bus_rx(spi, buffer + index, 1, timeout); - } - - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select -} - -uint8_t readRegister(uint16_t address) { - uint8_t data; - - readRegisters(address, &data, 1); - return data; -} - -uint16_t getSyncWord() { - uint8_t msb, lsb; - uint16_t syncword; - msb = readRegister(REG_LR_SYNCWORD); - lsb = readRegister(REG_LR_SYNCWORD + 1); - - FURI_LOG_E(TAG, "MSB: %02x", msb); - FURI_LOG_E(TAG, "LSB: %02x", lsb); - - syncword = (msb << 8) + lsb; - - return syncword; -} - -uint32_t getFreqInt() { - // get the current set device frequency from registers, return as long integer - - uint8_t MsbH, MsbL, Mid, Lsb; - uint32_t uinttemp; - float floattemp; - MsbH = readRegister(REG_RFFrequency31_24); - MsbL = readRegister(REG_RFFrequency23_16); - Mid = readRegister(REG_RFFrequency15_8); - Lsb = readRegister(REG_RFFrequency7_0); - floattemp = - ((MsbH * 0x1000000ul) + (MsbL * 0x10000ul) + (Mid * 0x100ul) + Lsb); - floattemp = ((floattemp * FREQ_STEP) / 1000000ul); - uinttemp = (uint32_t) (floattemp * 1000000); - return uinttemp; -} - -/*Convert a frequency in hz (such as 915000000) to the respective PLL setting. - * The radio requires that we set the PLL, which controls the multipler on the - * internal clock to achieve the desired frequency. Valid frequencies are 150MHz - * to 960MHz (150000000 to 960000000) - * - * NOTE: This assumes the radio is using a 32mhz clock, which is standard. This - * is independent of the microcontroller clock See datasheet section 13.4.1 for - * this calculation. Example: 915mhz (915000000) has a PLL of 959447040 - */ -uint32_t frequencyToPLL(long rfFreq) { - /* Datasheet Says: - * rfFreq = (pllFreq * xtalFreq) / 2^25 - * Rewrite to solve for pllFreq - * pllFreq = (2^25 * rfFreq)/xtalFreq - * - * In our case, xtalFreq is 32mhz - * pllFreq = (2^25 * rfFreq) / 32000000 - */ - // Basically, we need to do "return ((1 << 25) * rfFreq) / 32000000L" - // It's very important to perform this without losing precision or integer - // overflow. If arduino supported 64-bit varibales (which it doesn't), we - // could just do this: - // uint64_t firstPart = (1 << 25) * (uint64_t)rfFreq; - // return (uint32_t)(firstPart / 32000000L); - // - // Instead, we need to break this up mathimatically to avoid integer overflow - // First, we'll simplify the equation by dividing both parts by 2048 (2^11) - // ((1 << 25) * rfFreq) / 32000000L --> (16384 * rfFreq) / - // 15625; - // - // Now, we'll divide first, then multiply (multiplying first would cause - // integer overflow) Because we're dividing, we need to keep track of the - // remainder to avoid losing precision - uint32_t q = rfFreq / 15625UL; // Gives us the result (quotient), rounded - // down to the nearest integer - uint32_t r = rfFreq % 15625UL; // Everything that isn't divisible, aka "the - // part that hasn't been divided yet" - - // Multiply by 16384 to satisfy the equation above - q *= 16384UL; - r *= 16384UL; // Don't forget, this part still needs to be divided because it - // was too small to divide before - - return q + (r / 15625UL); // Finally divide the the remainder part before - // adding it back in with the quotient -} - -// Set the radio frequency. Just a single SPI call, -// but this is broken out to make it more convenient to change frequency -// on-the-fly You must set this->pllFrequency before calling this -void updateRadioFrequency() { - // Set PLL frequency (this is a complicated math equation. See datasheet entry - // for SetRfFrequency) - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x86; // Opcode for set RF Frequencty - spiBuff[1] = (pllFrequency >> 24) & 0xFF; // MSB of pll frequency - spiBuff[2] = (pllFrequency >> 16) & 0xFF; // - spiBuff[3] = (pllFrequency >> 8) & 0xFF; // - spiBuff[4] = (pllFrequency >> 0) & 0xFF; // LSB of requency - furi_hal_spi_bus_tx(spi, spiBuff, 5, timeout); - - furi_hal_spi_release(spi); - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for the radio to process command -} - -/** (Optional) Set the operating frequency of the radio. - * The 1262 radio supports 150-960Mhz. This library uses a default of 915Mhz. - * MAKE SURE THAT YOU ARE OPERATING IN A FREQUENCY THAT IS ALLOWED IN YOUR - * COUNTRY! For example, 915mhz (915000000 hz) is safe in the US. - * - * Specify the desired frequency in Hz (eg 915MHZ is 915000000). - * Returns TRUE on success, FALSE on invalid frequency - */ -bool configSetFrequency(long frequencyInHz) { - // Make sure the specified frequency is in the valid range. - if (frequencyInHz < 150000000 || frequencyInHz > 960000000) { - return false; - } - - // Calculate the PLL frequency (See datasheet section 13.4.1 for calculation) - // PLL frequency controls the radio's clock multipler to achieve the desired - // frequency - pllFrequency = frequencyToPLL(frequencyInHz); - updateRadioFrequency(); - return true; -} - -// Set the radio modulation parameters. -// This is things like bandwidth, spreading factor, coding rate, etc. -// This is broken into its own function because this command might get called -// frequently -void updateModulationParameters() { - // Set modulation parameters - // Modulation parameters are: - // - SpreadingFactor - // - Bandwidth - // - CodingRate - // - LowDataRateOptimize - // None of these actually matter that much. You can set them to anything, and - // data will still show up on a radio frequency monitor. You just MUST call - // "setModulationParameters", otherwise the radio won't work at all - - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - - spiBuff[0] = 0x8B; // Opcode for "SetModulationParameters" - spiBuff[1] = spreadingFactor; // ModParam1 = Spreading Factor. Can be - // SF5-SF12, written in hex (0x05-0x0C) - spiBuff[2] = bandwidth; // ModParam2 = Bandwidth. See Datasheet 13.4.5.2 for - // details. 0x00=7.81khz (slowest) - spiBuff[3] = codingRate; // ModParam3 = CodingRate. Semtech recommends - // CR_4_5 (which is 0x01). Options are 0x01-0x04, - // which correspond to coding rate 5-8 respectively - spiBuff[4] = lowDataRateOptimize; // LowDataRateOptimize. 0x00 = 0ff, 0x01 = - // On. Required to be on for SF11 + SF12 - - furi_hal_spi_acquire(spi); - - if (furi_hal_spi_bus_tx( - spi, spiBuff, 5, - timeout)) { // Assuming 'timeout' is defined somewhere in the code - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } - - // furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for the radio to process command - - // Determine transmit timeout based on spreading factor - // TODO: - // TIMEOUT SET TO 1000, STILL CHECKING HOW TO FIX - switch (spreadingFactor) { - case 12: - transmitTimeout = 1000; // 252000; // Actual tx time 126 seconds - break; - case 11: - transmitTimeout = 1000; // 160000; // Actual tx time 81 seconds - break; - case 10: - transmitTimeout = 1000; // 60000; // Actual tx time 36 seconds - break; - case 9: - transmitTimeout = 1000; // 40000; // Actual tx time 20 seconds - break; - case 8: - transmitTimeout = 1000; // 20000; // Actual tx time 11 seconds - break; - case 7: - transmitTimeout = 1000; // 12000; // Actual tx time 6.3 seconds - break; - case 6: - transmitTimeout = 1000; // 7000; // Actual tx time 3.7s seconds - break; - default: // SF5 - transmitTimeout = 1000; // 5000; // Actual tx time 2.2 seconds - break; - } -} - -/**(Optional) Use one of the pre-made radio configurations - * This is ideal for making simple changes to the radio config - * without needing to understand how the underlying settings work - * - * Argument: pass in one of the following - * - PRESET_DEFAULT: Default radio config. - * Medium range, medium speed - * - PRESET_FAST: Faster speeds, but less reliable at long ranges. - * Use when you need fast data transfer and have radios - * close together - * - PRESET_LONGRANGE: Most reliable option, but slow. Suitable when you - * prioritize reliability over speed, or when transmitting over long distances - */ -bool configSetPreset(int preset) { - if (preset == PRESET_DEFAULT) { - bandwidth = 0x04; // 125khz - codingRate = 0x01; // CR_4_5 - spreadingFactor = 0x08; // SF8 - lowDataRateOptimize = 0; // Don't optimize (used for SF12 only) - updateModulationParameters(); - return true; - } - - if (preset == PRESET_LONGRANGE) { - bandwidth = 4; // 125khz - codingRate = 1; // CR_4_5 - spreadingFactor = 12; // SF12 - lowDataRateOptimize = 1; // Optimize for low data rate (SF12 only) - updateModulationParameters(); - return true; - } - - if (preset == PRESET_FAST) { - bandwidth = 6; // 500khz - codingRate = 1; // CR_4_5 - spreadingFactor = 5; // SF5 - lowDataRateOptimize = 0; // Don't optimize (used for SF12 only) - updateModulationParameters(); - return true; - } - - // Invalid preset specified - return false; -} - -/*Send the bare-bones required commands needed for radio to run. - * Do not set custom or optional commands here, please keep this section as - * simplified as possible. Essential commands are found by reading the datasheet - */ -void configureRadioEssentials() { - // Tell DIO2 to control the RF switch so we don't have to do it manually - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x9D; // Opcode for "SetDIO2AsRfSwitchCtrl" - spiBuff[1] = 0x01; // Enable - - if (furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for the radio to process command - - // Just a single SPI command to set the frequency, but it's broken out - // into its own function so we can call it on-the-fly when the config changes - configSetFrequency(915000000); // Set default frequency to 915mhz - - // Set modem to LoRa (described in datasheet section 13.4.2) - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x8A; // Opcode for "SetPacketType" - spiBuff[1] = 0x01; // Packet Type: 0x00=GFSK, 0x01=LoRa - - if (furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for radio to process the command - - // Set Rx Timeout to reset on SyncWord or Header detection - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x9F; // Opcode for "StopTimerOnPreamble" - spiBuff[1] = 0x00; // Stop timer on: 0x00=SyncWord or header detection, - // 0x01=preamble detection - - if (furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for radio to process the command - - // Set modulation parameters is just one more SPI command, but since it - // is often called frequently when changing the radio config, it's broken up - // into its own function - configSetPreset(PRESET_DEFAULT); // Sets default modulation parameters - - // Set PA Config - // See datasheet 13.1.4 for descriptions and optimal settings recommendations - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x95; // Opcode for "SetPaConfig" - spiBuff[1] = - 0x04; // paDutyCycle. See datasheet, set in conjunction with hpMax - spiBuff[2] = - 0x07; // hpMax. Basically Tx power. 0x00-0x07 where 0x07 is max power - spiBuff[3] = 0x00; // device select: 0x00 = SX1262, 0x01 = SX1261 - spiBuff[4] = 0x01; // paLut (reserved, always set to 1) - - if (furi_hal_spi_bus_tx(spi, spiBuff, 5, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for radio to process the command - - // Set TX Params - // See datasheet 13.4.4 for details - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x8E; // Opcode for SetTxParams - spiBuff[1] = 22; // Power. Can be -17(0xEF) to +14x0E in Low Pow mode. - // -9(0xF7) to 22(0x16) in high power mode - spiBuff[2] = 0x02; // Ramp time. Lookup table. See table 13-41. 0x02="40uS" - - if (furi_hal_spi_bus_tx(spi, spiBuff, 3, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for radio to process the command - - // Set LoRa Symbol Number timeout - // How many symbols are needed for a good receive. - // Symbols are preamble symbols - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0xA0; // Opcode for "SetLoRaSymbNumTimeout" - spiBuff[1] = - 0x00; // Number of symbols. Ping-pong example from Semtech uses 5 - - if (furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for radio to process the command - - // Enable interrupts - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x08; // 0x08 is the opcode for "SetDioIrqParams" - spiBuff[1] = 0x00; // IRQMask MSB. IRQMask is "what interrupts are enabled" - spiBuff[2] = 0x02; // IRQMask LSB See datasheet table 13-29 for details - spiBuff[3] = 0xFF; // DIO1 mask MSB. Of the interrupts detected, which should - // be triggered on DIO1 pin - spiBuff[4] = 0xFF; // DIO1 Mask LSB - spiBuff[5] = 0x00; // DIO2 Mask MSB - spiBuff[6] = 0x00; // DIO2 Mask LSB - spiBuff[7] = 0x00; // DIO3 Mask MSB - spiBuff[8] = 0x00; // DIO3 Mask LSB - - if (furi_hal_spi_bus_tx(spi, spiBuff, 9, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - furi_delay_ms(100); // Give time for radio to process the command -} - -bool waitForRadioCommandCompletion(uint32_t timeout) { - uint32_t startTime = furi_get_tick(); // Get the start time in ticks - bool dataTransmitted = false; - - // Keep checking the radio status until the operation is completed - while (!dataTransmitted) { - // Wait a while between SPI status queries to avoid reading too quickly - furi_delay_ms(5); - - // Request a status update from the radio - furi_hal_gpio_write(pin_nss1, false); // Enable the radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0xC0; // Opcode for the "getStatus" command - spiBuff[1] = 0x00; // Dummy byte, status will overwrite this byte - - furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout); - - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable the radio chip-select - - // Parse the status - uint8_t chipMode = - (spiBuff[1] >> 4) & 0x07; // Chip mode is bits [6:4] (3-bits) - uint8_t commandStatus = - (spiBuff[1] >> 1) & 0x07; // Command status is bits [3:1] (3-bits) - - // Check if the operation has finished - // Status 0, 1, 2 mean we're still busy. Anything else means we're done. - // Commands 3-6 = command timeout, command processing error, failure to - // execute command, and Tx Done (respoectively) - if (commandStatus != 0 && commandStatus != 1 && commandStatus != 2) { - dataTransmitted = true; - FURI_LOG_E(TAG, "DATA TRANSMITTED"); - } - - // If we are in standby mode, there's no need to wait anymore - if (chipMode == 0x03 || chipMode == 0x02) { - dataTransmitted = true; - FURI_LOG_E(TAG, "DATA TRANSMITTED STANBY MODE"); - } - - // Prevent infinite loop by implementing a timeout - if ((furi_get_tick() - startTime) >= furi_ms_to_ticks(timeout)) { - return false; - } - } - - // Success! - return true; -} - -/* Set the bandwidth (basically, this is how big the frequency span is that we -occupy) Bigger bandwidth allows us to transmit large amounts of data faster, but -it occupies a larger span of frequencies. Smaller bandwidth takes longer to -transmit large amounts of data, but its less likely to collide with other -frequencies. - -Available bandwidth settings, pulled from datasheet 13.4.5.2 -SETTING. | Bandwidth -------------+----------- -0x00 | 7.81khz -0x08 | 10.42khz -0x01 | 15.63khz -0x09 | 20.83khz -0x02 | 31.25khz -0x0A | 41.67khz -0x03 | 62.50khz -0x04 | 125.00khz -0x05 | 250.00khz (default) -0x06 | 500.00khz -*/ -bool configSetBandwidth(int bw) { - if (bw < 0 || bw > 0x0A || bw == 7) { - return false; - } - bandwidth = bw; - updateModulationParameters(); - return true; -} - -/* Set the coding rate*/ -bool configSetCodingRate(int cr) { - // Coding rate must be 1-4 (inclusive) - if (cr < 1 || cr > 4) { - return false; - } - codingRate = cr; - updateModulationParameters(); - return true; -} - -/* Change the spreading factor of a packet -The higher the spreading factor, the slower and more reliable the transmission -will be. */ -bool configSetSpreadingFactor(int sf) { - if (sf < 5 || sf > 12) { - return false; - } - lowDataRateOptimize = - (sf >= 11) ? 1 : 0; // Turn on for SF11+SF12, turn off for anything else - spreadingFactor = sf; - updateModulationParameters(); - return true; -} - -// Sets the radio into receive mode, allowing it to listen for incoming packets. -// If radio is already in receive mode, this does nothing. -// There's no such thing as "setModeTransmit" because it is set automatically -// when transmit() is called -void setModeReceive() { - if (inReceiveMode) { - return; - } // We're already in receive mode, this would do nothing - - // Set packet parameters - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x8C; // Opcode for "SetPacketParameters" - spiBuff[1] = 0x00; // PacketParam1 = Preamble Len MSB - spiBuff[2] = 0x0C; // PacketParam2 = Preamble Len LSB - spiBuff[3] = 0x00; // PacketParam3 = Header Type. 0x00 = Variable Len, 0x01 = - // Fixed Length - spiBuff[4] = 0xFF; // PacketParam4 = Payload Length (Max is 255 bytes) - spiBuff[5] = 0x00; // PacketParam5 = CRC Type. 0x00 = Off, 0x01 = on - spiBuff[6] = - 0x00; // PacketParam6 = Invert IQ. 0x00 = Standard, 0x01 = Inverted - - if (furi_hal_spi_bus_tx(spi, spiBuff, 7, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } - - // furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - - waitForRadioCommandCompletion(100); - - // Tell the chip to wait for it to receive a packet. - // Based on our previous config, this should throw an interrupt when we get a - // packet - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x82; // 0x82 is the opcode for "SetRX" - spiBuff[1] = 0xFF; // 24-bit timeout, 0xFFFFFF means no timeout - spiBuff[2] = 0xFF; // ^^ - spiBuff[3] = 0xFF; // ^^ - - if (furi_hal_spi_bus_tx(spi, spiBuff, 4, timeout)) { - furi_hal_spi_release(spi); - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - } - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - - waitForRadioCommandCompletion(100); - - // Remember that we're in receive mode so we don't need to run this code again - // unnecessarily - inReceiveMode = true; -} - -/* Set radio into standby mode. -Switching directly from Rx to Tx mode can be slow, so we first want to go into -standby */ -void setModeStandby() { - // Tell the chip to wait for it to receive a packet. - // Based on our previous config, this should throw an interrupt when we get a - // packet - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - - spiBuff[0] = 0x80; // 0x80 is the opcode for "SetStandby" - spiBuff[1] = 0x01; // 0x00 = STDBY_RC, 0x01=STDBY_XOSC - - furi_hal_spi_acquire(spi); - furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout); - furi_hal_spi_release(spi); - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - waitForRadioCommandCompletion(100); - inReceiveMode = false; // No longer in receive mode -} - -void transmit(uint8_t* data, int dataLen) { - // Max lora packet size is 255 bytes - if (dataLen > 255) { - dataLen = 255; - } - - // Switching directly from rx to tx mode is slow. Go to standby first - if (inReceiveMode) { - setModeStandby(); - } - - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - - spiBuff[0] = 0x8C; // Opcode for "SetPacketParameters" - spiBuff[1] = 0x00; // PacketParam1 = Preamble Len MSB - spiBuff[2] = 0x0C; // PacketParam2 = Preamble Len LSB - spiBuff[3] = 0x00; // PacketParam3 = Header Type. 0x00 = Variable Len, 0x01 = - // Fixed Length - spiBuff[4] = dataLen; // PacketParam4 = Payload Length (Max is 255 bytes) - spiBuff[5] = 0x00; // PacketParam5 = CRC Type. 0x00 = Off, 0x01 = on - spiBuff[6] = - 0x00; // PacketParam6 = Invert IQ. 0x00 = Standard, 0x01 = Inverted - - furi_hal_spi_acquire(spi); - furi_hal_spi_bus_tx(spi, spiBuff, 7, timeout); - furi_hal_spi_release(spi); - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - waitForRadioCommandCompletion( - 100); // Give time for radio to process the command - - // Write the payload to the buffer - // Reminder: PayloadLength is defined in setPacketParams - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - - spiBuff[0] = 0x0E, // Opcode for WriteBuffer command - spiBuff[1] = 0x00; // Dummy byte before writing payload - - furi_hal_spi_acquire(spi); - furi_hal_spi_bus_tx(spi, spiBuff, 2, timeout); - - // Transmit data in chunks to avoid overwriting the original buffer - uint8_t size = sizeof(spiBuff); - for (uint16_t i = 0; i < dataLen; i += size) { - if (i + size > dataLen) { - size = dataLen - i; - } - memcpy(spiBuff, &(data[i]), size); - furi_hal_spi_bus_tx(spi, data + i, size, - timeout); // Write the payload itself - } - - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - waitForRadioCommandCompletion( - 1000); // Give time for radio to process the command - - // Transmit - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - - spiBuff[0] = 0x83; // Opcode for SetTx command - spiBuff[1] = 0xFF; // Timeout (3-byte number) - spiBuff[2] = 0xFF; // Timeout (3-byte number) - spiBuff[3] = 0xFF; // Timeout (3-byte number) - - furi_hal_spi_acquire(spi); - furi_hal_spi_bus_tx(spi, spiBuff, 4, timeout); - furi_hal_spi_release(spi); - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - - waitForRadioCommandCompletion( - transmitTimeout); // Wait for tx to complete, with a timeout so we don't - // wait forever - - // Remember that we are in Tx mode. If we want to receive a packet, we need - // to switch into receiving mode - inReceiveMode = false; -} - -/*Receive a packet if available -If available, this will return the size of the packet and store the packet -contents into the user-provided buffer. A max length of the buffer can be -provided to avoid buffer overflow. If buffer is not large enough for entire -payload, overflow is thrown out. Recommended to pass in a buffer that is 255 -bytes long to make sure you can received any lora packet that comes in. - -Returns -1 when no packet is available. -Returns 0 when an empty packet is received (packet with no payload) -Returns payload size (1-255) when a packet with a non-zero payload is received. -If packet received is larger than the buffer provided, this will return -buffMaxLen -*/ -int lora_receive_async(u_int8_t* buff, int buffMaxLen) { - setModeReceive(); // Sets the mode to receive (if not already in receive - // mode) - - if (furi_hal_gpio_read(pin_dio1)) { - furi_hal_gpio_write(pin_beacon, true); - furi_delay_ms(50); - furi_hal_gpio_write(pin_beacon, false); - } - - // Radio pin DIO1 (interrupt) goes high when we have a packet ready. If it's - // low, there's no packet yet - if (!furi_hal_gpio_read(pin_dio1)) { - return -1; - } // Return -1, meaning no packet ready - - FURI_LOG_E(TAG, "packet ready... "); - - // Tell the radio to clear the interrupt, and set the pin back inactive. - while (furi_hal_gpio_read(pin_dio1)) { - // Clear all interrupt flags. This should result in the interrupt pin going - // low - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x02; // Opcode for ClearIRQStatus command - spiBuff[1] = - 0xFF; // IRQ bits to clear (MSB) (0xFFFF means clear all interrupts) - spiBuff[2] = 0xFF; // IRQ bits to clear (LSB) - - furi_hal_spi_bus_tx(spi, spiBuff, 3, timeout); - - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - } - - // (Optional) Read the packet status info from the radio. - // This provides debug info about the packet we received - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x14; // Opcode for get packet status - spiBuff[1] = 0xFF; // Dummy byte. Returns status - spiBuff[2] = 0xFF; // Dummy byte. Returns rssi - spiBuff[3] = 0xFF; // Dummy byte. Returns snd - spiBuff[4] = 0xFF; // Dummy byte. Returns signal RSSI - - furi_hal_spi_bus_rx(spi, spiBuff, 5, timeout); - - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - - // Store these values as class variables so they can be accessed if needed - // Documentation for what these variables mean can be found in the .h file - rssi = - -((int) spiBuff[2]) / 2; // "Average over last packet received of RSSI. - // Actual signal power is –RssiPkt/2 (dBm)" - snr = ((int8_t) spiBuff[3]) / 4; // SNR is returned as a SIGNED byte, so we - // need to do some conversion first - signalRssi = -((int) spiBuff[4]) / 2; - - // We're almost ready to read the packet from the radio - // But first we have to know how big the packet is, and where in the radio - // memory it is stored - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x13; // Opcode for GetRxBufferStatus command - spiBuff[1] = 0xFF; // Dummy. Returns radio status - spiBuff[2] = 0xFF; // Dummy. Returns loraPacketLength - spiBuff[3] = 0xFF; // Dummy. Returns memory offset (address) - - furi_hal_spi_bus_rx(spi, spiBuff, 4, timeout); - - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - - uint8_t payloadLen = spiBuff[2]; // How long the lora packet is - - FURI_LOG_E(TAG, "payloadLen = %d", payloadLen); - - uint8_t startAddress = - spiBuff[3]; // Where in 1262 memory is the packet stored - - // Make sure we don't overflow the buffer if the packet is larger than our - // buffer - if (buffMaxLen < payloadLen) { - payloadLen = buffMaxLen; - } - - // Read the radio buffer from the SX1262 into the user-supplied buffer - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x1E; // Opcode for ReadBuffer command - spiBuff[1] = startAddress; // SX1262 memory location to start reading from - spiBuff[2] = 0x00; // Dummy byte - furi_hal_spi_bus_tx(spi, spiBuff, 3, - timeout); // Send commands to get read started - furi_hal_spi_bus_rx(spi, buff, payloadLen, - timeout); // Get the contents from the radio and store it - // into the user provided buffer - - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - - return payloadLen; // Return how many bytes we actually read -} - -void regTest() { - uint8_t regValue; - checkBusy(); - - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - - furi_hal_spi_acquire(spi); - - spiBuff[0] = 0x1D; - spiBuff[1] = 0x07; - spiBuff[2] = 0x40; - spiBuff[3] = 0x00; - - furi_hal_spi_bus_tx(spi, spiBuff, 4, timeout); - furi_hal_spi_bus_rx(spi, ®Value, 1, timeout); - - furi_hal_spi_release(spi); - - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select -} - -/* Tests that SPI is communicating correctly with the radio. - * If this fails, check your SPI wiring. This does not require any setup to - * run. We test the radio by reading a register that should have a known value. - * - * Returns: True if radio is communicating over SPI. False if no connection. - */ -bool sanityCheck() { - uint8_t command_read_register[1] = {0x1D}; // OpCode for "read register" - uint8_t read_register_address[2] = {0x07, 0x40}; - uint8_t dummy_byte = 0x00; - uint8_t regValue; - - furi_hal_gpio_write(pin_nss1, false); // Enable radio chip-select - furi_hal_spi_acquire(spi); - - if (furi_hal_spi_bus_tx(spi, command_read_register, 1, timeout) && - furi_hal_spi_bus_tx(spi, read_register_address, 2, timeout) && - furi_hal_spi_bus_tx(spi, &dummy_byte, 1, timeout) && - furi_hal_spi_bus_rx(spi, ®Value, 1, timeout)) { - FURI_LOG_E(TAG, "REGISTER VALUE: %02x", regValue); - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - - if (regValue == 0x14) { - // Initialize the LED pin as output. - // GpioModeOutputPushPull means true = 3.3 volts, false = 0 volts. - // GpioModeOutputOpenDrain means true = floating, false = 0 volts. - furi_hal_gpio_init_simple(pin_beacon, GpioModeOutputPushPull); - furi_hal_gpio_write(pin_beacon, true); - furi_delay_ms(100); - furi_hal_gpio_write(pin_beacon, false); - furi_delay_ms(100); - furi_hal_gpio_write(pin_beacon, true); - furi_delay_ms(100); - furi_hal_gpio_write(pin_beacon, false); - furi_delay_ms(100); - } - - return regValue == 0x14; // Success if we read 0x14 from the register - } else { - FURI_LOG_E(TAG, - "FAILED - furi_hal_spi_bus_tx or furi_hal_spi_bus_rx failed."); - furi_hal_spi_release(spi); - furi_hal_gpio_write(pin_nss1, true); // Disable radio chip-select - return false; - } -} - -void printRegisters(uint16_t Start, uint16_t End) { - // prints the contents of SX126x registers to serial monitor - - uint16_t Loopv1, Loopv2, RegData; - - FURI_LOG_E(TAG, "Reg 0 1 2 3 4 5 6 7 8 9 A B C D E F"); - - for (Loopv1 = Start; Loopv1 <= End;) // 32 lines - { - FURI_LOG_E(TAG, "0x%02x ", Loopv1); - - for (Loopv2 = 0; Loopv2 <= 15; Loopv2++) { - RegData = readRegister(Loopv1); - if (RegData < 0x10) { - // FURI_LOG_E(TAG,"0"); - } - - FURI_LOG_E(TAG, "0x%02x ", RegData); - - Loopv1++; - } - FURI_LOG_E(TAG, "\n"); - } -} - -bool begin() { - // furi_hal_gpio_init(pin_reset, GpioModeOutputPushPull, GpioPullUp, - // GpioSpeedVeryHigh); furi_hal_gpio_init(pin_nss1, GpioModeOutputPushPull, - // GpioPullUp, GpioSpeedVeryHigh); - - furi_hal_gpio_init_simple(pin_reset, GpioModeOutputPushPull); - furi_hal_gpio_init_simple(pin_nss1, GpioModeOutputPushPull); - - furi_hal_gpio_init_simple(pin_beacon, GpioModeOutputPushPull); - - furi_hal_gpio_write(pin_nss1, true); - furi_hal_gpio_write(pin_reset, true); - - furi_hal_gpio_init_simple(pin_dio1, GpioModeInput); - - FURI_LOG_E(TAG, "RESET DEVICE..."); - furi_delay_ms(10); - furi_hal_gpio_write(pin_reset, false); - furi_delay_ms(2); - furi_hal_gpio_write(pin_reset, true); - furi_delay_ms(25); - - checkBusy(); - - // Ensure SPI communication is working with the radio - FURI_LOG_E(TAG, "SANITYCHECK..."); - bool success = sanityCheck(); - if (!success) { - return false; - } - - // Run the bare-minimum required SPI commands to set up the radio to use - configureRadioEssentials(); - - uint32_t lora_freq = getFreqInt(); - - FURI_LOG_E(TAG, " FREQUENCY: %ld", lora_freq); - - return true; // Return success that we set up the radio -} diff --git a/applications_user/lora_relay/lora_relay.c b/applications_user/lora_relay/lora_relay.c deleted file mode 100644 index af20a03..0000000 --- a/applications_user/lora_relay/lora_relay.c +++ /dev/null @@ -1,304 +0,0 @@ -#include "lora_relay.h" - -#include -#include - -// Need access to u8g2 -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "view_lora_rx.h" -#include "view_lora_tx.h" - -#define LORA_APP_FOLDER "apps_data/lora" - -static FuriHalSpiBusHandle* spi = &furi_hal_spi_bus_handle_external; - -const GpioPin* const pin_led = &gpio_swclk; -const GpioPin* const pin_back = &gpio_button_back; - -#define TAG "LoRaRelay" - -void abandone(); -void configureRadioEssentials(); -bool begin(); -bool sanityCheck(); -void checkBusy(); -void setModeReceive(); -int lora_receive_async(u_int8_t* buff, int buffMaxLen); -bool configSetFrequency(long frequencyInHz); -bool configSetBandwidth(int bw); -bool configSetSpreadingFactor(int sf); - -// Our application menu has 2 items. You can add more items if you want. -typedef enum { - LoRaRelaySubmenuIndexConfigure, - LoRaRelaySubmenuIndexAbout, -} LoRaRelaySubmenuIndex; - -typedef struct { - Gui* gui; - ViewDispatcher* view_dispatcher; - ViewLoRaRX* view_lora_rx; - ViewLoRaTX* view_lora_tx; - Widget* widget_about; // The about screen - DialogsApp* dialogs; - - VariableItemList* variable_item_list; - Submenu* submenu; - - uint8_t config_bw; - uint8_t config_frequency; - uint8_t config_sf; -} LoRaRelay; - -typedef enum { - LoRaRelayViewSubmenu, - LoRaRelayViewConfigure, - LoRaRelayViewLoRaRX, - LoRaRelayViewLoRaTX, - LoRaRelayViewLoRaAbout, -} LoRaRelayView; - -const uint8_t config_bw_value[] = { - 0x00, 0x08, 0x01, 0x09, 0x02, 0x0A, 0x03, 0x04, 0x05, 0x06, -}; -const char* const config_bw_text[] = { - "7.81 kHz", "10.42 kHz", "15.63 kHz", "20.83 kHz", "31.25 kHz", - "41.67 kHz", "62.50 kHz", "125 kHz", "250 kHz", "500 kHz", -}; - -const uint8_t config_sf_value[] = { - 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, -}; -const char* const config_sf_text[] = { - "SF5", "SF6", "SF7", "SF8", "SF9", "SF10", "SF11", "SF12", -}; - -// void lora_make_app_folder(LoRaRelay* instance) { -// furi_assert(instance); - -// if(!storage_simply_mkdir(instance->storage, LORA_APP_FOLDER)) { -// dialog_message_show_storage_error(instance->dialogs, "Cannot -// create\napp folder"); -// } -// } - -static void lora_relay_submenu_callback(void* context, uint32_t index) { - LoRaRelay* instance = (LoRaRelay*) context; - view_dispatcher_switch_to_view(instance->view_dispatcher, index); - // switch(index) { - // case LoRaRelaySubmenuIndexConfigure: - // view_dispatcher_switch_to_view(instance->view_dispatcher, - // LoRaRelayViewSubmenu); break; - // case LoRaRelaySubmenuIndexAbout: - // view_dispatcher_switch_to_view(instance->view_dispatcher, - // LoRaRelayViewLoRaAbout); break; - // default: - // break; - // } -} - -static uint32_t lora_relay_previous_callback(void* context) { - UNUSED(context); - return LoRaRelayViewSubmenu; -} - -static uint32_t lora_relay_exit_callback(void* context) { - UNUSED(context); - return VIEW_NONE; -} - -static void lora_relay_reload_config(LoRaRelay* instance) { - FURI_LOG_I(TAG, "frequency: %d, sf: %d, bw: %d", instance->config_frequency, - instance->config_sf, instance->config_bw); -} - -static void lora_config_set_bw(VariableItem* item) { - LoRaRelay* instance = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, config_bw_text[index]); - instance->config_bw = config_bw_value[index]; - - configSetBandwidth(config_bw_value[index]); - - lora_relay_reload_config(instance); -} - -static void lora_config_set_sf(VariableItem* item) { - LoRaRelay* instance = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, config_sf_text[index]); - instance->config_sf = config_sf_value[index]; - - configSetSpreadingFactor(config_sf_value[index]); - - lora_relay_reload_config(instance); -} - -static void lora_config_set_frequency(VariableItem* item) { - LoRaRelay* instance = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - FuriString* temp; - temp = furi_string_alloc(); - furi_string_cat_printf(temp, "%d", index + 883); - variable_item_set_current_value_text(item, furi_string_get_cstr(temp)); - furi_string_free(temp); - instance->config_frequency = index; - - configSetFrequency((index + 883) * 1000000); - - lora_relay_reload_config(instance); -} - -LoRaRelay* lora_relay_alloc() { - LoRaRelay* instance = malloc(sizeof(LoRaRelay)); - - View* view = NULL; - - instance->gui = furi_record_open(RECORD_GUI); - - instance->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(instance->view_dispatcher); - view_dispatcher_attach_to_gui(instance->view_dispatcher, instance->gui, - ViewDispatcherTypeFullscreen); - - // Configure - instance->variable_item_list = variable_item_list_alloc(); - view = variable_item_list_get_view(instance->variable_item_list); - view_set_previous_callback(view, lora_relay_previous_callback); - view_dispatcher_add_view(instance->view_dispatcher, LoRaRelayViewConfigure, - view); - - // RX - instance->view_lora_rx = view_lora_rx_alloc(); - view = view_lora_rx_get_view(instance->view_lora_rx); - view_set_previous_callback(view, lora_relay_previous_callback); - view_dispatcher_add_view(instance->view_dispatcher, LoRaRelayViewLoRaRX, - view); - - // TX - instance->view_lora_tx = view_lora_tx_alloc(); - view = view_lora_tx_get_view(instance->view_lora_tx); - view_set_previous_callback(view, lora_relay_previous_callback); - view_dispatcher_add_view(instance->view_dispatcher, LoRaRelayViewLoRaTX, - view); - - // Configuration items - VariableItem* item; - instance->config_bw = 0x04; - instance->config_frequency = 32; - instance->config_sf = 0x08; - // Frequency - item = variable_item_list_add(instance->variable_item_list, "Frequency:", 64, - lora_config_set_frequency, instance); - variable_item_set_current_value_index(item, 32); - variable_item_set_current_value_text(item, "915"); - // Band Width - item = variable_item_list_add(instance->variable_item_list, - "Band Width:", COUNT_OF(config_bw_value), - lora_config_set_bw, instance); - variable_item_set_current_value_index(item, 7); - variable_item_set_current_value_text(item, config_bw_text[7]); - // Spread Factor - item = variable_item_list_add(instance->variable_item_list, - "Spread Factor:", COUNT_OF(config_sf_value), - lora_config_set_sf, instance); - variable_item_set_current_value_index(item, 3); - variable_item_set_current_value_text(item, config_sf_text[3]); - - // Menu - instance->submenu = submenu_alloc(); - view = submenu_get_view(instance->submenu); - view_set_previous_callback(view, lora_relay_exit_callback); - view_dispatcher_add_view(instance->view_dispatcher, LoRaRelayViewSubmenu, - view); - submenu_add_item(instance->submenu, "LoRa settings", LoRaRelayViewConfigure, - lora_relay_submenu_callback, instance); - submenu_add_item(instance->submenu, "LoRa sniffer", LoRaRelayViewLoRaRX, - lora_relay_submenu_callback, instance); - submenu_add_item(instance->submenu, "LoRa sender", LoRaRelayViewLoRaTX, - lora_relay_submenu_callback, instance); - submenu_add_item(instance->submenu, "About", LoRaRelayViewLoRaAbout, - lora_relay_submenu_callback, instance); - - instance->widget_about = widget_alloc(); - widget_add_text_scroll_element( - instance->widget_about, 0, 0, 128, 64, - "This is a sample application.\n---\nReplace code and message\nwith your " - "content!\n\nauthor: " - "@codeallnight\nhttps://discord.com/invite/NsjCvqwPAd\nhttps://" - "youtube.com/@MrDerekJamison"); - view_set_previous_callback(widget_get_view(instance->widget_about), - lora_relay_previous_callback); - view_dispatcher_add_view(instance->view_dispatcher, LoRaRelayViewLoRaAbout, - widget_get_view(instance->widget_about)); - - return instance; -} - -void lora_relay_free(LoRaRelay* instance) { - view_dispatcher_remove_view(instance->view_dispatcher, LoRaRelayViewSubmenu); - submenu_free(instance->submenu); - - view_dispatcher_remove_view(instance->view_dispatcher, - LoRaRelayViewConfigure); - variable_item_list_free(instance->variable_item_list); - - view_dispatcher_remove_view(instance->view_dispatcher, LoRaRelayViewLoRaRX); - view_dispatcher_remove_view(instance->view_dispatcher, LoRaRelayViewLoRaTX); - view_dispatcher_remove_view(instance->view_dispatcher, - LoRaRelayViewLoRaAbout); - widget_free(instance->widget_about); - view_lora_rx_free(instance->view_lora_rx); - view_lora_tx_free(instance->view_lora_tx); - - view_dispatcher_free(instance->view_dispatcher); - furi_record_close(RECORD_GUI); - - free(instance); -} - -int32_t lora_relay_run(LoRaRelay* instance) { - UNUSED(instance); - view_dispatcher_switch_to_view(instance->view_dispatcher, - LoRaRelayViewSubmenu); - view_dispatcher_run(instance->view_dispatcher); - - return 0; -} - -int32_t lora_relay_app(void* p) { - UNUSED(p); - - spi->cs = &gpio_ext_pc0; - - furi_hal_spi_bus_handle_init(spi); - - abandone(); - - begin(); - - LoRaRelay* instance = lora_relay_alloc(); - - int32_t ret = lora_relay_run(instance); - - lora_relay_free(instance); - - furi_hal_spi_bus_handle_deinit(spi); - spi->cs = &gpio_ext_pa4; - - // Typically when a pin is no longer in use, it is set to analog mode. - furi_hal_gpio_init_simple(pin_led, GpioModeAnalog); - - return ret; -} diff --git a/applications_user/lora_relay/lora_relay.h b/applications_user/lora_relay/lora_relay.h deleted file mode 100644 index 6f70f09..0000000 --- a/applications_user/lora_relay/lora_relay.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/applications_user/lora_relay/view_lora_rx.c b/applications_user/lora_relay/view_lora_rx.c deleted file mode 100644 index 1ddfb5f..0000000 --- a/applications_user/lora_relay/view_lora_rx.c +++ /dev/null @@ -1,230 +0,0 @@ -#include -#include -#include -#include - -#include "lora_relay_icons.h" -#include "view_lora_rx.h" - -#define PATHAPP "apps_data/lora" -#define PATHAPPEXT EXT_PATH(PATHAPP) -#define PATHLORA PATHAPPEXT "/data.log" -#define LORA_LOG_FILE_EXTENSION ".log" - -#define TAG "RX " - -const GpioPin* const test_led = &gpio_swclk; - -int lora_receive_async(u_int8_t* buff, int buffMaxLen); - -uint8_t receiveBuff[255]; -char asciiBuff[255]; - -typedef struct { - uint32_t test; - uint32_t size; - uint32_t counter; - bool flag_file; - DialogsApp* dialogs; - Storage* storage; - File* file; -} ViewLoRaRXModel; - -struct ViewLoRaRX { - View* view; - FuriTimer* timer; -}; - -static void view_lora_rx_draw_callback_intro(Canvas* canvas, void* _model) { - UNUSED(_model); - - canvas_draw_icon(canvas, 0, 0, &I_flippers_cat); - canvas_draw_str(canvas, 17, 8, "Use > to start sniffing"); -} - -void bytesToAscii(uint8_t* buffer, uint8_t length) { - uint8_t i; - for (i = 0; i < length; ++i) { - asciiBuff[i * 2] = "0123456789ABCDEF"[buffer[i] >> 4]; // High nibble - asciiBuff[i * 2 + 1] = "0123456789ABCDEF"[buffer[i] & 0x0F]; // Low nibble - } - asciiBuff[length * 2] = '\0'; // Null-terminate the string - FURI_LOG_E(TAG, "OUT bytesToAscii "); -} - -static void view_lora_rx_draw_callback_move(Canvas* canvas, void* _model) { - ViewLoRaRXModel* model = _model; - - bool flag_file = model->flag_file; - - uint8_t block = 5 + model->size; - uint8_t width = canvas_width(canvas) - block; - uint8_t height = canvas_height(canvas) - block; - - uint8_t x = model->counter % width; - if ((model->counter / width) % 2) { - x = width - x; - } - - uint8_t y = model->counter % height; - if ((model->counter / height) % 2) { - y = height - y; - } - - canvas_draw_box(canvas, x, y, block, block); - - // Receive a packet over radio - int bytesRead = lora_receive_async(receiveBuff, sizeof(receiveBuff)); - - if (bytesRead > -1) { - FURI_LOG_E(TAG, "Packet received... "); - receiveBuff[bytesRead] = '\0'; - - if (flag_file) { - storage_file_write(model->file, receiveBuff, bytesRead); - storage_file_write(model->file, "\n", 1); - } - - FURI_LOG_E(TAG, "%s", receiveBuff); - bytesToAscii(receiveBuff, 16); - asciiBuff[17] = '.'; - asciiBuff[18] = '.'; - asciiBuff[19] = '.'; - asciiBuff[20] = '\0'; - } - - if (flag_file) { - canvas_draw_icon(canvas, 110, 4, &I_write); - } else { - canvas_draw_icon(canvas, 110, 4, &I_no_write); - } - - canvas_draw_str(canvas, 0, 8, "Use (o) to start/stop"); - canvas_draw_str(canvas, 0, 16, "recording"); - canvas_draw_str(canvas, 0, 30, "Packet received..."); - canvas_draw_str(canvas, 0, 40, asciiBuff); - canvas_draw_str(canvas, 0, 52, "ASCII:"); - canvas_draw_str(canvas, 0, 62, - (const char*) receiveBuff); //(char*)receiveBuff); -} - -const ViewDrawCallback view_lora_rx_tests[] = { - view_lora_rx_draw_callback_intro, - view_lora_rx_draw_callback_move, -}; - -static void view_lora_rx_draw_callback(Canvas* canvas, void* _model) { - ViewLoRaRXModel* model = _model; - view_lora_rx_tests[model->test](canvas, _model); -} - -static bool view_lora_rx_input_callback(InputEvent* event, void* context) { - ViewLoRaRX* instance = context; - - bool consumed = false; - if (event->type == InputTypeShort || event->type == InputTypeRepeat) { - with_view_model( - instance->view, ViewLoRaRXModel * model, - { - if (event->key == InputKeyLeft && model->test > 0) { - model->test--; - consumed = true; - } else if (event->key == InputKeyRight && - model->test < (COUNT_OF(view_lora_rx_tests) - 1)) { - model->test++; - consumed = true; - } else if (event->key == InputKeyDown && model->size > 0) { - model->size--; - consumed = true; - } else if (event->key == InputKeyUp && model->size < 24) { - model->size++; - consumed = true; - } else if (event->key == InputKeyOk) { - model->flag_file = !model->flag_file; - - if (model->flag_file) { - storage_file_open(model->file, PATHLORA, FSAM_WRITE, - FSOM_CREATE_ALWAYS); - FURI_LOG_E(TAG, "OPEN FILE "); - } else { - storage_file_close(model->file); - FURI_LOG_E(TAG, "CLOSE FILE "); - } - consumed = true; - } - }, - consumed); - } - - return consumed; -} - -static void view_lora_rx_enter(void* context) { - ViewLoRaRX* instance = context; - furi_timer_start(instance->timer, furi_kernel_get_tick_frequency() / 32); - - // Initialize the LED pin as output. - // GpioModeOutputPushPull means true = 3.3 volts, false = 0 volts. - // GpioModeOutputOpenDrain means true = floating, false = 0 volts. - furi_hal_gpio_init_simple(test_led, GpioModeOutputPushPull); -} - -static void view_lora_rx_exit(void* context) { - ViewLoRaRX* instance = context; - - ViewLoRaRXModel* model = view_get_model(instance->view); - - furi_timer_stop(instance->timer); - model->test = 0; -} - -static void view_lora_rx_timer_callback(void* context) { - ViewLoRaRX* instance = context; - with_view_model( - instance->view, ViewLoRaRXModel * model, { model->counter++; }, true); -} - -ViewLoRaRX* view_lora_rx_alloc() { - ViewLoRaRX* instance = malloc(sizeof(ViewLoRaRX)); - - instance->view = view_alloc(); - view_set_context(instance->view, instance); - - view_allocate_model(instance->view, ViewModelTypeLockFree, - sizeof(ViewLoRaRXModel)); - - ViewLoRaRXModel* model = view_get_model(instance->view); - - model->dialogs = furi_record_open(RECORD_DIALOGS); - model->storage = furi_record_open(RECORD_STORAGE); - model->file = storage_file_alloc(model->storage); - - view_set_draw_callback(instance->view, view_lora_rx_draw_callback); - view_set_input_callback(instance->view, view_lora_rx_input_callback); - view_set_enter_callback(instance->view, view_lora_rx_enter); - view_set_exit_callback(instance->view, view_lora_rx_exit); - - instance->timer = furi_timer_alloc(view_lora_rx_timer_callback, - FuriTimerTypePeriodic, instance); - - return instance; -} - -void view_lora_rx_free(ViewLoRaRX* instance) { - furi_assert(instance); - - ViewLoRaRXModel* model = view_get_model(instance->view); - - storage_file_free(model->file); - furi_record_close(RECORD_STORAGE); - furi_record_close(RECORD_DIALOGS); - - furi_timer_free(instance->timer); - view_free(instance->view); - free(instance); -} - -View* view_lora_rx_get_view(ViewLoRaRX* instance) { - furi_assert(instance); - return instance->view; -} diff --git a/applications_user/lora_relay/view_lora_rx.h b/applications_user/lora_relay/view_lora_rx.h deleted file mode 100644 index afc4ca9..0000000 --- a/applications_user/lora_relay/view_lora_rx.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include -#include - -typedef struct ViewLoRaRX ViewLoRaRX; - -ViewLoRaRX* view_lora_rx_alloc(); - -void view_lora_rx_free(ViewLoRaRX* instance); - -View* view_lora_rx_get_view(ViewLoRaRX* instance); diff --git a/applications_user/lora_relay/view_lora_tx.c b/applications_user/lora_relay/view_lora_tx.c deleted file mode 100644 index 3828417..0000000 --- a/applications_user/lora_relay/view_lora_tx.c +++ /dev/null @@ -1,277 +0,0 @@ -#include -#include -#include -#include -#include -// #include -#include - -#include "lora_relay_icons.h" -#include "view_lora_tx.h" - -#define PATHAPP "apps_data/lora" -#define PATHAPPEXT EXT_PATH(PATHAPP) -#define PATHLORA PATHAPPEXT "/data.txt" -#define LORA_LOG_FILE_EXTENSION ".log" - -#define TAG "TX " - -const GpioPin* const tx_led = &gpio_swclk; - -void transmit(uint8_t* data, int dataLen); - -typedef struct { - uint32_t test; - uint32_t size; - uint32_t counter; - bool flag_tx_file; - bool flag_signal; - FuriString* text; - DialogsApp* dialogs; - Storage* storage; - File* file; - FuriString* setting_2_name; // The name setting -} ViewLoRaTXModel; - -struct ViewLoRaTX { - ViewDispatcher* view_dispatcher; - View* view; - TextInput* text_input; // The text input screen - char* temp_buffer; // Temporary buffer for text input - uint32_t temp_buffer_size; // Size of temporary buffer - FuriTimer* timer; -}; - -// Each view is a screen we show the user. -typedef enum { - LoRaTXViewTextInput, // Input for configuring text settings - LoRaTXViewConfigure, // The configuration screen - LoRaTXViewAbout, // The about screen with directions, link to social channel, - // etc. -} LoRaTXView; - -static void view_lora_tx_draw_callback_intro(Canvas* canvas, void* _model) { - UNUSED(_model); - - canvas_draw_str(canvas, 6, 12, "Use (o) to select file and send content"); -} - -static void view_lora_tx_draw_callback_move(Canvas* canvas, void* _model) { - ViewLoRaTXModel* model = _model; - - bool flag_tx = model->flag_tx_file; - - uint8_t block = 5 + model->size; - uint8_t width = canvas_width(canvas) - block; - uint8_t height = canvas_height(canvas) - block; - - canvas_draw_icon(canvas, 0, 0, &I_kitty_tx); - - uint8_t x = model->counter % width; - - if (model->counter % 20) { - model->flag_signal = !model->flag_signal; - } - - if ((model->counter / width) % 2) { - x = width - x; - } - - uint8_t y = model->counter % height; - if ((model->counter / height) % 2) { - y = height - y; - } - - if (flag_tx) { - } - - if (model->flag_signal) { - canvas_draw_icon(canvas, 44, 15, &I_signal); - } else { - canvas_draw_icon(canvas, 44, 15, &I_no_signal); - } - - canvas_draw_box(canvas, x, y, block, block); - - canvas_draw_str(canvas, 6, 12, "LoRa TX..."); -} - -const ViewDrawCallback view_lora_tx_tests[] = { - view_lora_tx_draw_callback_intro, - view_lora_tx_draw_callback_move, -}; - -static void view_lora_tx_draw_callback(Canvas* canvas, void* _model) { - ViewLoRaTXModel* model = _model; - view_lora_tx_tests[model->test](canvas, _model); -} - -static bool view_lora_tx_input_callback(InputEvent* event, void* context) { - ViewLoRaTX* instance = context; - - uint8_t transmitBuff[64]; - - bool consumed = false; - if (event->type == InputTypeShort || event->type == InputTypeRepeat) { - with_view_model( - instance->view, ViewLoRaTXModel * model, - { - if (event->key == InputKeyLeft && model->test > 0) { - // model->test--; - consumed = true; - } else if (event->key == InputKeyRight) { //&& - // model->test < (COUNT_OF(view_lora_tx_tests) - 1)) { - // model->test++; - consumed = true; - } else if (event->key == InputKeyDown) { //&& model->size > 0) { - // model->size--; - consumed = true; - } else if (event->key == InputKeyUp) { //&& model->size < 24) { - // model->size++; - consumed = true; - } else if (event->key == InputKeyOk) { - FuriString* predefined_filepath = - furi_string_alloc_set_str(PATHAPP); - FuriString* selected_filepath = furi_string_alloc(); - DialogsFileBrowserOptions browser_options; - dialog_file_browser_set_basic_options( - &browser_options, LORA_LOG_FILE_EXTENSION, NULL); - browser_options.base_path = PATHAPP; - - dialog_file_browser_show(model->dialogs, selected_filepath, - predefined_filepath, &browser_options); - - if (storage_file_open(model->file, - furi_string_get_cstr(selected_filepath), - FSAM_READ, FSOM_OPEN_EXISTING)) { - model->flag_tx_file = true; - model->test = 1; - - // furi_string_reset(model->text); - char buf[storage_file_size(model->file)]; - - storage_file_read(model->file, buf, sizeof(buf)); - buf[sizeof(buf)] = '\0'; - - uint16_t maxlen = sizeof(buf); - - for (uint16_t i = 0, j = 0; i < maxlen; i++, j++) { - transmitBuff[j] = buf[i]; - if (buf[i] == '\n') { - transmitBuff[j] = '\0'; - transmit(transmitBuff, j); - furi_delay_ms(10); - j = 0; - i++; - } - } - } else { - dialog_message_show_storage_error(model->dialogs, - "Cannot open File"); - } - storage_file_close(model->file); - model->test = 0; - furi_string_free(selected_filepath); - furi_string_free(predefined_filepath); - - furi_hal_gpio_write(tx_led, true); - furi_delay_ms(50); - furi_hal_gpio_write(tx_led, false); - - model->flag_tx_file = false; - consumed = true; - } - }, - consumed); - } - - return consumed; -} - -// static const char* setting_2_config_label = "Name"; -// static const char* setting_2_entry_text = "Enter name"; -// static const char* setting_2_default_value = "Bob"; - -// static void view_lora_tx_setting_2_text_updated(void* context) { -// ViewLoRaTX* instance = (ViewLoRaTX*)context; -// bool redraw = true; -// with_view_model( -// instance->view, -// ViewLoRaTXModel * model, -// { -// furi_string_set(model->setting_2_name, instance->temp_buffer); -// //variable_item_set_current_value_text( -// //model->setting_2_name, -// furi_string_get_cstr(model->setting_2_name)); -// }, -// redraw); -// view_dispatcher_switch_to_view(instance->view_dispatcher, -// LoRaTXViewConfigure); -// } - -static void view_lora_tx_enter(void* context) { - ViewLoRaTX* instance = context; - furi_timer_start(instance->timer, furi_kernel_get_tick_frequency() / 32); - - // Initialize the LED pin as output. - // GpioModeOutputPushPull means true = 3.3 volts, false = 0 volts. - // GpioModeOutputOpenDrain means true = floating, false = 0 volts. - furi_hal_gpio_init_simple(tx_led, GpioModeOutputPushPull); -} - -static void view_lora_tx_exit(void* context) { - ViewLoRaTX* instance = context; - furi_timer_stop(instance->timer); -} - -static void view_lora_tx_timer_callback(void* context) { - ViewLoRaTX* instance = context; - with_view_model( - instance->view, ViewLoRaTXModel * model, { model->counter++; }, true); -} - -ViewLoRaTX* view_lora_tx_alloc() { - ViewLoRaTX* instance = malloc(sizeof(ViewLoRaTX)); - - instance->view = view_alloc(); - view_set_context(instance->view, instance); - view_allocate_model(instance->view, ViewModelTypeLockFree, - sizeof(ViewLoRaTXModel)); - - ViewLoRaTXModel* model = view_get_model(instance->view); - - model->dialogs = furi_record_open(RECORD_DIALOGS); - model->storage = furi_record_open(RECORD_STORAGE); - model->file = storage_file_alloc(model->storage); - model->text = furi_string_alloc(); - - view_set_draw_callback(instance->view, view_lora_tx_draw_callback); - view_set_input_callback(instance->view, view_lora_tx_input_callback); - view_set_enter_callback(instance->view, view_lora_tx_enter); - view_set_exit_callback(instance->view, view_lora_tx_exit); - - instance->timer = furi_timer_alloc(view_lora_tx_timer_callback, - FuriTimerTypePeriodic, instance); - - return instance; -} - -void view_lora_tx_free(ViewLoRaTX* instance) { - furi_assert(instance); - - ViewLoRaTXModel* model = view_get_model(instance->view); - - storage_file_free(model->file); - furi_record_close(RECORD_STORAGE); - furi_record_close(RECORD_DIALOGS); - furi_string_free(model->text); - - furi_timer_free(instance->timer); - view_free(instance->view); - free(instance); -} - -View* view_lora_tx_get_view(ViewLoRaTX* instance) { - furi_assert(instance); - return instance->view; -} diff --git a/applications_user/lora_relay/view_lora_tx.h b/applications_user/lora_relay/view_lora_tx.h deleted file mode 100644 index 3d03948..0000000 --- a/applications_user/lora_relay/view_lora_tx.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include -#include - -typedef struct ViewLoRaTX ViewLoRaTX; - -ViewLoRaTX* view_lora_tx_alloc(); - -void view_lora_tx_free(ViewLoRaTX* instance); - -View* view_lora_tx_get_view(ViewLoRaTX* instance);