import 'dart:typed_data'; import '../connector/meshcore_protocol.dart'; class Channel { final int index; final String name; final Uint8List psk; // 16 bytes Channel({ required this.index, required this.name, required this.psk, }); String get pskHex => _bytesToHex(psk); bool get isEmpty => name.isEmpty && psk.every((b) => b == 0); bool get isPublicChannel => pskHex == publicChannelPsk; static Channel? fromFrame(Uint8List data) { // CHANNEL_INFO format: // [0] = RESP_CODE_CHANNEL_INFO (18) // [1] = channel_idx // [2-33] = name (32 bytes, null-terminated) // [34-49] = psk (16 bytes) if (data.length < 50) return null; if (data[0] != respCodeChannelInfo) return null; final index = data[1]; final name = readCString(data, 2, 32); final psk = Uint8List.fromList(data.sublist(34, 50)); return Channel(index: index, name: name, psk: psk); } static Channel empty(int index) { return Channel( index: index, name: '', psk: Uint8List(16), ); } static Channel fromHex(int index, String name, String pskHex) { final psk = parsePskHex(pskHex); return Channel(index: index, name: name, psk: psk); } static Uint8List parsePskHex(String hex) { final cleaned = hex.replaceAll(RegExp(r'[^0-9a-fA-F]'), ''); if (cleaned.length != 32) { throw const FormatException('PSK must be 32 hex characters'); } final bytes = Uint8List(16); for (int i = 0; i < 16; i++) { final start = i * 2; bytes[i] = int.parse(cleaned.substring(start, start + 2), radix: 16); } return bytes; } static String formatPskHex(Uint8List psk) { return _bytesToHex(psk); } static String _bytesToHex(Uint8List bytes) { return bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join(); } static const String publicChannelPsk = '8b3387e9c5cdea6ac9e5edbaa115cd72'; }