ptz 发布的文章

参考:

udelay、mdelay、ndelay、msleep使用比较说明
https://www.cnblogs.com/Ph-one/p/4678361.html

arm体系下的cpu_relax()函数疑惑
http://www.wowotech.net/forum/viewtopic.php?id=21#:~:text=cpu_relax%E5%BF%85%E9%A1%BB%E5%85%B7%E5%A4%87%E4%B8%A4%E4%B8%AA%E5%8A%9F%E8%83%BD%EF%BC%9A%201%E3%80%81%E7%A1%AE%E4%BF%9D%E5%AF%B9flag%E7%9A%84%E8%AE%BF%E9%97%AE%E6%AF%8F%E6%AC%A1%E9%83%BD%E4%BB%8Ememory%E4%B8%AD%E5%8A%A0%E8%BD%BD%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AFbarrier,%28%29%E5%87%BD%E6%95%B0%E7%9A%84%E4%BD%9C%E7%94%A8%202%E3%80%81%E9%80%9A%E7%9F%A5%E5%BA%95%E5%B1%82CPU%EF%BC%8C%E7%9B%AE%E5%89%8D%E4%BB%A3%E7%A0%81%E6%B2%A1%E6%9C%89%E5%9C%A8%E5%81%9A%E4%BB%80%E4%B9%88%E5%AE%9E%E9%99%85%E6%9C%89%E6%84%8F%E4%B9%89%E7%9A%84%E4%BA%8B%E6%83%85%EF%BC%8C%E5%A6%82%E6%9E%9C%E5%8F%AF%E4%BB%A5%E7%9A%84%E8%AF%9D%EF%BC%8C%E5%88%AB%E8%AE%A9cpu%E5%81%9A%E5%A4%AA%E5%A4%9A%E4%BA%8B%E6%83%85%EF%BC%8C%E7%B3%BB%E7%BB%9F%E7%9A%84%E8%B5%84%E6%BA%90%E5%B0%BD%E9%87%8F%E8%AE%A9%E7%BB%99%E5%85%B6%E4%BB%96%E7%9A%84cpu%E3%80%82

问题:

硬件电路里面按键时高电平有效,从 getevent -l 这边看,kernel 上报时没有问题的,只是up 和 down 反过来而已,有一下,就发一条信息。但是在 app 里面就不一样了,每当 app 的界面出现前后台切换的时候,会对所有的按键进行刷新,导致出现一直刷新按键事件的情况。

解决方法:

直接修改按键本身比较困难,最简单方法是新建一个驱动文件,专门针对这个高电平有效按键即可。

//#define DEBUG

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <linux/sched.h>
#include <linux/input.h>
#include <linux/input/mt.h>

#include <linux/platform_device.h>

#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/types.h>

#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/pinctrl/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/power_supply.h>

#include <linux/uaccess.h>

#include <linux/kdev_t.h>
#include <linux/device.h>
#include <linux/wait.h>

static struct class *gpio_reverse_key_class;

 struct gpio_reverse_key_detect {
        struct device *dev;
        struct input_dev *p_inputdev;

        unsigned int gpio_reverse_key_gpio;
        unsigned int gpio_reverse_key_irq_num;

        struct workqueue_struct *gpio_reverse_key_detect_wq;
        struct delayed_work gpio_work;

        atomic_t state;
        unsigned int code;

};

static int reverse_key_count = 0;

static void gpio_reverse_key_detect_work_func(struct work_struct *work){
        struct gpio_reverse_key_detect *dev_struct;
        int old_state, new_state;
        printk("gpio_reverse_key_detect in work func\n");
        dev_struct = container_of(work, struct gpio_reverse_key_detect, gpio_work.work);

        reverse_key_count = 0;
        old_state = atomic_read(&dev_struct->state);
        new_state = gpio_get_value(dev_struct->gpio_reverse_key_gpio);
        if (new_state < 0) {
                dev_err(dev_struct->dev,
                        "failed to get qrcode-gpio state: %d\n", new_state);
                return;
        }

        if(new_state != old_state){
                dev_err(dev_struct->dev, "qrcode_detect update state %d", new_state);
                atomic_set(&dev_struct->state, new_state);
                input_report_key(dev_struct->p_inputdev, dev_struct->code, new_state);
                input_sync(dev_struct->p_inputdev);
        }

        printk("gpio_reverse_key_detect repot the key %d, value %d\n", dev_struct->code, new_state);
        enable_irq(dev_struct->gpio_reverse_key_irq_num);
        printk("gpio_reverse_key_detect enable irq");
}

static irqreturn_t gpio_reverse_key_detect_func(int irq, void *dev_id){
        struct gpio_reverse_key_detect * dev_struct = dev_id;

        printk("gpio_reverse_key_detect in irq func\n");
        disable_irq_nosync(dev_struct->gpio_reverse_key_irq_num);
        //printk("gpio_reverse_key_detect disable irq\n");

        if(!reverse_key_count){
                        schedule_delayed_work(&dev_struct->gpio_work,msecs_to_jiffies(20));
                        reverse_key_count = 1;
        }else{
                cancel_delayed_work(&dev_struct->gpio_work);
                schedule_delayed_work(&dev_struct->gpio_work,msecs_to_jiffies(20));
        //queue_work(dev_struct->gpio_reverse_key_detect_wq, &dev_struct->work);
        //printk("gpio_reverse_key_detect queue work ok\n");
        }

        return IRQ_HANDLED;

}

static int gpio_reverse_key_detect_input_set(struct gpio_reverse_key_detect *dev_struct){
        int ret;

        printk("gpio_reverse_key_detect input set begin\n");
        dev_struct->p_inputdev = input_allocate_device();
        if (dev_struct->p_inputdev == NULL) {
                printk("Failed to allocate input device.\n");
                return -1;
        }
        __set_bit(EV_KEY, dev_struct->p_inputdev->evbit);
        dev_struct->p_inputdev->name = "gpio_reverse_key_detect_input";
        //__set_bit(KEY_VOLUMEDOWN, dev_struct->p_inputdev->keybit);
        __set_bit(dev_struct->code, dev_struct->p_inputdev->keybit);
        printk("gpio_reverse_key_detect input set bit %d\n", dev_struct->code);
        input_set_drvdata(dev_struct->p_inputdev, dev_struct);

        ret = input_register_device(dev_struct->p_inputdev);
        if (ret) {
                printk( "Register %s input device failed.\n",dev_struct->p_inputdev->name);
        //      goto exit_free_inputdev;
        }
        printk("gpio_reverse_key_detect input set successd \n");
        return 0;
}

static int gpio_reverse_key_detect_probe(struct platform_device *pdev){
        struct gpio_reverse_key_detect *dev_struct;
        int ret;
        int state;
        printk("gpio_reverse_key_detect probe begin\n");
        dev_struct = devm_kzalloc(&pdev->dev,sizeof(struct gpio_reverse_key_detect) , GFP_KERNEL);
        dev_struct->dev = &pdev->dev;

        dev_struct->gpio_reverse_key_gpio = of_get_named_gpio(dev_struct->dev->of_node, "gpio_reverse_key_gpio", 0);

        gpio_request(dev_struct->gpio_reverse_key_gpio, "gpio_reverse_key_gpio");

        dev_struct->gpio_reverse_key_irq_num = gpio_to_irq(dev_struct->gpio_reverse_key_gpio);

        gpio_direction_input(dev_struct->gpio_reverse_key_gpio);

        if(of_property_read_u32(dev_struct->dev->of_node, "linux,code", &dev_struct->code)) {
                dev_err(dev_struct->dev, "fail to get linux code\n");
                return (-EINVAL);
        }
        printk("gpio_reverse_key_detect probe get key code %d\n", dev_struct->code);

        gpio_reverse_key_detect_input_set(dev_struct);

        dev_struct->gpio_reverse_key_detect_wq = create_singlethread_workqueue("gpio_reverse_key_detect_wq");

        INIT_DELAYED_WORK(&dev_struct->gpio_work, gpio_reverse_key_detect_work_func);

        state = gpio_get_value(dev_struct->gpio_reverse_key_gpio);
        if(state < 0) {
                dev_err(dev_struct->dev, "fail to init base_detect state %d\n", state);
                return (-EINVAL);
        }
        atomic_set(&dev_struct->state, state);

        ret = devm_request_threaded_irq(&pdev->dev, dev_struct->gpio_reverse_key_irq_num, (irq_handler_t)gpio_reverse_key_detect_func, NULL, IRQF_TRIGGER_FALLING |IRQF_TRIGGER_RISING | IRQF_ONESHOT, "gpio_reverse_key_detect", dev_struct);
        if (ret) {
                printk("quectel sc20 %s  create gpio_reverse_key_class err\n", __func__);
                        return ret;
        }

        printk("gpio_reverse_key_detect probe end\n");
        return 0;
}

static struct of_device_id of_device_sc20_gpio_match_table[] =
{
        {.compatible = "quectel,gpio_reverse_key_detect"},
        {},
};

int gpio_reverse_key_detect_remove(struct platform_device *pdev)
{
        int ret = 0;
//      struct  = NULL;
//      sc20_gpio_dev = (struct sc20_gpio_device *)dev_get_drvdata(&pdev->dev);
//      if(sc20_gpio_dev)
//              kfree(sc20_gpio_dev);
        printk("quectel sc20 %s enter\n", __func__);

        return ret;
}

static struct platform_driver gpio_reverse_key_platform_driver =
{
        .probe = gpio_reverse_key_detect_probe,
        .remove = gpio_reverse_key_detect_remove,
        .driver =
                {
                        .name = "GPIO_REVERSE_KEY",
                        .owner = THIS_MODULE,
                        .of_match_table = of_device_sc20_gpio_match_table,
                }
};

static int __init gpio_reverse_key_detect_init(void)
{
        int ret = 0;
        printk("quectel sc20 %s enter\n", __func__);
        gpio_reverse_key_class = class_create(THIS_MODULE, "gpio_reverse_key_detect");
        if (IS_ERR(gpio_reverse_key_class))
                {
                printk("quectel sc20 %s  create gpio_reverse_key_class err\n", __func__);
                return PTR_ERR(gpio_reverse_key_class);
                }

//      sc20_gpio_class->dev_attrs = sc20_gpio_class_attrs;

        printk("quectel sc20 %s  create gpio_reverse_key_class success\n", __func__);
        ret = platform_driver_register(&gpio_reverse_key_platform_driver);

        return ret;
}

module_init(gpio_reverse_key_detect_init);

static void __exit gpio_reverse_key_detect_exit(void)
{
        printk("quectel sc20 %s enter\n", __func__);
}
module_exit(gpio_reverse_key_detect_exit);

mODULE_DESCRIPTION("QUCTEL sc20 GPIOS_REVERSE_KEY");
mODULE_LICENSE("GPL v2");

参考:

按键响应onKeyDown,onKeyLongPress,onKeyUp
https://www.jianshu.com/p/83a1dd9db896
onKeyPress Vs. onKeyUp and onKeyDown
https://stackoverflow.com/questions/3396754/onkeypress-vs-onkeyup-and-onkeydown#:~:text=The%20onKeyDown%20event%20is%20triggered%20when%20the%20user,%26%20releases%20a%20key%20%28onKeyDown%20followed%20by%20onKeyUp%29.
onkeyup、onkeydown和onkeypress的区别
https://blog.csdn.net/czh500/article/details/80330207
安卓onkeyup onkeydown事件小记
https://blog.csdn.net/sjpz0124/article/details/50619524#:~:text=android%20Activity%E7%B1%BB%20onKeyUp%20%28%29%2C%20onKeyDown,%E7%95%A5%E8%AF%BB%20Activity.%20onKeyDown%20%28%29%3B%20%E5%BD%93%E6%9F%90%E4%B8%AA%E9%94%AE%E8%A2%AB%E6%8C%89%E4%B8%8B%E6%97%B6%E4%BC%9A%E8%A7%A6%E5%8F%91%EF%BC%8C%E4%BD%86%E4%B8%8D%E4%BC%9A%E8%A2%AB%E4%BB%BB%E4%BD%95%E7%9A%84%E8%AF%A5Activity%E5%86%85%E7%9A%84%E4%BB%BB%E4%BD%95view%E5%A4%84%E7%90%86%E3%80%82

问题

Android Studio一直 Download fastutil-x.x.x.jar, 应该是被墙了。

解决方法

在项目目录下面的 build.gradle 里面添加 aliyun

buildscript {
    repositories {
        maven {
            url 'https://maven.aliyun.com/repository/google';
        }
        maven {
            url 'https://maven.aliyun.com/repository/public';
        }
        maven {
            url 'https://maven.aliyun.com/repository/jcenter';
        }
        google()
        mavenCentral()
    }
    dependencies {
        ...
    }
}

参考:

Android Studio一直Download fastutil-x.x.x.jar
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/118637583?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_default&utm_relevant_index=1
Download fastutil-8.4.0-sources jar一直加载问题
https://blog.csdn.net/qq_48092631/article/details/119818131

java 的 ymodem 可以使用 github 上面的 YModemForAndroid,链接是 https://github.com/LeonXtp/YModemForAndroid

问题:

直接使用 YModemForAndroid 有以下几个问题

  • 在最后不足 1024 的数据时,应该按照 128 来发送,而不是 1024 来发送。 补足 1024 的是 xmodem-1k 的协议,ymodem 是按照 128 来发。
  • 正常 ymodem 不需要检查 md5,这边的实现需要调整一下。

参考:

当Android BLE遇上YModem
https://www.jianshu.com/p/d37eb7fa1d6e

【安卓相关】蓝牙基于Ymodem协议发送bin文件,对硬件设备进行升级。
https://www.jianshu.com/p/85784aa3143b

YMODEM协议简介
https://zhuanlan.zhihu.com/p/81133050

stm32 Bootloader设计(YModem协议)
https://www.amobbs.com/thread-5559677-1-1.html

Ymodem协议详解
https://blog.csdn.net/lcmsir/article/details/80550821/

Ymodem 协议详解
https://blog.csdn.net/huangdenan/article/details/103611081

BGAUpdate-Android
https://github.com/bingoogolapple/BGAUpdate-Android

YModemForAndroid
https://github.com/LeonXtp/YModemForAndroid

YModemlib_Android
https://github.com/ArdWang/YModemlib_Android

anroid ymodem 实现单片机固件升级
https://www.jianshu.com/p/c36e0d0211e4

MCUUpdate
https://github.com/h4de5ing/MCUUpdate

SerialPortLib
https://github.com/h4de5ing/SerialPortLib

ymodem
https://github.com/aesirot/ymodem

app 中修改

需要在 xml 文件中增加 system 相关设置,编译的时候,会有红字提示不能安装,这个提示不用管。

aosp 中修改

  1. 找到as编译出的 app,\项目名\app\build\outputs\apk\debug\app_debug.apk
  2. 在AOSP源码 packages/apps/下新建一个文件夹 GetImei
  3. 拷入附件的android.mk 拷入as 编译的 app_debug.apk,改名为 GetImei.apk
  4. 源码 \device\qcom\common\base.mk 中添加一行 PRODUCT_PACKAGES += GetImei
  5. 源码编译:
source build/envsetup.sh
lunch
(选择项目)
mmm packages/apps/GetImei/
  1. 拿到 \out\target\product\msm8937_32\system\app\GetImei\GetImei.apk

  2. 设备 root remount
adb root
adb disable-verity
adb reboot

adb root
adb remount
adb shell
#mkdir system/app/GetImei
#chmod 777 system/app/GetImei
#exit
adb push D:\GetImei.apk system/app/GetImei/
adb shell
#chmod 777 system/app/GetImei/GetImei.apk
#reboot

参考:

RK3399 Android7.1系统 自定义号码CMEI信息写入vendor_storage
https://blog.csdn.net/yafeixi/article/details/95626903

[RK3399][Android7.1] Vendor Storage区域知识及探讨
https://blog.csdn.net/kris_fei/article/details/79580845

通过设置菜单设置

  1. 下拉通知,点击设置,进入设置菜单。
  2. 进入应用和通知,查看全部应用。
  3. 点击 quickstep 或者 其他想要的 app.
  4. 高级,主屏幕应用,点击选中想要的 app 作为 launcher.

通过代码设置

这个网上有很多,修改 xml 文件。

参考:

Launcher安卓手机桌面怎么切换 Launcher手机桌面切换方法
https://product.pconline.com.cn/itbk/sjtx/sjwt/1711/10278395.html
Android 6.0替换原系统Launcher傻瓜教程
https://blog.csdn.net/kkle1994/article/details/85338328

定时器使用:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/timer.h>

#define SECOND_MAJOR 248

struct timer_list mt;

void mtimer_handler(struct timer_list*arg)
{
    printk("__%s__\n",__func__);
    mod_timer(&mt,jiffies + 10*HZ);
}

static int __init timer_init(void)
{   
//  init_timer(&mt);
//  init_timer(mt); 

    timer_setup(&mt,&mtimer_handler,0);
//  mt.function = mtimer_handler;
    mt.expires = jiffies + 10*HZ;

    add_timer(&mt);

    printk("[%s]\n",__func__);
    return 0;
}

module_init(timer_init);

static void __exit timer_exit(void)
{
    del_timer(&mt);
    printk("[%s]\n",__func__);

}

module_exit(timer_exit);

MODULE_AUTHOR("BW");
MODULE_LICENSE("GPL v2");

参考:

Linux内核定时器struct timer_list
https://www.cnblogs.com/Cqlismy/p/11838913.html

linux驱动之定时器的使用
https://www.cnblogs.com/hjj801006/p/4551378.html

linux下网卡链路状态检测方法
https://blog.csdn.net/wj31932/article/details/98087522

Linux驱动程序教程:如何编写简单的Linux设备驱动程序
https://blog.csdn.net/yeshennet/article/details/82290724

Linux驱动技术(七) _内核定时器与延迟工作
https://www.cnblogs.com/xiaojiang1025/p/6388604.html

定时器+工作队列 内核周期性任务的实现机制
https://blog.csdn.net/iteye_8149/article/details/82240560?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_antiscanv2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_antiscanv2&utm_relevant_index=2

工作队列(workqueue) create_workqueue/schedule_work/queue_work
https://blog.csdn.net/angle_birds/article/details/8448070

[Linux]softirq,tasklet和workqueue
https://zhuanlan.zhihu.com/p/361409809

Linux-workqueue讲解
https://www.cnblogs.com/vedic/p/11069249.html

【Linux内幕】schedule_work基本流程
https://blog.csdn.net/u012503639/article/details/107933857

(linux)schedule_delayed_work()
https://www.cnblogs.com/yanghong-hnu/p/4671350.html

linux驱动之定时任务timer,队列queue,小任务tasklet机制及用法
https://blog.csdn.net/u013256018/article/details/47803941

参考:

QT中倒计时显示 QLCDNumber
https://blog.csdn.net/zyc_csdn/article/details/78830577

【QT】利用QT做一个简单的LCD的倒计时效果
https://rong11417.blog.csdn.net/article/details/104573462?spm=1001.2101.3001.6650.4&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-4.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-4.pc_relevant_default&utm_relevant_index=9

QT下lcdNumber实现倒计时源代码
https://haigear.blog.csdn.net/article/details/120562850?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_default&utm_relevant_index=2

QLCDNumber制作的超简单计时器,按下空格键暂停。
https://blog.csdn.net/shensheng100221/article/details/103671469?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2.pc_relevant_default&utm_relevant_index=5

QLCDNumber使用
https://blog.csdn.net/xuancailinggan/article/details/77487705?spm=1001.2101.3001.6650.6&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-6.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-6.pc_relevant_default&utm_relevant_index=12

Qt|QTimer动态倒计时显示距离下一次任务执行剩余的时间
https://blog.csdn.net/kllo__/article/details/120221995?spm=1001.2101.3001.6650.10&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-10.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-10.pc_relevant_default&utm_relevant_index=16

关于QT倒计时的简单实现
https://blog.csdn.net/qq_43627385/article/details/100022968?spm=1001.2101.3001.6650.11&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-11.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-11.pc_relevant_default&utm_relevant_index=17

Qt使用QTimer实现倒计时功能
https://blog.csdn.net/kllo__/article/details/120200812?spm=1001.2101.3001.6650.15&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-15.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-15.pc_relevant_default&utm_relevant_index=21