Meshtastic-Android/app/src/main/java/com/geeksville/mesh/model/Channel.kt
2021-02-27 13:43:55 +08:00

91 lines
3.7 KiB
Kotlin

package com.geeksville.mesh.model
import android.graphics.Bitmap
import android.net.Uri
import android.util.Base64
import com.geeksville.mesh.ChannelProtos
import com.geeksville.mesh.MeshProtos
import com.google.protobuf.ByteString
import com.google.zxing.BarcodeFormat
import com.google.zxing.MultiFormatWriter
import com.journeyapps.barcodescanner.BarcodeEncoder
import java.net.MalformedURLException
/** 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() }
data class Channel(
val settings: ChannelProtos.ChannelSettings = ChannelProtos.ChannelSettings.getDefaultInstance()
) {
companion object {
// Note: this string _SHOULD NOT BE LOCALIZED_ because it directly hashes to values used on the device for the default channel name.
// FIXME - make this work with new channel name system
const val defaultChannelName = "Default"
// These bytes must match the well known and not secret bytes used the default channel AES128 key device code
val channelDefaultKey = byteArrayOfInts(
0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59,
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf
)
// Placeholder when emulating
val emulated = Channel(
ChannelProtos.ChannelSettings.newBuilder().setName(defaultChannelName)
.setModemConfig(ChannelProtos.ChannelSettings.ModemConfig.Bw125Cr45Sf128).build()
)
}
/// Return the name of our channel as a human readable string. If empty string, assume "Default" per mesh.proto spec
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) {
ChannelProtos.ChannelSettings.ModemConfig.Bw125Cr45Sf128 -> "Medium"
ChannelProtos.ChannelSettings.ModemConfig.Bw500Cr45Sf128 -> "ShortFast"
ChannelProtos.ChannelSettings.ModemConfig.Bw31_25Cr48Sf512 -> "LongAlt"
ChannelProtos.ChannelSettings.ModemConfig.Bw125Cr48Sf4096 -> "LongSlow"
else -> "Invalid"
}
} else
settings.name
val modemConfig: ChannelProtos.ChannelSettings.ModemConfig get() = settings.modemConfig
val psk
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)
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)
}
}
/**
* Return a name that is formatted as #channename-suffix
*
* Where suffix indicates the hash of the PSK
*/
val humanName: String
get() {
val suffix: Char = if (settings.psk.size() != 1) {
// we have a full PSK, so hash it to generate the suffix
val code = settings.psk.fold(0, { acc, x -> acc xor (x.toInt() and 0xff) })
'A' + (code % 26)
} else
'0' + settings.psk.byteAt(0).toInt()
return "#${name}-${suffix}"
}
}