幽冥大陆(三十六)S18酒店门锁SDK rust语言——东方仙盟筑基期

代码

复制代码
use std::collections::HashMap;
use std::ffi::{CString, CStr};
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::ptr;
use std::time::{SystemTime, UNIX_EPOCH};
use chrono::{Local, DateTime, TimeZone};
use winapi::um::winuser::{MessageBoxA, MB_OK, MB_ICONERROR, MB_ICONINFORMATION};
use libc::{c_char, c_int, c_uint, c_uchar, size_t};

// 定义DLL函数绑定
#[link(name = "proRFLV102024", kind = "dylib")]
extern "stdcall" {
    // proRFLV102024.dll
    fn GetDLLVersion(sDllVer: *mut c_char) -> c_int;
    fn CloseUSB();
    fn Buzzer(fUSB: c_uchar, t: c_int) -> c_int;
    fn ReadCard(fUSB: c_uchar, Buffer: *mut c_uchar) -> c_int;
    #[link_name = "ReadCard"]
    fn ReadCard_v10(fUSB: c_uchar, Buffer: *mut c_uchar) -> c_int;
    fn ReadCardID_T5557(fUSB: c_uchar, Buffer: *mut c_uchar) -> c_int;
    fn GuestCard(
        fUSB: c_uchar,
        dlsCoID: c_int,
        CardNo: c_uchar,
        dai: c_uchar,
        llock: c_uchar,
        pdoors: c_uchar,
        BDate: *const c_char,
        EDate: *const c_char,
        RoomNo: *const c_char,
        CardHexStr: *mut c_uchar,
    ) -> c_int;
    #[link_name = "GuestCard"]
    fn GuestCard_原始(
        d12: c_int,
        dlsCoID: c_int,
        CardNo: c_int,
        dai: c_int,
        LLock: c_int,
        pdoors: c_int,
        BDate: *const c_char,
        EDate: *const c_char,
        RoomNo: *const c_char,
        cardHexStr: *mut c_char,
    ) -> c_int;
    fn LimitCard(
        fUSB: c_uchar,
        dlsCoID: c_int,
        CardNo: c_uchar,
        dai: c_uchar,
        BDate: *const c_char,
        LCardNo: *const c_char,
        CardHexStr: *const c_char,
    ) -> c_int;
    fn CardErase(fUSB: c_uchar, dlsCoID: c_int, cardHexStr: *mut c_uchar) -> c_int;
    #[link_name = "CardErase"]
    fn CardErase_V10(d12: c_int, dlsCoID: c_int, CardNo: *mut c_char) -> c_int;
    fn hex_a(hex: *const c_char, asc: *mut c_char, hLen: c_int) -> c_int;
    fn a_hex(asc: *const c_char, hex: *mut c_char, aLen: c_int) -> c_int;
    fn GetCardTypeByCardDataStr(cardHexStr: *const c_char, CardType: *mut c_char) -> c_int;
    fn GetGuestLockNoByCardDataStr(dlsCoID: c_int, cardHexStr: *const c_char, LockNo: *mut c_char) -> c_int;
    fn GetGuestETimeByCardDataStr(dlsCoID: c_int, cardHexStr: *mut c_uchar, eTime: *mut c_uchar) -> c_int;
    fn ReadRecord(fUSB: c_uchar, bufData: *mut c_char) -> c_int;
    fn GetOpenRecordByDataStr(DataStr: *const c_char, sOpen: *mut c_char) -> c_int;
}

#[link(name = "proRFLP50202501", kind = "dylib")]
extern "stdcall" {
    // proRFLP50202501.dll
    #[link_name = "GetDLLVersion"]
    fn GetDLLVersion_P50(sDllVer: *mut c_char) -> c_int;
    #[link_name = "initializeUSB"]
    fn initializeUSB_P50(d12: c_int) -> c_int;
    #[link_name = "CloseUSB"]
    fn CloseUSB_P50(d12: c_int);
    #[link_name = "Buzzer"]
    fn Buzzer_P50(fUSB: c_uchar, t: c_int) -> c_int;
    #[link_name = "CardErase"]
    fn CardErase_P50(d12: c_int, dlsCoID: c_int, CardNo: *mut c_char) -> c_int;
    #[link_name = "GuestCard"]
    fn GuestCard_P50(
        fUSB: c_uchar,
        dlsCoID: c_int,
        CardNo: c_uchar,
        dai: c_uchar,
        llock: c_uchar,
        pdoors: c_uchar,
        BDate: *const c_char,
        EDate: *const c_char,
        RoomNo: *const c_char,
        CardHexStr: *mut c_uchar,
    ) -> c_int;
    #[link_name = "GuestCard"]
    fn GuestCard_原始_P50(
        d12: c_int,
        dlsCoID: c_int,
        CardNo: c_int,
        dai: c_int,
        LLock: c_int,
        pdoors: c_int,
        BDate: *const c_char,
        EDate: *const c_char,
        RoomNo: *const c_char,
        cardHexStr: *mut c_char,
    ) -> c_int;
    #[link_name = "GetGuestLockNoByCardDataStr"]
    fn GetGuestLockNoByCardDataStr_P50(dlsCoID: c_int, cardHexStr: *const c_char, LockNo: *mut c_char) -> c_int;
}

// 全局常量
const BUF_CARD_SIZE: usize = 129;    // 128 + 1
const BUF_CARD_V10_SIZE: usize = 201; // 200 + 1

// 全局变量(使用Mutex保证线程安全)
lazy_static::lazy_static! {
    static ref CARD_DATA: std::sync::Mutex<[u8; 128]> = std::sync::Mutex::new([0u8; 128]);
    static ref ID_PHOTO_SAVE_PATH: std::sync::Mutex<String> = std::sync::Mutex::new(String::new());
    static ref BUF_CARD: std::sync::Mutex<[u8; BUF_CARD_SIZE]> = std::sync::Mutex::new([0u8; BUF_CARD_SIZE]);
    static ref BUF_CARD_V10: std::sync::Mutex<[u8; BUF_CARD_V10_SIZE]> = std::sync::Mutex::new([0u8; BUF_CARD_V10_SIZE]);
}

// 模拟C#的NameValueCollection
type NameValueCollection = HashMap<String, String>;

// 协议解析结构体
#[derive(Default)]
struct ClCyberWinAPPProtocolPackage {
    data: HashMap<String, String>,
}

impl ClCyberWinAPPProtocolPackage {
    fn new() -> Self {
        ClCyberWinAPPProtocolPackage {
            data: HashMap::new(),
        }
    }

    // 解析协议字符串(支持 "key=value&key2=value2" 格式)
    fn format_string(&mut self, param: &str) {
        self.data.clear();
        for pair in param.split('&') {
            let parts: Vec<&str> = pair.splitn(2, '=').collect();
            if parts.len() == 2 {
                self.data.insert(parts[0].to_string(), parts[1].to_string());
            }
        }
    }

    fn get(&self, key: &str) -> String {
        self.data.get(key).cloned().unwrap_or_default()
    }
}

// 弹窗函数(模拟MessageBox)
fn show_message_box(title: &str, message: &str, icon: u32) {
    let title_c = CString::new(title).unwrap();
    let message_c = CString::new(message).unwrap();
    unsafe {
        MessageBoxA(
            ptr::null_mut(),
            message_c.as_ptr(),
            title_c.as_ptr(),
            MB_OK | icon,
        );
    }
}

// 信息弹窗
fn info_box(title: &str, message: &str) {
    show_message_box(title, message, MB_ICONINFORMATION);
}

// 错误弹窗
fn error_box(title: &str, message: &str) {
    show_message_box(title, message, MB_ICONERROR);
}

// 日志写入函数
fn write_log(capture_type: &str, log_type: &str, content: &str) -> io::Result<()> {
    // 获取可执行文件路径
    let exe_path = std::env::current_exe()?;
    let exe_dir = exe_path.parent().unwrap_or(Path::new("."));
    
    // 构建日志路径
    let now = Local::now();
    let date_str = now.format("%Y-%m-%d").to_string();
    let log_dir = exe_dir.join("log").join(capture_type).join(date_str);
    
    // 创建目录
    fs::create_dir_all(&log_dir)?;
    
    // 日志文件路径
    let log_path = log_dir.join(format!("{}_log.log", log_type));
    
    // 写入日志内容
    let mut file = File::options().append(true).create(true).open(log_path)?;
    let log_time = now.format("%Y-%m-%d %H:%M:%S").to_string();
    writeln!(file, "==============================")?;
    writeln!(file, "{}<<<<<<<<<<<<<<<<<<<<<<<<<<", log_time)?;
    writeln!(file, "{}", content)?;
    writeln!(file)?;
    
    Ok(())
}

// 模拟C#的Copy函数(从字节数组截取字符串)
fn copy_bytes(data: &[u8], start: usize, length: usize) -> String {
    // C#是1-based索引,转换为0-based
    let start_idx = if start > 0 { start - 1 } else { 0 };
    let end_idx = start_idx + length;
    
    // 确保不越界
    let end_idx = end_idx.min(data.len());
    if start_idx >= end_idx {
        return String::new();
    }
    
    // 转换为字符串(ASCII编码)
    String::from_utf8_lossy(&data[start_idx..end_idx]).into_owned()
}

// 读卡函数(旧版本)
fn rd_card() -> bool {
    let mut buf_card = BUF_CARD.lock().unwrap();
    let st = unsafe { ReadCard(1, buf_card.as_mut_ptr()) };
    
    if st != 0 {
        if st == 1 {
            error_box(
                "读卡失败(返回值=1)",
                "请放一张卡在发卡器上面,\n确保 门锁软件 可以正常发卡,然后调试接口",
            );
        } else {
            error_box("提示", &format!("读卡失败\n错误码: {}", st));
        }
        return false;
    }
    
    // 验证卡数据
    let card_data_str = copy_bytes(&buf_card, 5, 2);
    if card_data_str != "01" {
        error_box("提示", "发卡器的感应区无卡");
        return false;
    }
    
    true
}

// V10版本读卡函数
fn rd_card_v10() -> bool {
    let mut buf_card_v10 = BUF_CARD_V10.lock().unwrap();
    let st = unsafe { ReadCard_v10(1, buf_card_v10.as_mut_ptr()) };
    
    if st != 0 {
        error_box("提示", &format!("读卡失败\n错误码: {}", st));
        return false;
    }
    
    true
}

// 获取卡片标识
fn cyber_win_locak_app_get_sign(buf_card: &[u8]) -> String {
    // 检查是否为空白卡
    if copy_bytes(buf_card, 25, 8) == "FFFFFFFF" {
        error_box("提示", "此卡是空白卡,请换一张能开门的卡");
        return "此卡是空白卡,请换一张能开门的卡".to_string();
    }
    
    // 计算酒店标识
    let s = copy_bytes(buf_card, 11, 4);
    let i = u64::from_str_radix(&s, 16).unwrap_or(0) % 16384;
    
    let s2 = copy_bytes(buf_card, 9, 2);
    let i2 = u64::from_str_radix(&s2, 16).unwrap_or(0);
    let i = i + i2 * 65536;
    
    // 最终计算
    let i_final = i2 * 65536 + (i % 16383);
    i_final.to_string()
}

// 构建卡片信息JSON
fn build_card_info_json(
    status: &str,
    hotel_sign: &str,
    message: &str,
    lock_no: &str,
    physical_no: &str,
    check_in_time: &str,
    check_out_time: &str,
    llock: &str,
) -> String {
    format!(
        r#"{{
            "status": "{}",
            "hotelsign": "{}",
            "message": "{}",
            "lockno": "{}",
            "physical_no": "{}",
            "checkingintime": "{}",
            "checkingouttime": "{}",
            "llock": "{}"
        }}"#,
        status, hotel_sign, message, lock_no, physical_no, check_in_time, check_out_time, llock
    )
}

// ------------------------------ 业务函数 ------------------------------

// 启动函数
pub fn start(obj: &NameValueCollection) -> String {
    let _param1 = obj.get("param1").cloned().unwrap_or_default();
    "随机预安装插件".to_string()
}

// 状态函数
pub fn status(obj: &NameValueCollection) -> String {
    // 调用蜂鸣器(fUSB=1, 时长50ms)
    unsafe { Buzzer(1, 50) };
    "当你听到设备蜂鸣器,说明设备已经连接".to_string()
}

// 退房(注销卡片)
pub fn checking_out(obj: &NameValueCollection) -> String {
    let mut result = "注销卡片".to_string();
    let param = obj.get("param").cloned().unwrap_or_default();
    
    // 解析协议
    let mut cl_app = ClCyberWinAPPProtocolPackage::new();
    cl_app.format_string(&param);
    let _ = write_log("酒店智能门锁", "P50", &format!("注销,{}", param));
    
    let hotel_sign_str = cl_app.get("hotelsign");
    let hotel_sign = match hotel_sign_str.parse::<i32>() {
        Ok(v) => v,
        Err(_) => {
            return format!("{}:酒店标识格式错误", result);
        }
    };
    
    // 初始化USB设备(1=proUSB)
    let st = unsafe { initializeUSB_P50(1) };
    if st != 0 {
        error_box("错误", "设备打开失败");
        return "打开端口失败".to_string();
    }
    
    // 确保退出时关闭设备
    struct CloseUsbGuard;
    impl Drop for CloseUsbGuard {
        fn drop(&mut self) {
            unsafe { CloseUSB_P50(1) };
        }
    }
    let _guard = CloseUsbGuard;
    
    // 注销卡片
    let mut card_no_buf = [0u8; 100];
    let st = unsafe {
        CardErase_P50(
            1,
            hotel_sign,
            card_no_buf.as_mut_ptr() as *mut c_char,
        )
    };
    
    if st != 0 {
        let msg = format!("注销失败\n错误码: {}", st);
        info_box("提示", &msg);
        result = format!("{}:注销失败{}", result, st);
    } else {
        result = format!("{}:成功", result);
    }
    
    result
}

// 入住(发卡)
pub fn checking_in(obj: &NameValueCollection) -> String {
    let mut result = "酒店入住发卡".to_string();
    let param = obj.get("param").cloned().unwrap_or_default();
    
    // 解析协议
    let mut cl_app = ClCyberWinAPPProtocolPackage::new();
    cl_app.format_string(&param);
    let _ = write_log("酒店智能门锁", "P50", &format!("入住,{}", param));
    
    let lock_no = cl_app.get("lockno");
    let hotel_sign_str = cl_app.get("hotelsign");
    let check_out_time = cl_app.get("checkingouttime");
    
    // 验证锁号长度
    if lock_no.len() < 6 {
        error_box("提示", &format!("锁号长度错误={}", lock_no));
        return String::new();
    }
    
    let hotel_sign = match hotel_sign_str.parse::<i32>() {
        Ok(v) => v,
        Err(_) => {
            return format!("{}:酒店标识格式错误", result);
        }
    };
    
    // 初始化USB设备
    let st = unsafe { initializeUSB_P50(1) };
    if st != 0 {
        error_box("错误", "设备打开失败");
        return "打开端口失败".to_string();
    }
    
    // 确保退出时关闭设备
    struct CloseUsbGuard;
    impl Drop for CloseUsbGuard {
        fn drop(&mut self) {
            unsafe { CloseUSB_P50(1) };
        }
    }
    let _guard = CloseUsbGuard;
    
    // 生成时间字符串(yyMMddHHmmss)
    let check_in_time = Local::now().format("%y%m%d%H%M%S").to_string();
    
    // 发卡参数
    let dai = 1;          // DAI值
    let llock = 1;        // 反锁标志
    let mut card_hex_str = [0u8; 500];
    
    // 转换字符串为CString
    let check_in_time_c = CString::new(check_in_time).unwrap();
    let check_out_time_c = CString::new(check_out_time).unwrap();
    let lock_no_c = CString::new(lock_no).unwrap();
    
    // 调用发卡函数
    let st = unsafe {
        GuestCard_原始_P50(
            1,
            hotel_sign,
            0,
            dai,
            llock,
            0,
            check_in_time_c.as_ptr(),
            check_out_time_c.as_ptr(),
            lock_no_c.as_ptr(),
            card_hex_str.as_mut_ptr() as *mut c_char,
        )
    };
    
    if st != 0 {
        let msg = format!("调用发卡函数失败\n错误码: {}", st);
        info_box("提示", &msg);
        result = format!("{}调用发卡函数失败", result);
    } else {
        result = format!("{}制卡成功V2024{}", result, lock_no);
    }
    
    result
}

// 获取卡片标识
pub fn get_sign(obj: &NameValueCollection) -> String {
    if !rd_card_v10() {
        return "读卡失败".to_string();
    }
    
    let buf_card_v10 = BUF_CARD_V10.lock().unwrap();
    cyber_win_locak_app_get_sign(&buf_card_v10)
}

// 读取房卡信息
pub fn read_card_info(obj: &NameValueCollection) -> String {
    let param = obj.get("param").cloned().unwrap_or_default();
    
    // 解析协议
    let mut cl_app = ClCyberWinAPPProtocolPackage::new();
    cl_app.format_string(&param);
    let _ = write_log("酒店智能门锁", "P50", &format!("读卡,{}", param));
    
    let hotel_sign_str = cl_app.get("hotelsign");
    let hotel_sign = match hotel_sign_str.parse::<i32>() {
        Ok(v) => v,
        Err(_) => {
            return build_card_info_json(
                "3",
                &hotel_sign_str,
                "酒店标识格式错误",
                "",
                "",
                "",
                "",
                "",
            );
        }
    };
    
    // 模拟卡数据(实际应从读卡获取)
    let card_data_hex = "551501C1011B4D9D1B0601036707CB2C07D30000000000000000000000000000000000325CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00";
    let mut lock_no_buf = [0u8; 50];
    
    // 转换为CString
    let card_data_hex_c = CString::new(card_data_hex).unwrap();
    
    // 调用DLL获取卡信息
    let st = unsafe {
        GetGuestLockNoByCardDataStr_P50(
            hotel_sign,
            card_data_hex_c.as_ptr(),
            lock_no_buf.as_mut_ptr() as *mut c_char,
        )
    };
    
    let (status, message, lock_no, physical_no, check_in_time, check_out_time, llock) = match st {
        -4 => (
            "4",
            &format!("空白卡或者已经注销的卡片,返回值:{}", st),
            "", "", "", "", "",
        ),
        -3 => (
            "3",
            &format!("非本酒店卡,酒店标识不匹配,返回值:{}", st),
            "", "", "", "", "",
        ),
        -2 => (
            "3",
            &format!("没有有效卡片,返回值:{}", st),
            "", "", "", "", "",
        ),
        0 => {
            // 解析返回数据
            let lock_no = copy_bytes(&lock_no_buf, 1, 6);
            let check_in_time = copy_bytes(&lock_no_buf, 7, 12);
            let check_out_time = copy_bytes(&lock_no_buf, 19, 12);
            let physical_no = copy_bytes(&lock_no_buf, 33, 8);
            let llock = copy_bytes(&lock_no_buf, 31, 1);
            
            (
                "9",
                "读取成功",
                &lock_no,
                &physical_no,
                &check_in_time,
                &check_out_time,
                &llock,
            )
        }
        1 => (
            "1",
            &format!("连接发卡器失败,返回值:{}", st),
            "", "", "", "", "",
        ),
        _ => (
            "4",
            &format!("未知返回值:{}", st),
            "", "", "", "", "",
        ),
    };
    
    // 显示弹窗
    if st != 0 {
        info_box("提示", message);
    }
    
    build_card_info_json(
        status,
        &hotel_sign_str,
        message,
        lock_no,
        physical_no,
        check_in_time,
        check_out_time,
        llock,
    )
}

// 初始化函数(可选)
pub fn init() {
    // 读取DLL版本信息
    let mut ver_buf = [0u8; 256];
    unsafe {
        GetDLLVersion(ver_buf.as_mut_ptr() as *mut c_char);
    }
    let version = CStr::from_bytes_until_nul(&ver_buf)
        .unwrap()
        .to_str()
        .unwrap_or("未知");
    println!("DLL版本: {}", version);
}

阿雪技术观

在科技发展浪潮中,我们不妨积极投身技术共享。不满足于做受益者,更要主动担当贡献者。无论是分享代码、撰写技术博客,还是参与开源项目维护改进,每一个微小举动都可能蕴含推动技术进步的巨大能量。东方仙盟是汇聚力量的天地,我们携手在此探索硅基生命,为科技进步添砖加瓦。

Hey folks, in this wild tech - driven world, why not dive headfirst into the whole tech - sharing scene? Don't just be the one reaping all the benefits; step up and be a contributor too. Whether you're tossing out your code snippets, hammering out some tech blogs, or getting your hands dirty with maintaining and sprucing up open - source projects, every little thing you do might just end up being a massive force that pushes tech forward. And guess what? The Eastern FairyAlliance is this awesome place where we all come together. We're gonna team up and explore the whole silicon - based life thing, and in the process, we'll be fueling the growth of technology.

相关推荐
free-elcmacom1 小时前
MATLAB物理仿真<1>电磁场有限元仿真
开发语言·matlab·电磁场仿真
Emilia486.1 小时前
C++ 类与对象:解锁面向对象编程的核心密码(上)
开发语言·c++
成豆o((⊙﹏⊙))o.1 小时前
C语言基础知识,仅供自己参考
c语言·开发语言
行走在电子领域的工匠1 小时前
台达ST:自定义串行通讯传送与接收指令COMRS程序范例二
开发语言
Mr_WangAndy1 小时前
C++17 新特性_第二章 C++17标准库特性_std::invoke和std::invoke_result_t
c++·invoke·c++40周年·c++17新特性·invoke_result
Sally_xy1 小时前
Python 虚拟环境
开发语言·chrome·python
张np1 小时前
java基础-List接口
java·开发语言
拾贰_C2 小时前
[python ]anaconda
开发语言·python
VBA63372 小时前
VBA数据库解决方案第二十五讲:工作表中数据在数据表中批量删除
开发语言