diff --git a/docs/about/overview/radio-settings.mdx b/docs/about/overview/radio-settings.mdx index 233cb887..1a6df906 100644 --- a/docs/about/overview/radio-settings.mdx +++ b/docs/about/overview/radio-settings.mdx @@ -6,6 +6,8 @@ sidebar_label: Radio Settings sidebar_position: 1 --- +import {FrequencyCalculator} from "/src/components/tools/FrequencyCalculator"; + :::info Meshtastic is **not** LoRaWAN, Helium or TTN (TheThingsNetwork). Meshtastic uses the full spectrum frequency range designated to LoRa technology per region. This allows for several hundred possible frequency channels in the US region alone. ::: @@ -14,6 +16,10 @@ Meshtastic is **not** LoRaWAN, Helium or TTN (TheThingsNetwork). Meshtastic uses Power limits will generally be lifted in the software if `is_licensed` is set to `true`. See [HAM Mode](/docs/faq#amateur-radio-ham) for more information. ::: +## Channel Frequency Calculator + + + ## Europe Frequency Bands ### 433 MHz diff --git a/src/components/tools/FrequencyCalculator.tsx b/src/components/tools/FrequencyCalculator.tsx new file mode 100644 index 00000000..88f4efb8 --- /dev/null +++ b/src/components/tools/FrequencyCalculator.tsx @@ -0,0 +1,336 @@ +import React, { useEffect } from "react"; +import { Protobuf, Types } from "@meshtastic/meshtasticjs"; + +interface Region { + freq_start: number; + freq_end: number; + duty_cycle: number; + spacing: number; + power_limit: number; +} + +interface Modem { + bw: number; + cr: number; + sf: number; +} + +const RegionData = new Map([ + [ + Protobuf.Config_LoRaConfig_RegionCode.US, + { + freq_start: 902.0, + freq_end: 928.0, + duty_cycle: 100, + spacing: 0, + power_limit: 30, + }, + ], + [ + Protobuf.Config_LoRaConfig_RegionCode.EU_433, + { + freq_start: 433.0, + freq_end: 434.0, + duty_cycle: 10, + spacing: 0, + power_limit: 12, + }, + ], + [ + Protobuf.Config_LoRaConfig_RegionCode.EU_868, + { + freq_start: 869.4, + freq_end: 869.65, + duty_cycle: 10, + spacing: 0, + power_limit: 27, + }, + ], + [ + Protobuf.Config_LoRaConfig_RegionCode.CN, + { + freq_start: 470.0, + freq_end: 510.0, + duty_cycle: 100, + spacing: 0, + power_limit: 19, + }, + ], + [ + Protobuf.Config_LoRaConfig_RegionCode.JP, + { + freq_start: 920.8, + freq_end: 927.8, + duty_cycle: 100, + spacing: 0, + power_limit: 16, + }, + ], + [ + Protobuf.Config_LoRaConfig_RegionCode.ANZ, + { + freq_start: 915.0, + freq_end: 928.0, + duty_cycle: 100, + spacing: 0, + power_limit: 30, + }, + ], + [ + Protobuf.Config_LoRaConfig_RegionCode.RU, + { + freq_start: 868.7, + freq_end: 869.2, + duty_cycle: 100, + spacing: 0, + power_limit: 20, + }, + ], + [ + Protobuf.Config_LoRaConfig_RegionCode.KR, + { + freq_start: 920.0, + freq_end: 923.0, + duty_cycle: 100, + spacing: 0, + power_limit: 0, + }, + ], + [ + Protobuf.Config_LoRaConfig_RegionCode.TW, + { + freq_start: 920.0, + freq_end: 925.0, + duty_cycle: 100, + spacing: 0, + power_limit: 0, + }, + ], + [ + Protobuf.Config_LoRaConfig_RegionCode.IN, + { + freq_start: 865.0, + freq_end: 867.0, + duty_cycle: 100, + spacing: 0, + power_limit: 30, + }, + ], + [ + Protobuf.Config_LoRaConfig_RegionCode.NZ_865, + { + freq_start: 864.0, + freq_end: 868.0, + duty_cycle: 100, + spacing: 0, + power_limit: 36, + }, + ], + [ + Protobuf.Config_LoRaConfig_RegionCode.TH, + { + freq_start: 920.0, + freq_end: 925.0, + duty_cycle: 100, + spacing: 0, + power_limit: 16, + }, + ], + [ + Protobuf.Config_LoRaConfig_RegionCode.UA_433, + { + freq_start: 433.0, + freq_end: 434.7, + duty_cycle: 10, + spacing: 0, + power_limit: 10, + }, + ], + [ + Protobuf.Config_LoRaConfig_RegionCode.UA_868, + { + freq_start: 868.0, + freq_end: 868.6, + duty_cycle: 1, + spacing: 0, + power_limit: 14, + }, + ], + [ + Protobuf.Config_LoRaConfig_RegionCode.LORA_24, + { + freq_start: 2400.0, + freq_end: 2483.5, + duty_cycle: 100, + spacing: 0, + power_limit: 10, + }, + ], + [ + Protobuf.Config_LoRaConfig_RegionCode.UNSET, + { + freq_start: 902.0, + freq_end: 928.0, + duty_cycle: 100, + spacing: 0, + power_limit: 30, + }, + ], +]); + +const modemPresets = new Map([ + [ + Protobuf.Config_LoRaConfig_ModemPreset.SHORT_FAST, + { + bw: 250, + cr: 8, + sf: 7, + }, + ], + [ + Protobuf.Config_LoRaConfig_ModemPreset.SHORT_SLOW, + { + bw: 250, + cr: 8, + sf: 8, + }, + ], + [ + Protobuf.Config_LoRaConfig_ModemPreset.MEDIUM_FAST, + { + bw: 250, + cr: 8, + sf: 9, + }, + ], + [ + Protobuf.Config_LoRaConfig_ModemPreset.MEDIUM_SLOW, + { + bw: 250, + cr: 8, + sf: 10, + }, + ], + [ + Protobuf.Config_LoRaConfig_ModemPreset.LONG_FAST, + { + bw: 250, + cr: 8, + sf: 11, + }, + ], + [ + Protobuf.Config_LoRaConfig_ModemPreset.LONG_MODERATE, + { + bw: 125, + cr: 8, + sf: 11, + }, + ], + [ + Protobuf.Config_LoRaConfig_ModemPreset.LONG_SLOW, + { + bw: 125, + cr: 8, + sf: 12, + }, + ], + [ + Protobuf.Config_LoRaConfig_ModemPreset.VERY_LONG_SLOW, + { + bw: 62.5, + cr: 8, + sf: 12, + }, + ], +]); + +export const FrequencyCalculator = (): JSX.Element => { + const [modemPreset, setModemPreset] = + React.useState( + Protobuf.Config_LoRaConfig_ModemPreset.LONG_FAST, + ); + const [region, setRegion] = + React.useState( + Protobuf.Config_LoRaConfig_RegionCode.US, + ); + const [channel, setChannel] = React.useState( + Types.ChannelNumber.PRIMARY, + ); + const [numChannels, setNumChannels] = React.useState(0); + const [channelFrequency, setChannelFrequency] = React.useState(0); + + useEffect(() => { + const selectedRegion = RegionData.get(region); + const selectedModemPreset = modemPresets.get(modemPreset); + setNumChannels( + Math.floor( + (selectedRegion.freq_end - selectedRegion.freq_start) / + (selectedRegion.spacing + selectedModemPreset.bw / 1000), + ), + ); + setChannelFrequency( + selectedRegion.freq_start + + selectedModemPreset.bw / 2000 + + channel * (selectedModemPreset.bw / 1000), + ); + }, [modemPreset, region, channel]); + + return ( + + + Modem Preset: + + setModemPreset( + parseInt( + e.target.value, + ) as Protobuf.Config_LoRaConfig_ModemPreset, + ) + } + > + {Array.from(modemPresets.keys()).map((key) => ( + + {Protobuf.Config_LoRaConfig_ModemPreset[key]} + + ))} + + + + Region: + setRegion(parseInt(e.target.value))} + > + {Array.from(RegionData.keys()).map((key) => ( + + {Protobuf.Config_LoRaConfig_RegionCode[key]} + + ))} + + + + Channel: + setChannel(parseInt(e.target.value))} + > + {Array.from(Array(numChannels).keys()).map((key) => ( + + {key} + + ))} + + + + Number of channels: + + + + Channel Frequency: + + + + ); +};