2020-03-24 13:48:22 -07:00
|
|
|
package com.geeksville.mesh.model
|
|
|
|
|
|
2021-02-27 13:43:55 +08:00
|
|
|
import com.geeksville.mesh.ChannelProtos
|
2020-12-14 21:30:00 +08:00
|
|
|
import com.google.protobuf.ByteString
|
2020-03-24 13:48:22 -07:00
|
|
|
|
2020-06-12 20:38:43 -07:00
|
|
|
/** 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() }
|
|
|
|
|
|
2020-03-24 13:48:22 -07:00
|
|
|
|
|
|
|
|
data class Channel(
|
2021-02-27 13:43:55 +08:00
|
|
|
val settings: ChannelProtos.ChannelSettings = ChannelProtos.ChannelSettings.getDefaultInstance()
|
2020-03-24 13:48:22 -07:00
|
|
|
) {
|
|
|
|
|
companion object {
|
2020-08-10 21:20:55 -04:00
|
|
|
// These bytes must match the well known and not secret bytes used the default channel AES128 key device code
|
2020-06-12 20:38:43 -07:00
|
|
|
val channelDefaultKey = byteArrayOfInts(
|
|
|
|
|
0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59,
|
|
|
|
|
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf
|
|
|
|
|
)
|
|
|
|
|
|
2021-03-19 17:09:35 +08:00
|
|
|
// TH=he unsecured channel that devices ship with
|
|
|
|
|
val defaultChannel = Channel(
|
|
|
|
|
ChannelProtos.ChannelSettings.newBuilder()
|
2021-02-27 13:43:55 +08:00
|
|
|
.setModemConfig(ChannelProtos.ChannelSettings.ModemConfig.Bw125Cr45Sf128).build()
|
2020-03-24 13:48:22 -07:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 21:30:00 +08:00
|
|
|
/// Return the name of our channel as a human readable string. If empty string, assume "Default" per mesh.proto spec
|
2021-01-05 12:35:41 +08:00
|
|
|
val name: String
|
|
|
|
|
get() = if (settings.name.isEmpty()) {
|
|
|
|
|
// We have a new style 'empty' channel name. Use the same logic from the device to convert that to a human readable name
|
|
|
|
|
if (settings.bandwidth != 0)
|
|
|
|
|
"Unset"
|
|
|
|
|
else when (settings.modemConfig) {
|
2021-02-27 13:43:55 +08:00
|
|
|
ChannelProtos.ChannelSettings.ModemConfig.Bw125Cr45Sf128 -> "Medium"
|
|
|
|
|
ChannelProtos.ChannelSettings.ModemConfig.Bw500Cr45Sf128 -> "ShortFast"
|
|
|
|
|
ChannelProtos.ChannelSettings.ModemConfig.Bw31_25Cr48Sf512 -> "LongAlt"
|
|
|
|
|
ChannelProtos.ChannelSettings.ModemConfig.Bw125Cr48Sf4096 -> "LongSlow"
|
2021-01-05 12:35:41 +08:00
|
|
|
else -> "Invalid"
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
settings.name
|
2020-04-09 16:33:42 -07:00
|
|
|
|
2021-02-27 13:43:55 +08:00
|
|
|
val modemConfig: ChannelProtos.ChannelSettings.ModemConfig get() = settings.modemConfig
|
2020-12-14 21:30:00 +08:00
|
|
|
|
2021-01-05 12:35:41 +08:00
|
|
|
val psk
|
|
|
|
|
get() = if (settings.psk.size() != 1)
|
|
|
|
|
settings.psk // A standard PSK
|
2020-12-14 21:30:00 +08:00
|
|
|
else {
|
2021-01-05 12:35:41 +08:00
|
|
|
// One of our special 1 byte PSKs, see mesh.proto for docs.
|
|
|
|
|
val pskIndex = settings.psk.byteAt(0).toInt()
|
|
|
|
|
|
|
|
|
|
if (pskIndex == 0)
|
|
|
|
|
ByteString.EMPTY // Treat as an empty PSK (no encryption)
|
|
|
|
|
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)
|
|
|
|
|
}
|
2020-12-14 21:30:00 +08:00
|
|
|
}
|
|
|
|
|
|
2020-08-12 12:31:37 -07:00
|
|
|
/**
|
|
|
|
|
* Return a name that is formatted as #channename-suffix
|
|
|
|
|
*
|
|
|
|
|
* Where suffix indicates the hash of the PSK
|
|
|
|
|
*/
|
|
|
|
|
val humanName: String
|
|
|
|
|
get() {
|
2021-03-19 17:42:26 +08:00
|
|
|
// start with the PSK then xor in the name
|
|
|
|
|
val pskCode = xorHash(psk.toByteArray())
|
|
|
|
|
val nameCode = xorHash(name.toByteArray())
|
|
|
|
|
val suffix = 'A' + ((pskCode xor nameCode) % 26)
|
2021-01-05 12:35:41 +08:00
|
|
|
|
|
|
|
|
return "#${name}-${suffix}"
|
2020-08-12 12:31:37 -07:00
|
|
|
}
|
2020-03-24 13:48:22 -07:00
|
|
|
}
|
2021-03-19 17:42:26 +08:00
|
|
|
|
|
|
|
|
fun xorHash(b: ByteArray) = b.fold(0, { acc, x -> acc xor (x.toInt() and 0xff) })
|