import Foundation /// 设备命令服务:发送 JSON 命令(fire-and-forget,响应由协议层回调处理) final class DeviceInfoService { private let protocolService: BleProtocolService init(protocolService: BleProtocolService) { self.protocolService = protocolService } // MARK: - Commands func getDeviceInfo() throws { try protocolService.sendJSON( type: .getDeviceInfo, payload: CommandPayload(type: CommandType.getDeviceInfo.rawValue) ) } func getDeviceVersion() throws { try protocolService.sendJSON( type: .getDeviceVersion, payload: CommandPayload(type: CommandType.getDeviceVersion.rawValue) ) } func bindDevice(userId: String) throws { try protocolService.sendJSON( type: .bindDevice, payload: BindPayload(type: CommandType.bindDevice.rawValue, userId: userId, loop: nil) ) } func unbindDevice(userId: String) throws { try protocolService.sendJSON( type: .unbindDevice, payload: BindPayload(type: CommandType.unbindDevice.rawValue, userId: userId, loop: nil) ) } /// 切换播放模式(复用 BIND_DEVICE 命令字 0x0F,payload 携带 loop 字段) func setPlayMode(userId: String, loop: PlayMode) throws { try protocolService.sendJSON( type: .bindDevice, payload: BindPayload( type: CommandType.bindDevice.rawValue, userId: userId, loop: UInt8(loop.rawValue) ) ) } func deleteFile(key: String) throws { try protocolService.sendJSON( type: .deleteFile, payload: FileKeyPayload(type: CommandType.deleteFile.rawValue, key: key) ) } func prepareTransfer(key: String, size: Int) throws { try protocolService.sendJSON( type: .prepareTransfer, payload: PrepareTransferPayload( type: CommandType.prepareTransfer.rawValue, key: key, size: size ) ) } } // MARK: - Command Payloads private struct CommandPayload: Encodable { let type: UInt8 } /// 绑定 / 解绑 / 切模式 共用 payload。 /// `loop == nil` 时严格省略该字段(不写 null),与 Expo 端 zod.optional 行为对齐。 struct BindPayload: Encodable { let type: UInt8 let userId: String let loop: UInt8? enum CodingKeys: String, CodingKey { case type, userId, loop } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(type, forKey: .type) try container.encode(userId, forKey: .userId) if let loop = loop { try container.encode(loop, forKey: .loop) } } } private struct FileKeyPayload: Encodable { let type: UInt8 let key: String } private struct PrepareTransferPayload: Encodable { let type: UInt8 let key: String let size: Int }