kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
refactor: add channel hash function
rodzic
505ba8a7d3
commit
e9f63b4e80
|
@ -4,6 +4,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import com.geeksville.mesh.model.Channel
|
import com.geeksville.mesh.model.Channel
|
||||||
import com.geeksville.mesh.model.URL_PREFIX
|
import com.geeksville.mesh.model.URL_PREFIX
|
||||||
import com.geeksville.mesh.model.getChannelUrl
|
import com.geeksville.mesh.model.getChannelUrl
|
||||||
|
import com.geeksville.mesh.model.numChannels
|
||||||
import com.geeksville.mesh.model.toChannelSet
|
import com.geeksville.mesh.model.toChannelSet
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
@ -23,6 +24,20 @@ class ChannelTest {
|
||||||
Assert.assertEquals(channelUrl.toChannelSet(), ch)
|
Assert.assertEquals(channelUrl.toChannelSet(), ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun channelHashGood() {
|
||||||
|
val ch = Channel.default
|
||||||
|
|
||||||
|
Assert.assertEquals(8, ch.hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun numChannelsGood() {
|
||||||
|
val ch = Channel.default
|
||||||
|
|
||||||
|
Assert.assertEquals(104, ch.loraConfig.numChannels)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun channelNumGood() {
|
fun channelNumGood() {
|
||||||
val ch = Channel.default
|
val ch = Channel.default
|
||||||
|
|
|
@ -89,24 +89,13 @@ data class Channel(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hash a string into an integer using the djb2 algorithm by Dan Bernstein
|
* Given a channel name and psk, return the (0 to 255) hash for that channel
|
||||||
* http://www.cse.yorku.ca/~oz/hash.html
|
|
||||||
*/
|
*/
|
||||||
val hash: UInt // using UInt instead of Long to match RadioInterface.cpp results
|
val hash: Int get() = xorHash(name.toByteArray()) xor xorHash(psk.toByteArray())
|
||||||
get() {
|
|
||||||
var hash: UInt = 5381u
|
|
||||||
for (c in name) {
|
|
||||||
hash += (hash shl 5) + c.code.toUInt()
|
|
||||||
print("$c ${c.code} $hash ")
|
|
||||||
}
|
|
||||||
return hash
|
|
||||||
}
|
|
||||||
|
|
||||||
val channelNum: Int
|
val channelNum: Int get() = loraConfig.channelNum(name)
|
||||||
get() = if (loraConfig.channelNum != 0) loraConfig.channelNum
|
|
||||||
else (hash % RegionInfo.numChannels(loraConfig).toUInt()).toInt() + 1
|
|
||||||
|
|
||||||
val radioFreq: Float get() = RegionInfo.radioFreq(loraConfig, channelNum)
|
val radioFreq: Float get() = loraConfig.radioFreq(channelNum)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean = (other is Channel)
|
override fun equals(other: Any?): Boolean = (other is Channel)
|
||||||
&& psk.toByteArray() contentEquals other.psk.toByteArray()
|
&& psk.toByteArray() contentEquals other.psk.toByteArray()
|
||||||
|
|
|
@ -5,9 +5,29 @@ import com.geeksville.mesh.ConfigProtos.Config.LoRaConfig.ModemPreset
|
||||||
import com.geeksville.mesh.ConfigProtos.Config.LoRaConfig.RegionCode
|
import com.geeksville.mesh.ConfigProtos.Config.LoRaConfig.RegionCode
|
||||||
import com.geeksville.mesh.R
|
import com.geeksville.mesh.R
|
||||||
|
|
||||||
fun LoRaConfig.bandwidth() = if (usePreset) {
|
/**
|
||||||
|
* hash a string into an integer using the djb2 algorithm by Dan Bernstein
|
||||||
|
* http://www.cse.yorku.ca/~oz/hash.html
|
||||||
|
*/
|
||||||
|
private fun hash(name: String): UInt { // using UInt instead of Long to match RadioInterface.cpp results
|
||||||
|
var hash: UInt = 5381u
|
||||||
|
for (c in name) {
|
||||||
|
hash += (hash shl 5) + c.code.toUInt()
|
||||||
|
}
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
|
||||||
|
private val ModemPreset.bandwidth: Float
|
||||||
|
get() {
|
||||||
|
for (option in ChannelOption.entries) {
|
||||||
|
if (option.modemPreset == this) return option.bandwidth
|
||||||
|
}
|
||||||
|
return 0f
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun LoRaConfig.bandwidth() = if (usePreset) {
|
||||||
val wideLora = region == RegionCode.LORA_24
|
val wideLora = region == RegionCode.LORA_24
|
||||||
ChannelOption.bandwidth(modemPreset) * if (wideLora) 3.25f else 1f
|
modemPreset.bandwidth * if (wideLora) 3.25f else 1f
|
||||||
} else when (bandwidth) {
|
} else when (bandwidth) {
|
||||||
31 -> .03125f
|
31 -> .03125f
|
||||||
62 -> .0625f
|
62 -> .0625f
|
||||||
|
@ -18,6 +38,28 @@ fun LoRaConfig.bandwidth() = if (usePreset) {
|
||||||
else -> bandwidth / 1000f
|
else -> bandwidth / 1000f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val LoRaConfig.numChannels: Int get() {
|
||||||
|
for (option in RegionInfo.entries) {
|
||||||
|
if (option.regionCode == region)
|
||||||
|
return ((option.freqEnd - option.freqStart) / bandwidth()).toInt()
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun LoRaConfig.channelNum(primaryName: String): Int {
|
||||||
|
return if (channelNum != 0) channelNum
|
||||||
|
else (hash(primaryName) % numChannels.toUInt()).toInt() + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun LoRaConfig.radioFreq(channelNum: Int): Float {
|
||||||
|
if (overrideFrequency != 0f) return overrideFrequency + frequencyOffset
|
||||||
|
for (option in RegionInfo.entries) {
|
||||||
|
if (option.regionCode == region)
|
||||||
|
return (option.freqStart + bandwidth() / 2) + (channelNum - 1) * bandwidth()
|
||||||
|
}
|
||||||
|
return 0f
|
||||||
|
}
|
||||||
|
|
||||||
enum class RegionInfo(
|
enum class RegionInfo(
|
||||||
val regionCode: RegionCode,
|
val regionCode: RegionCode,
|
||||||
val freqStart: Float,
|
val freqStart: Float,
|
||||||
|
@ -38,26 +80,8 @@ enum class RegionInfo(
|
||||||
UA_433(RegionCode.UA_433, 433.0f, 434.7f),
|
UA_433(RegionCode.UA_433, 433.0f, 434.7f),
|
||||||
UA_868(RegionCode.UA_868, 868.0f, 868.6f),
|
UA_868(RegionCode.UA_868, 868.0f, 868.6f),
|
||||||
LORA_24(RegionCode.LORA_24, 2400.0f, 2483.5f),
|
LORA_24(RegionCode.LORA_24, 2400.0f, 2483.5f),
|
||||||
UNSET(RegionCode.UNSET, 902.0f, 928.0f);
|
UNSET(RegionCode.UNSET, 902.0f, 928.0f),
|
||||||
|
;
|
||||||
companion object {
|
|
||||||
fun numChannels(loraConfig: LoRaConfig): Int {
|
|
||||||
for (option in values()) {
|
|
||||||
if (option.regionCode == loraConfig.region)
|
|
||||||
return ((option.freqEnd - option.freqStart) / loraConfig.bandwidth()).toInt()
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fun radioFreq(loraConfig: LoRaConfig, channelNum: Int): Float = with(loraConfig) {
|
|
||||||
if (overrideFrequency != 0f) return overrideFrequency + frequencyOffset
|
|
||||||
for (option in values()) {
|
|
||||||
if (option.regionCode == region)
|
|
||||||
return (option.freqStart + bandwidth() / 2) + (channelNum - 1) * bandwidth()
|
|
||||||
}
|
|
||||||
return 0f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ChannelOption(
|
enum class ChannelOption(
|
||||||
|
@ -74,13 +98,4 @@ enum class ChannelOption(
|
||||||
LONG_SLOW(ModemPreset.LONG_SLOW, R.string.modem_config_slow_long, .125f),
|
LONG_SLOW(ModemPreset.LONG_SLOW, R.string.modem_config_slow_long, .125f),
|
||||||
VERY_LONG_SLOW(ModemPreset.VERY_LONG_SLOW, R.string.modem_config_very_long, .0625f),
|
VERY_LONG_SLOW(ModemPreset.VERY_LONG_SLOW, R.string.modem_config_very_long, .0625f),
|
||||||
;
|
;
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun bandwidth(modemPreset: ModemPreset?): Float {
|
|
||||||
for (option in values()) {
|
|
||||||
if (option.modemPreset == modemPreset) return option.bandwidth
|
|
||||||
}
|
|
||||||
return 0f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import com.geeksville.mesh.ChannelProtos.ChannelSettings
|
||||||
import com.geeksville.mesh.ConfigProtos.Config.LoRaConfig
|
import com.geeksville.mesh.ConfigProtos.Config.LoRaConfig
|
||||||
import com.geeksville.mesh.copy
|
import com.geeksville.mesh.copy
|
||||||
import com.geeksville.mesh.model.Channel
|
import com.geeksville.mesh.model.Channel
|
||||||
import com.geeksville.mesh.model.RegionInfo
|
import com.geeksville.mesh.model.numChannels
|
||||||
import com.geeksville.mesh.ui.components.DropDownPreference
|
import com.geeksville.mesh.ui.components.DropDownPreference
|
||||||
import com.geeksville.mesh.ui.components.EditListPreference
|
import com.geeksville.mesh.ui.components.EditListPreference
|
||||||
import com.geeksville.mesh.ui.components.EditTextPreference
|
import com.geeksville.mesh.ui.components.EditTextPreference
|
||||||
|
@ -136,7 +136,7 @@ fun LoRaConfigItemList(
|
||||||
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
|
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
|
||||||
onFocusChanged = { isFocused = it.isFocused },
|
onFocusChanged = { isFocused = it.isFocused },
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
if (it <= RegionInfo.numChannels(loraInput)) // max numChannels
|
if (it <= loraInput.numChannels) // total num of LoRa channels
|
||||||
loraInput = loraInput.copy { channelNum = it }
|
loraInput = loraInput.copy { channelNum = it }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue