当前位置:

首页 > 硬件相关 > .NET 8.0 与硬件设备的火花碰撞

.NET 8.0 与硬件设备的火花碰撞

前言近期我在社区中表达了想要制作稚晖君的瀚文键盘的意愿,幸运的是,有两位朋友慷慨相助,一位赠送了我电路板,另一位则送来了已经焊接好元件的电路板。既然大家如此大方,我也决定全力投入到这把客制化键盘的制作中。为了节省成本,我特意重新设计了外壳模型,并使用3D打印机打印了整个外壳,这样就省下了八九百元的CNC加工费。关于键盘的基本介绍这里就不赘述了,它的主要特色在于左侧的扩展模块,配备了墨水屏和手感极佳的旋钮,当然也支持自定义开发,这也是我撰写这篇文章的动机之一,因为我想开发一些功能。以下是效果图:技术选型我查

本文目录

    前言

    近期我在社区中表达了想要制作稚晖君的瀚文键盘的意愿,幸运的是,有两位朋友慷慨相助,一位赠送了我电路板,另一位则送来了已经焊接好元件的电路板。既然大家如此大方,我也决定全力投入到这把客制化键盘的制作中。为了节省成本,我特意重新设计了外壳模型,并使用3D打印机打印了整个外壳,这样就省下了八九百元的CNC加工费。

    关于键盘的基本介绍这里就不赘述了,它的主要特色在于左侧的扩展模块,配备了墨水屏和手感极佳的旋钮,当然也支持自定义开发,这也是我撰写这篇文章的动机之一,因为我想开发一些功能。以下是效果图:

    .NET 8.0 与硬件设备能碰撞出怎么样的火花

    技术选型

    我查阅了一些社区的键盘资料,发现社区的固件有多个版本。稚晖君原版的固件年代久远,不太好用,而赠送我键盘的那位朋友的版本我觉得很方便,且用户量也很多。因此,我基于这个版本的固件进行dotnet版本的SDK开发。目前,社区还有其他版本的SDK,包括Python版本和Vue版本,我可以参考这些进行开发。

    1、框架选择

    作为一名.Net开发者,我自然希望使用.Net进行开发。理由是这个键盘主要用于PC上,使用.Net实现SDK可以与WPF、MAUI和WinUI无缝对接,完成很多任务型功能。我选择了最新的.Net8版本,在SDK测试编写完成后,将其集成到我之前的WinUI桌面程序中。大家可能会问,为什么不选择MAUI?因为我暂时不想花时间重新编写,但SDK是支持跨平台的,这点问题不大。

    2、设备通讯协议

    键盘使用的固件是基于开源的ZMK代码编写的,设备在电脑上被识别为HID设备,通讯格式采用Protobuf协议。因此,对于.Net也需要使用Protobuf来进行数据打包。这部分花费了我一些时间,主要是有些地方不太理解,坑主要是在将数据转换成字节数组时遇到的问题,这点在后面的代码讲解中会有详细说明。

    设备固件地址:https://github.com/xingrz/zmk-config_helloword_hw-75

    Python SDK: https://github.com/xingrz/zmkx-sdk

    3、库选择

    我原本以为.Net可以使用的HID库有很多,但经过一番测试后发现,HidApi.Net的表现还算不错,其他如Device.Net和HidLibrary则不太满意。最终,我选择了HidApi.Net来与设备通讯,使用Google.Protobuf和Grpc.Tools处理通讯数据,使用SixLabors.ImageSharp进行图片数据转换。

    HidApi.Net

    Google.Protobuf

    Grpc.Tools

    SixLabors.ImageSharp

    最终效果如下图所示:

    .NET 8.0 与硬件设备能碰撞出怎么样的火花

    代码讲解

    我这次将项目代码提交到了电子脑壳的仓库,因为我要将功能集成到电子脑壳中,所以放在了这个仓库的helloworld-keyboard分支,未来可能会合并到主分支。

    仓库地址:https://github.com/maker-community/ElectronBot.DotNet

    .NET 8.0 与硬件设备能碰撞出怎么样的火花

    通讯协议实现

    通讯的核心部分是Hw75DynamicDevice的Call方法,它包含了将protobuf生成的C#对象转换成字节数组并拆分成数据包发送到设备。

    代码语言:javascript

    代码运行次数:0

    private MessageD2H Call(MessageH2D h2d) {
        if (_device == null) {
            throw new Exception("设备为空");
        }
        var bytes = h2d.EnCodeProtoMessage();
        for (int i = 0; i < bytes.Length; i += PayloadSize) {
            byte[] buf;
            if (i + PayloadSize > bytes.Length) {
                buf = bytes[i..];
            } else {
                buf = bytes[i..(i + PayloadSize)];
            }
            var list = new byte[2] { 1, (byte)buf.Length };
            var result = list.Concat(buf).ToArray();
            _device.Write(result);
        }
        Task.Delay(20);
        var byteList = new List();
        while (true) {
            var read = _device.Read(RePortCount + 1);
            int cnt = read[1];
            byteList.AddRange(read[3..(cnt + 2)]);
            if (cnt < PayloadSize) {
                break;
            }
        }
        var resultMessage = new MessageD2H();
        resultMessage.MergeFrom(byteList.ToArray());
        return resultMessage;
    }

    数据打包时有一个关键问题,就是在拼接图片数据时,需要将byte[]长度使用protobuf编码后再组装到数据的byte[]前面。这个转换成byte[]时需要特别注意,代码如下:

    代码语言:javascript

    代码运行次数:0

    public static byte[] EnCodeProtoMessage(this MessageH2D messageH2D) {
        var msgBytes = messageH2D.ToByteArray();
        using (MemoryStream ms = new MemoryStream()) {
            CodedOutputStream output = new CodedOutputStream(ms);
            output.WriteInt32(msgBytes.Length);
            output.Flush();
            byte[] byteList = ms.ToArray();
            var result = byteList.Concat(msgBytes).ToArray();
            return result;
        }
    }

    .NET 8.0 与硬件设备能碰撞出怎么样的火花

    重点部分是HID设备每次发送64字节,第一字节是固定数字1,第二字节是数据长度,后面是数据内容。

    .NET 8.0 与硬件设备能碰撞出怎么样的火花

    数据传输测试

    在完成SDK编写和测试后,我使用控制台项目进行测试,包括图片的合成和文字的绘制,以及将绘制好的图片转换成设备可用的字节数据。

    首先使用ImageSharp加载图片,再加载字体文件,将文字和图片绘制到图片上,为后续制作动态数据做准备,代码如下:

    代码语言:javascript

    代码运行次数:0

    using SixLabors.Fonts;
    using SixLabors.ImageSharp;
    using SixLabors.ImageSharp.Drawing.Processing;
    using SixLabors.ImageSharp.PixelFormats;
    using SixLabors.ImageSharp.Processing;
    using System.Diagnostics;
    using System.Numerics;
    

    byte[] byteArray = new byte[128 * 296 / 8]; var list = new List(); var collection = new FontCollection(); var family = collection.Add("./SmileySans-Oblique.ttf"); var font = family.CreateFont(18, FontStyle.Bold);

    using (var image = Image.Load("face.jpg")) { using var overlay = Image.Load("bzhan.png"); overlay.Mutate(x => { x.Resize(new Size(50,50)); }); // Convert the image to grayscale image.Mutate(x => { x.DrawImage(overlay, new Point(0, 64), opacity: 1); x.DrawText("粉丝数:", font, Color.Black, new Vector2(20, 220)); x.DrawText("999999", font, Color.Black, new Vector2(20, 260)); x.Grayscale(); }); image.Save("test.jpg"); byteArray = image.EnCodeImageToBytes(); }

    然后将ImageSharp合成的图片转换成01矩阵,再组装成byte[]。如果大家有更好的方法,欢迎推荐给我。我的逻辑写在了EnCodeImageToBytes这个扩展方法中。

    代码语言:javascript

    代码运行次数:0

    public static byte[] EnCodeImageToBytes(this Image image) {
    // Create a 01 matrix
    int[,] matrix = new int[image.Height, image.Width];
    for (int y = 0; y < image.Height; y++) {
    for (int x = 0; x < image.Width; x++) {
    var pixel = image[x, y];
    matrix[y, x] = pixel.R > 128 ? 1 : 0;
    }
    }
    // Convert the matrix to a byte array
    byte[] byteArray = new byte[image.Height  image.Width / 8];
    for (int y = 0; y < image.Height; y++) {
    for (int x = 0; x < image.Width; x += 8) {
    byte b = 0;
    for (int i = 0; i < 8; i++) {
    if (x + i < image.Width) {
    b |= (byte)(matrix[y, x + i] << (7 - i));
    }
    }
    byteArray[y  (image.Width / 8) + x / 8] = b;
    }
    }
    return byteArray;
    }

    全部代码如下:

    代码语言:javascript

    代码运行次数:0

    using Google.Protobuf;
    using Google.Protobuf.WellKnownTypes;
    using HelloWordKeyboard.DotNet;
    using HidApi;
    using SixLabors.Fonts;
    using SixLabors.ImageSharp;
    using SixLabors.ImageSharp.Drawing.Processing;
    using SixLabors.ImageSharp.PixelFormats;
    using SixLabors.ImageSharp.Processing;
    using System.Diagnostics;
    using System.Numerics;

    byte[] byteArray = new byte[128 * 296 / 8]; var list = new List(); var collection = new FontCollection(); var family = collection.Add("./SmileySans-Oblique.ttf"); var font = family.CreateFont(18, FontStyle.Bold);

    using (var image = Image.Load("face.jpg")) { using var overlay = Image.Load("bzhan.png"); overlay.Mutate(x => { x.Resize(new Size(50,50)); }); // Convert the image to grayscale image.Mutate(x => { x.DrawImage(overlay, new Point(0, 64), opacity: 1); x.DrawText("粉丝数:", font, Color.Black, new Vector2(20, 220)); x.DrawText("999999", font, Color.Black, new Vector2(20, 260)); x.Grayscale(); }); image.Save("test.jpg"); byteArray = image.EnCodeImageToBytes(); }

    var hidDevice = new Hw75DynamicDevice(); hidDevice.Open(); Stopwatch sw = Stopwatch.StartNew(); sw.Start(); var data111 = hidDevice.SetEInkImage(byteArray, 0, 0, 128, 296, false); sw.Stop(); Console.WriteLine($"send data ms:{sw.ElapsedMilliseconds}"); Console.ReadKey(); Hid.Exit();

    总结

    这次功能的编写让我最有感悟的地方就是自己对Github Copilot的依赖更多了,我基本上很多的知识都是通过询问它获得的,因为从网上搜索还要自己过滤那些数据,比较耽误时间。

    另一个值得一提的点是,HidApi.Net这个库是最近刚有人编写的,社区中还是有新鲜血液的,支持.net6,7,8,非常新,也算是个惊喜。希望社区的轮子越来越多!

    其他角度的照片展示

    .NET 8.0 与硬件设备能碰撞出怎么样的火花

    .NET 8.0 与硬件设备能碰撞出怎么样的火花

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    硬件相关
    相关文章 更多
    鸿蒙微信新版本开启测试,修复问题更新上线
    鸿蒙微信新版本开启测试,修复问题更新上线

    近日,华为鸿蒙原生版微信启动了新一轮邀请测试,意味着这款国民级社交应用在鸿蒙生态中的适配与升级正持续深化。据CNMO报道,本次测试聚焦于问题修复与体验优化,为后续面向更广泛用户的正式版本发布铺路。鸿蒙微信数码博主“超维界”透露,微信鸿蒙版App近期已开启新版本的定向内测。其中,版本号为8.0.15.32的测试包说明中明确指出:“修复了若干已知问题”。此外,微信内部员工“客村小蒋”也在社交平台确认,该版本已进入内测阶段;开发团队在攻克多个用户反馈集中的复杂功能后,现阶段正集中精力打磨细节体验,并

    虚环是什么游戏 类型及前瞻解析
    虚环是什么游戏 类型及前瞻解析

    虚环究竟是一款怎样的作品?不少玩家对它的定位尚不明确。实际上,这是一款以虚拟偶像圈层(V圈)为背景,融合高强度战斗演出、策略布阵与角色养成元素的创新手游。接下来,让我们一同了解虚环的游戏类型与核心玩法前瞻。游戏以V圈为核心主题,巧妙地将虚拟主播的世界观与动作策略机制结合。在虚环构建的设定中,人气V圈主播将化身战斗偶像,踏入被称为“虚环”的异次元空间展开激烈对决。玩家则扮演指挥官,组建并培养专属战队,通过策略搭配阵容,与来自各方的传奇偶像展开较量。这种将虚拟主播文化与战斗策略深度结合的设计,不仅新颖独特,也

    Golang表驱动与基准测试技巧
    Golang表驱动与基准测试技巧

    表驱动测试结合基准测试可同时验证代码正确性与性能。通过定义测试用例结构体,TestAdd函数覆盖多种输入场景,确保逻辑正确;BenchmarkConcatStrings则对不同规模字符串拼接进行性能测量,利用b.Run为每组数据单独计时,实现精细化性能监控,提升测试可维护性与执行效率。

    小米汽车新版本开发中,预计4-8周完成
    小米汽车新版本开发中,预计4-8周完成

    近日,小米汽车对网友关注的问题做出了回应,表示小米SU7Ultra的「排位模式」功能增加了解锁条件,引起了部分用户的不满,对此表示诚挚的歉意。在收到用户反馈后,小米高度重视,已暂停了此次更新。已升级的少数用户,官方将在下一个版本更新中解决问题。小米已启动新版本的开发和测试,预计需要4-8周,具体时间将以小米官方通知为准。小米表示,设计该功能的初衷是为了提升驾驶安全性,但未能充分征求用户意见,也未做好相关功能的沟通说明。此次事件使小米深刻认识到:任何涉及用户体验的重大更新,都必须建立在充分沟通的基

    PHP 函数的调试和测试
    PHP 函数的调试和测试

    PHP函数调试和测试指南:配置Xdebug以获得高级调试功能。使用var_dump()和print_r()检查变量值。使用条件断点和断点来控制执行流程。编写单元测试以自动化功能检查。

    Golang函数的测试和调试
    Golang函数的测试和调试

    在Golang中测试函数:创建以_test.go结尾的测试文件。声明一个以TestXXX命名的测试函数,其中XXX是被测函数的名称。使用断言来验证预期结果与实际结果是否一致。设置断点并使用调试器来调试测试失败的情况。使用表驱动测试和覆盖率工具来增强测试效率。

    golang函数的测试代码如何组织?
    golang函数的测试代码如何组织?

    组织GoLang测试代码的最佳实践:文件结构:每个包的测试代码应放置在以_test.go后缀结尾的独立文件中。测试函数命名:使用funcTest<FunctionName>_<TestType>()命名测试函数,描述其测试的内容。测试表:使用测试表组织涉及多个输入/输出值的情况。基准测试:使用基准测试功能评估函数的性能。模拟:使用模拟框架模拟函数依赖关系。

    golang函数闭包在测试中的作用
    golang函数闭包在测试中的作用

    Go语言函数闭包在单元测试中发挥着至关重要的作用:捕获值:闭包可以访问外部作用域的变量,允许在嵌套函数中捕获和重用测试参数。简化测试代码:通过捕获值,闭包消除了对每个循环重复设置参数的需求,从而简化了测试代码。提高可读性:使用闭包可以组织测试逻辑,使测试代码更清晰、更易于阅读。

    微信电脑端可发朋友圈,查看他人动态
    微信电脑端可发朋友圈,查看他人动态

    今日,微信官网上架了Windows最新4.0.3测试版,同时还提供了macOS测试版的dmg安装包,支持英特尔和AppleSilicon平台。全新版本的更新内容主要包括:体验更新,Windows、Mac等多端统一;可发表朋友圈:可查看朋友的朋友圈相册;朋友圈可设置置顶内容:可设置深色模式和浅色模式:可设置字号大小。据悉,4.0以后的微信内测版不会覆盖电脑上已安装的微信正式版,而且用户也可以将已有微信上的聊天记录快速导入到内测版中。感兴趣的小伙伴可以去下载试一下~与此同时,微信也

    在Colab运行Mamba模型全攻略
    在Colab运行Mamba模型全攻略

    在我们之前的文章中,我们介绍了研究人员提出了一种挑战Transformer的新架构Mamba。他们的研究表明,Mamba是一种状态空间模型(SSM),在多种模式(如语言、音频和时间序列)中展现出了卓越的性能。为了证明这一点,研究人员使用Mamba-3B模型进行了语言建模实验。该模型超越了同等大小的Transformer模型,并且在预训练和下游评估期间,其表现与大小为其两倍的Transformer模型相当。Mamba的独特之处在于其快速处理能力、选择性SSM层以及受FlashAttention启发的硬件友好

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。