mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
102 lines
4 KiB
Kotlin
102 lines
4 KiB
Kotlin
package com.geeksville.mesh.model
|
|
|
|
import com.geeksville.mesh.ChannelProtos
|
|
import com.geeksville.mesh.ConfigProtos.Config.LoRaConfig.ModemPreset
|
|
import com.geeksville.mesh.ConfigKt.loRaConfig
|
|
import com.geeksville.mesh.ConfigProtos
|
|
import com.geeksville.mesh.channelSettings
|
|
import com.google.protobuf.ByteString
|
|
import java.security.SecureRandom
|
|
|
|
/** Utility function to make it easy to declare byte arrays - FIXME move someplace better */
|
|
fun byteArrayOfInts(vararg ints: Int) = ByteArray(ints.size) { pos -> ints[pos].toByte() }
|
|
fun xorHash(b: ByteArray) = b.fold(0) { acc, x -> acc xor (x.toInt() and 0xff) }
|
|
|
|
data class Channel(
|
|
val settings: ChannelProtos.ChannelSettings = default.settings,
|
|
val loraConfig: ConfigProtos.Config.LoRaConfig = default.loraConfig,
|
|
) {
|
|
companion object {
|
|
// These bytes must match the well known and not secret bytes used the default channel AES128 key device code
|
|
private val channelDefaultKey = byteArrayOfInts(
|
|
0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59,
|
|
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0x01
|
|
)
|
|
|
|
private val cleartextPSK = ByteString.EMPTY
|
|
private val defaultPSK =
|
|
byteArrayOfInts(1) // a shortstring code to indicate we need our default PSK
|
|
|
|
// The default channel that devices ship with
|
|
val default = Channel(
|
|
channelSettings { psk = ByteString.copyFrom(defaultPSK) },
|
|
// references: NodeDB::installDefaultConfig / Channels::initDefaultChannel
|
|
loRaConfig {
|
|
usePreset = true
|
|
modemPreset = ModemPreset.LONG_FAST
|
|
hopLimit = 3
|
|
txEnabled = true
|
|
}
|
|
)
|
|
|
|
fun getRandomKey(size: Int = 32): ByteString {
|
|
val bytes = ByteArray(size)
|
|
val random = SecureRandom()
|
|
random.nextBytes(bytes)
|
|
return ByteString.copyFrom(bytes)
|
|
}
|
|
}
|
|
|
|
/// Return the name of our channel as a human readable string. If empty string, assume "Default" per mesh.proto spec
|
|
val name: String
|
|
get() = settings.name.ifEmpty {
|
|
// We have a new style 'empty' channel name. Use the same logic from the device to convert that to a human readable name
|
|
if (loraConfig.usePreset) when (loraConfig.modemPreset) {
|
|
ModemPreset.SHORT_FAST -> "ShortFast"
|
|
ModemPreset.SHORT_SLOW -> "ShortSlow"
|
|
ModemPreset.MEDIUM_FAST -> "MediumFast"
|
|
ModemPreset.MEDIUM_SLOW -> "MediumSlow"
|
|
ModemPreset.LONG_FAST -> "LongFast"
|
|
ModemPreset.LONG_SLOW -> "LongSlow"
|
|
ModemPreset.LONG_MODERATE -> "LongMod"
|
|
ModemPreset.VERY_LONG_SLOW -> "VLongSlow"
|
|
else -> "Invalid"
|
|
} else "Custom"
|
|
}
|
|
|
|
val psk: ByteString
|
|
get() = if (settings.psk.size() != 1)
|
|
settings.psk // A standard PSK
|
|
else {
|
|
// One of our special 1 byte PSKs, see mesh.proto for docs.
|
|
val pskIndex = settings.psk.byteAt(0).toInt()
|
|
|
|
if (pskIndex == 0)
|
|
cleartextPSK
|
|
else {
|
|
// Treat an index of 1 as the old channelDefaultKey and work up from there
|
|
val bytes = channelDefaultKey.clone()
|
|
bytes[bytes.size - 1] = (0xff and (bytes[bytes.size - 1] + pskIndex - 1)).toByte()
|
|
ByteString.copyFrom(bytes)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Given a channel name and psk, return the (0 to 255) hash for that channel
|
|
*/
|
|
val hash: Int get() = xorHash(name.toByteArray()) xor xorHash(psk.toByteArray())
|
|
|
|
val channelNum: Int get() = loraConfig.channelNum(name)
|
|
|
|
val radioFreq: Float get() = loraConfig.radioFreq(channelNum)
|
|
|
|
override fun equals(other: Any?): Boolean = (other is Channel)
|
|
&& psk.toByteArray() contentEquals other.psk.toByteArray()
|
|
&& name == other.name
|
|
|
|
override fun hashCode(): Int {
|
|
var result = settings.hashCode()
|
|
result = 31 * result + loraConfig.hashCode()
|
|
return result
|
|
}
|
|
}
|