Restrições Principais e Estratégia de Adaptação
O código original em C# depende de DLLs nativas do Windows (como proRFLV102024.dll) para interação com hardware (leitura de cartões, emissão, campainha), enquanto o HarmonyOS (especialmente em dispositivos) não pode chamar diretamente DLLs do Windows. A interação com hardware no HarmonyOS deve ser realizada através de APIs de acesso a hardware do HarmonyOS (como USB, drivers de periféricos) ou de um SDK adaptado para HarmonyOS fornecido pelo fabricante.
A estratégia de conversão é dividida em duas partes:
- Preservar a lógica de negócio principal (análise de protocolo, lógica de emissão/cancelamento de cartões, registro de logs) implementando-a em ArkTS (a principal linguagem de desenvolvimento do HarmonyOS);
- Para a interação com hardware, fornecer um esquema de adaptação de acesso a hardware para dispositivos HarmonyOS (marcando onde a lógica de chamada da DLL original deve ser substituída).
Preparação do Ambiente de Desenvolvimento HarmonyOS
- Instale o DevEco Studio (IDE oficial do HarmonyOS);
- Crie um projeto HarmonyOS (selecione o modelo Stage, baseado em ArkTS);
- Se envolver interação com hardware, configure as permissões de hardware do dispositivo (como permissões de USB, acesso a periféricos).
Exemplos de Código em ArkTS para Dispositivos/Servidores HarmonyOS
O código abaixo é dividido em classes de lógica de negócio principal e entrada de UI/serviço HarmonyOS, mantendo a lógica central de emissão de cartões para check-in, cancelamento para check-out e leitura de cartões, adaptando-se à sintaxe e APIs do HarmonyOS.
1. Classe Utilitária: Análise de Protocolo e Registro de Logs (ProtocolUtils.ets)
/**
* Classe para análise de protocolos, similar à classe original CyberWinAPPProtocolPackage
* Adaptada para o HarmonyOS
*/
export class ProtocolAnalyzer {
private parsedData: Map<string, string> = new Map();
/**
* Analisa uma string de parâmetros (lógica simulada, expansível conforme o protocolo real)
* @param params String de parâmetros, formato como "hotelsign=123&lockno=456789"
*/
parse(params: string): void {
// Usar URLSearchParams para simplificar a análise no HarmonyOS
const searchParams = new URLSearchParams(params);
searchParams.forEach((value, key) => {
this.parsedData.set(key, value);
});
}
/**
* Obtém um parâmetro analisado
* @param key Nome do parâmetro
* @returns Valor do parâmetro (string vazia se inexistente)
*/
getValue(key: string): string {
return this.parsedData.get(key) || '';
}
}
/**
* Classe utilitária para logs, adaptada à API de sistema de arquivos do HarmonyOS
*/
export class LoggerService {
/**
* Escreve uma entrada de log (equivalente ao método write_log original)
* @param category Categoria do log
* @param logType Tipo do log
* @param message Conteúdo do log
*/
public static async recordLog(category: string, logType: string, message: string): Promise<void> {
try {
// Obter caminho do sandbox do aplicativo no HarmonyOS (requer permissão de arquivo: ohos.permission.WRITE_USER_STORAGE)
const appContext = getContext(this);
const logDirectory = `${appContext.filesDir}/logs/${category}/${new Date().toISOString().split('T')[0]}`;
// Criar diretório usando a API fileio do HarmonyOS
const fileio = require('@ohos.fileio');
if (!fileio.accessSync(logDirectory)) {
fileio.mkdirSync(logDirectory, { recursive: true });
}
// Caminho do arquivo de log
const logFilePath = `${logDirectory}/${logType}.log`;
// Escrever log (modo de anexação)
const logEntry = `=== Registro ===\n${new Date().toLocaleString()} - INÍCIO\n${message}\n\n`;
fileio.writeFileSync(logFilePath, logEntry, { flag: 'a', encoding: 'utf-8' });
} catch (error) {
console.error(`Falha ao escrever log: ${error}`);
}
}
}
/**
* Classe para análise de dados do cartão, similar à CyberWin_LocakAPP original
*/
export class CartaoDataParser {
/**
* Analisa o identificador do hotel a partir dos dados do cartão
* @param cardBuffer Dados do cartão em Uint8Array
* @returns Identificador do hotel ou mensagem de aviso
*/
public static extractHotelId(cardBuffer: Uint8Array): string {
// Converter para string ASCII (equivalente a Encoding.ASCII.GetString original)
const cardString = new TextDecoder('ascii').decode(cardBuffer);
// Verificar se é um cartão em branco
if (this.extractSubstring(cardBuffer, 25, 8) === 'FFFFFFFF') {
console.log('Este cartão está em branco, use um cartão que abra a porta');
return 'Cartão em branco';
}
// Analisar identificador do hotel (lógica original mantida)
const segment1 = this.extractSubstring(cardBuffer, 11, 4);
let value1 = parseInt(segment1, 16) % 16384;
const segment2 = this.extractSubstring(cardBuffer, 9, 2);
value1 = value1 + (parseInt(segment2, 16) * 65536);
const finalValue = parseInt(this.extractSubstring(cardBuffer, 9, 2), 16) * 65536 + parseInt(this.extractSubstring(cardBuffer, 11, 4), 16) % 16383;
return finalValue.toString();
}
/**
* Extrai uma substring de um buffer de dados (equivalente ao método Copy original)
* @param buffer Buffer de dados
* @param startPosition Posição inicial (começando em 1)
* @param length Comprimento da substring
* @returns Substring extraída
*/
private static extractSubstring(buffer: Uint8Array, startPosition: number, length: number): string {
const bufferString = new TextDecoder('ascii').decode(buffer);
const adjustedStart = startPosition < 1 ? 1 : startPosition;
return bufferString.substring(adjustedStart - 1, adjustedStart - 1 + length);
}
}
2. Classe de Negócio Princiapl: Controle de Fechadura de Hotel (LockManager.ets)
import { ProtocolAnalyzer, LoggerService, CartaoDataParser } from './ProtocolUtils';
/**
* Classe de negócio principal para fechadura de hotel (equivalente à classe APP original)
* No HarmonyOS, pode-se usar o padrão Singleton (opcional)
*/
export class LockManager {
private static instance: LockManager;
private cardDataBuffer: Uint8Array = new Uint8Array(128); // Equivalente a byte[128]
private idPhotoPath: string = '';
public static readBuffer: Uint8Array = new Uint8Array(128 + 1); // Buffer de leitura de cartão
public static v10ReadBuffer: Uint8Array = new Uint8Array(200 + 1); // Buffer para leitura V10
public static operationStatus: number = 0; // Código de status
// Padrão Singleton (comum no HarmonyOS)
public static getInstance(): LockManager {
if (!this.instance) {
this.instance = new LockManager();
}
return this.instance;
}
// -------------------------- Adaptação de Interação com Hardware (substituindo chamadas DLL) --------------------------
/**
* Inicializa o dispositivo USB (equivalente a initializeUSB original, precisa ser substituído pela API USB do HarmonyOS)
* @param deviceType 0=USB com driver, 1=proUSB
* @returns 0=sucesso, outro=falha
*/
private initializeUsbDevice(deviceType: number): number {
// 【Adaptação de Hardware HarmonyOS】Substituir pela lógica de inicialização de dispositivo USB do HarmonyOS
// Referência: https://developer.harmonyos.com/cn/docs/documentation/doc-references/usb_device-0000001524415869
// Exemplo: obter lista de dispositivos USB, abrir dispositivo específico
try {
// Simular retorno de sucesso; na prática, integrar com SDK de hardware
return 0;
} catch (e) {
return -1;
}
}
/**
* Controle da campainha (equivalente a Buzzer original, precisa ser substituído por API de periféricos)
* @param deviceHandle Identificador do dispositivo
* @param duration Duração em ms
* @returns 0=sucesso, outro=falha
*/
private activateBuzzer(deviceHandle: number, duration: number): number {
// 【Adaptação de Hardware HarmonyOS】Substituir pela lógica de controle de campainha (via API GPIO se suportado)
console.log(`Campainha ativada por ${duration}ms`);
return 0;
}
/**
* Cancela um cartão (equivalente a CardErase original, precisa ser substituído por SDK de hardware)
* @param deviceHandle Identificador do dispositivo
* @param hotelId Identificador do hotel
* @param cardNumber Número do cartão (buffer)
* @returns 0=sucesso, outro=falha
*/
private eraseCardData(deviceHandle: number, hotelId: number, cardNumber: string): number {
// 【Adaptação de Hardware HarmonyOS】Substituir pela lógica de cancelamento de cartão (chamada ao SDK de hardware)
try {
// Simular retorno de sucesso
return 0;
} catch (e) {
return -1;
}
}
/**
* Emite um cartão (equivalente a GuestCard_原始 original, precisa ser substituído por SDK de hardware)
* @param issuanceParams Parâmetros de emissão
* @returns 0=sucesso, outro=falha
*/
private issueGuestCard(issuanceParams: {
deviceHandle: number,
hotelId: number,
cardIndex: number,
roomType: number,
lockFlag: number,
doorAccess: number,
validFrom: string,
validUntil: string,
lockIdentifier: string,
cardPayload: string
}): number {
// 【Adaptação de Hardware HarmonyOS】Substituir pela lógica de emissão de cartão (chamada ao SDK de hardware)
try {
// Simular retorno de sucesso
return 0;
} catch (e) {
return -1;
}
}
/**
* Lê um cartão V10 (equivalente a rdCard_v10 original, precisa ser substituído por SDK de hardware)
* @returns true=sucesso, false=falha
*/
private performV10CardRead(): boolean {
// 【Adaptação de Hardware HarmonyOS】Substituir pela lógica de leitura de cartão (chamada ao SDK de hardware)
try {
// Simular leitura bem-sucedida, preencher buffer
LockManager.v10ReadBuffer = new Uint8Array(201).fill(0x30); // Dados simulados
LockManager.operationStatus = 0;
return true;
} catch (e) {
LockManager.operationStatus = -1;
console.error(`Falha na leitura do cartão: ${e}`);
return false;
}
}
// -------------------------- Implementação dos Métodos de Negócio Originais --------------------------
/**
* Método de inicialização (equivalente a start)
* @param params Conjunto de parâmetros
* @returns String de resultado
*/
initialize(params: Record<string, string>): string {
const configValue = params['config'] || '';
return 'Plugin pré-instalado aleatório';
}
/**
* Verificação de status do dispositivo (equivalente a status)
* @param params Conjunto de parâmetros
* @returns String de resultado
*/
checkDeviceStatus(params: Record<string, string>): string {
this.activateBuzzer(1, 50); // Controlar campainha
return 'Quando a campainha do dispositivo soar, indica que ele está conectado';
}
/**
* Processo de check-out com cancelamento de cartão (equivalente a checkingout)
* @param params Conjunto de parâmetros
* @returns String de resultado
*/
processCheckout(params: Record<string, string>): string {
let outcome = 'Cancelamento de cartão';
const queryParams = params['params'] || '';
// Analisar parâmetros do protocolo
const analyzer = new ProtocolAnalyzer();
analyzer.parse(queryParams);
const hotelSign = analyzer.getValue('hotelsign');
if (!hotelSign) {
return `${outcome}: Identificador do hotel vazio`;
}
// Inicializar dispositivo USB
const usbInitStatus = this.initializeUsbDevice(1);
if (usbInitStatus !== 0) {
console.log('Falha ao abrir dispositivo');
return 'Falha ao abrir porta';
}
// Chamar função de cancelamento de cartão
const simulatedCardNo = '';
const operationResult = this.eraseCardData(1, parseInt(hotelSign), simulatedCardNo);
if (operationResult !== 0) {
outcome += `: Falha no cancelamento ${operationResult}`;
} else {
outcome += ': Sucesso';
}
// Registrar log
LoggerService.recordLog('hotel', 'checkout', outcome);
return outcome;
}
/**
* Processo de check-in com emissão de cartão (equivalente a checkingin)
* @param params Conjunto de parâmetros
* @returns String de resultado
*/
processCheckin(params: Record<string, string>): string {
let outcome = 'Emissão de cartão para check-in';
const queryParams = params['params'] || '';
// Analisar parâmetros do protocolo
const analyzer = new ProtocolAnalyzer();
analyzer.parse(queryParams);
const lockNumber = analyzer.getValue('lockno');
const hotelSign = analyzer.getValue('hotelsign');
const checkoutTime = analyzer.getValue('checkingouttime');
// Validar comprimento do número da fechadura
if (lockNumber.length < 6) {
LoggerService.recordLog('hotel', 'checkin', `Comprimento do número da fechadura inválido=${lockNumber}`);
return `${outcome}: Comprimento do número da fechadura inválido`;
}
// Inicializar dispositivo USB
const usbInitStatus = this.initializeUsbDevice(1);
if (usbInitStatus !== 0) {
console.log('Falha ao abrir dispositivo');
return 'Falha ao abrir porta';
}
// Construir parâmetros de emissão
const accessStartTime = new Date().toISOString().replace(/[^0-9]/g, '').substring(0, 14); // Formato: aaaammddHHmmss
const lockFlagValue = 1; // Sinalizador de trancamento
const roomTypeValue = 1; // Identificador do tipo de quarto
// Chamar função de emissão de cartão
const issuanceResult = this.issueGuestCard({
deviceHandle: 1,
hotelId: parseInt(hotelSign),
cardIndex: 0,
roomType: roomTypeValue,
lockFlag: lockFlagValue,
doorAccess: 0,
validFrom: accessStartTime,
validUntil: checkoutTime,
lockIdentifier: lockNumber,
cardPayload: ''
});
if (issuanceResult !== 0) {
outcome += ' Falha na emissão do cartão';
} else {
outcome += ` Cartão emitido com sucesso V2024 ${lockNumber}`;
}
// Registrar log
LoggerService.recordLog('hotel', 'checkin', outcome);
return outcome;
}
/**
* Lê o identificador do hotel (equivalente a getsign)
* @param params Conjunto de parâmetros
* @returns Identificador do hotel ou mensagem de aviso
*/
retrieveHotelId(params: Record<string, string>): string {
// Ler cartão
if (!this.performV10CardRead()) {
LoggerService.recordLog('hotel', 'getsign', 'Falha na leitura do cartão');
return 'Falha na leitura do cartão';
}
// Analisar identificador do hotel
const hotelId = CartaoDataParser.extractHotelId(LockManager.v10ReadBuffer);
LoggerService.recordLog('hotel', 'getsign', `Identificador do hotel: ${hotelId}`);
return hotelId;
}
}
3. Página de Interface do Usuário HarmonyOS: Exemplo de Chamada (MainPage.ets)
import { LockManager } from './LockManager';
@Entry
@Component
struct HotelLockControlPage {
private lockController = LockManager.getInstance();
@State displayResult: string = '';
build() {
Column() {
Text('Controle de Fechadura de Hotel')
.fontSize(30)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 20 });
// Botão para verificar status do dispositivo
Button('Verificar Status do Dispositivo')
.onClick(() => {
this.displayResult = this.lockController.checkDeviceStatus({});
})
.margin({ bottom: 10 });
// Botão para cancelamento no check-out
Button('Cancelar Cartão no Check-out')
.onClick(() => {
// Parâmetros simulados: hotelsign=123456
this.displayResult = this.lockController.processCheckout({ params: 'hotelsign=123456' });
})
.margin({ bottom: 10 });
// Botão para emissão no check-in
Button('Emitir Cartão no Check-in')
.onClick(() => {
// Parâmetros simulados: hotelsign=123456&lockno=123456&checkingouttime=2501010000
this.displayResult = this.lockController.processCheckin({
params: 'hotelsign=123456&lockno=123456&checkingouttime=2501010000'
});
})
.margin({ bottom: 10 });
// Botão para ler identificador do hotel
Button('Ler Identificador do Hotel')
.onClick(() => {
this.displayResult = this.lockController.retrieveHotelId({});
})
.margin({ bottom: 10 });
// Exibição do resultado
Text(this.displayResult)
.fontSize(16)
.margin({ top: 20 })
.textAlign(TextAlign.Center);
}
.width('100%')
.height('100%')
.padding(20)
.justifyContent(FlexAlign.Center);
}
}
Pontos-Chave Explicados
- Adaptação de Interação com Hardware: As chamadas DLL originais em C# foram substituídas por uma camada de adaptação de APIs de hardware do HarmonyOS, indicando onde a lógica de inicialização USB, controle de campainha e operações de cartão deve ser implementada usando as APIs HarmonyOS ou SDKs de hardware de terceiros.
- Preservação da Lógica de Negócio: A análise de protocolo, validação de parâmetros, lógica de emissão/cancelamento e reigstro de logs foram mantidas integralmente, adaptadas apanas à sintaxe do ArkTS e às APIs do HarmonyOS (como
fileiopara logs,TextDecoderpara codificação de caracteres). - Adaptação a Características do HarmonyOS: Utilização do padrão Singleton, UI declarativa com decoradores
@Entrye@Component, e separação clara entre lógica de negócios e interface.
Complemento sobre Interação com Hardware no HarmonyOS
Para implementar interação real com hardware (leitura/emissão de cartões) em dispositivos HarmonyOS, é necessário:
- Solicitar permissões de hardware: Configurar permissões como
ohos.permission.USB_DEVICEno arquivomodule.json5; - Integrar com SDK de hardware: Contatar o fabricante para obter o SDK de fechadura de hotel compatível com HarmonyOS (substituindo a DLL original do Windows);
- Utilizar APIs de hardware do HarmonyOS: Consultar a documentação oficial do HarmonyOS sobre desenvolvimento de dispositivos USB e desenvolvimento de GPIO.