Linux/Android driver驱动 BL5372

一、Linux驱动大全

1001: 时钟驱动 BL5372

1.硬件
BL5372 RTC
https://www.belling.com.cn/product_info.html?id=65

驱动代码如下(C):

/*
 * An I2C driver for Beilin BL5372 RTC
 */

//#define DEBUG           /* Enable dev_dbg */

#include <linux/i2c.h>
#include <linux/bcd.h>
#include <linux/rtc.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>

#define DRV_VERSION "0.0.2"
#define DRIVER_NAME     "rtc-bl5372"

#define TIME24 1
#define RS5C_ADDR(R)        (((R) << 4) | 0)
#define RS5C372_REG_SECS    0
#define RS5C372_REG_MINS    1
#define RS5C372_REG_HOURS   2
#define RS5C372_REG_WDAY    3
#define RS5C372_REG_DAY     4
#define RS5C372_REG_MONTH   5
#define RS5C372_REG_YEAR    6
#define RS5C372_REG_TRIM    7
#define RS5C_REG_ALARM_A_MIN    8           /* or ALARM_W */
#define RS5C_REG_ALARM_A_HOURS  9
#define RS5C_REG_ALARM_A_WDAY   10

#define RS5C_REG_ALARM_B_MIN    11          /* or ALARM_D */
#define RS5C_REG_ALARM_B_HOURS  12
#define RS5C_REG_ALARM_B_WDAY   13          /* (ALARM_B only) */
#define RS5C_REG_CTRL1          14
#define RS5C_REG_CTRL2          15

struct bl5372 {
    struct rtc_device *rtc;
    struct i2c_client *client;
    bool irq_registered;
};

static int bl5372_clear_int_flags(struct bl5372 * bl5372);

static unsigned rs5c_reg2hr(unsigned reg)
{
#if TIME24
    return bcd2bin(reg & 0x3f);
#else
    unsigned    hour;
    hour = bcd2bin(reg & 0x1f);
    if (hour == 12)
        hour = 0;
    if (reg & 0x20)
        hour += 12;
    return hour;
#endif
}

static unsigned rs5c_hr2reg(unsigned hour)
{
#if TIME24
    return bin2bcd(hour);

#else
    if (hour > 12)
        return 0x20 | bin2bcd(hour - 12);
    if (hour == 12)
        return 0x20 | bin2bcd(12);
    if (hour == 0)
        return bin2bcd(12);
    return bin2bcd(hour);
#endif
}

/* caller holds rtc->ops_lock */
static int bl5372_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{
    int err = 0;
    struct bl5372 *bl5372 = i2c_get_clientdata(client);
    unsigned char buf[7] = { RS5C_ADDR(RS5C372_REG_SECS) };

    struct i2c_msg msgs[] = {
        {/* setup read ptr */
            .addr = client->addr,
            .flags = 0,/* write */
            .len = 1,
            .buf = buf
        },
        {/* read the sec,min,hour,week,day,month,year */
            .addr = client->addr,
            .flags = I2C_M_RD,/* read */
            .len = 7,
            .buf = buf
        },
    };

    /* read registers */
    err = i2c_transfer(client->adapter, msgs, 2);
    if (err != 2) {
        dev_err(&client->dev, "[%s:%d]: read error\n", __func__, __LINE__);
        err = -EIO;
        goto EXIT_PROC;
    }

    tm->tm_sec = bcd2bin(buf[0] & 0x7f);
    tm->tm_min = bcd2bin(buf[1] & 0x7f);
    tm->tm_hour = rs5c_reg2hr(buf[2]);
    tm->tm_mday = bcd2bin(buf[4] & 0x7f);;
    tm->tm_wday = bcd2bin(buf[3] & 0x7f);
    tm->tm_mon = rs5c_reg2hr(buf[5])-1;
    tm->tm_year = bcd2bin(buf[6] & 0x7f)+100;

    /* the clock can give out invalid datetime, but we cannot return
     * -EINVAL otherwise hwclock will refuse to set the time on bootup.
     */
    if (rtc_valid_tm(tm) < 0)
        dev_err(&client->dev, "retrieved date/time is not valid.\n");

EXIT_PROC:

    return err;
}

/* caller holds rtc->ops_lock */
static int bl5372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
    struct bl5372 *bl5372 = i2c_get_clientdata(client);
    int err = 0;
    unsigned char buf[7];

    dev_dbg(&(client->dev), "%s secs=%d, mins=%d, "
        "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
        "write", tm->tm_sec, tm->tm_min,
        tm->tm_hour, tm->tm_mday,
        tm->tm_mon, tm->tm_year, tm->tm_wday);

    buf[0] = RS5C_ADDR(RS5C_REG_CTRL2);
    struct i2c_msg msgs2[] = {
        {/* setup read  */
            .addr = client->addr,
            .len = 1,
            .buf = buf
        },
        {/* read is_24hour */
            .addr = client->addr,
            .flags = I2C_M_RD,
            .len = 1,
            .buf = buf
        },
    };
    /* read registers */
    err = i2c_transfer(client->adapter, msgs2, 2);
    if (err != 2) {
        dev_err(&client->dev, "[%s:%d]: read error\n", __func__, __LINE__);
        err = -EIO;
        goto EXIT_PROC;
    }

    if((buf[0]&0x20)== 0)   /* 12 hour system */
    {
        /* use 24 hour system */
        buf[0] = RS5C_ADDR(RS5C_REG_CTRL2);
        buf[1] |= (1<<5);
        err = i2c_master_send(client, buf, 2);
        if(0 != err)
        {
            goto EXIT_PROC;
        }
    }

    /* hours, minutes and seconds */
    buf[0] = bin2bcd(tm->tm_sec);
    buf[1] = bin2bcd(tm->tm_min);
    buf[2] = rs5c_hr2reg(tm->tm_hour);
    buf[3] = bin2bcd(tm->tm_wday & 0x07); //week 0~6
    buf[4] = bin2bcd(tm->tm_mday);
    buf[5] = bin2bcd(tm->tm_mon)+1;// 0~11
    tm->tm_year -= 100;
    buf[6] = bin2bcd(tm->tm_year % 100);// start at 1900  2018=>118

    err = i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_SECS),   buf[0]);
    if(0 != err)
    {
        goto EXIT_PROC;
    }
    err = i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_MINS) ,  buf[1]);
    if(0 != err)
    {
        goto EXIT_PROC;
    }
    err = i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_HOURS) , buf[2]);
    if(0 != err)
    {
        goto EXIT_PROC;
    }
    err = i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_WDAY) ,  buf[3]);
    if(0 != err)
    {
        goto EXIT_PROC;
    }
    err = i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_DAY) ,   buf[4]);
    if(0 != err)
    {
        goto EXIT_PROC;
    }
    err = i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_MONTH) , buf[5]);
    if(0 != err)
    {
        goto EXIT_PROC;
    }
    err = i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_YEAR) ,  buf[6]);
    if(0 != err)
    {
        goto EXIT_PROC;
    }

EXIT_PROC:

    return err;
}

/* The caller(rtc_mgr.ioctl) holds rtc->ops_lock */
static int bl5372_set_alarm(struct bl5372 *bl5372, struct rtc_wkalrm *t)
{
    int err_out = 0, err_ret;
    struct i2c_client *client = bl5372->client;
    u8 regData;

    dev_dbg(&(client->dev), "%s secs=%d, mins=%d, "
        "hours=%d, mday=%d, enabled=%d, pending=%d\n",
        "alarm set", t->time.tm_sec, t->time.tm_min,
        t->time.tm_hour, t->time.tm_mday,
        t->enabled, t->pending);

    /* clean interrupt flags */
    err_ret = bl5372_clear_int_flags(bl5372);
    if(0 != err_ret)
    {
        err_out = err_ret;
        goto EXIT_PROC;
    }

    if(t->enabled)
    {
        /* alarm_A.minute */
        regData = bin2bcd(t->time.tm_min);
        err_ret = i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C_REG_ALARM_A_MIN), regData);
        if(0 != err_ret)
        {
            err_out = err_ret;
            pr_err("[%s:%d]i2c w err %d\n", __FUNCTION__, __LINE__, err_ret);
            goto EXIT_PROC;
        }
        /* alarm_A.hour */
        regData = bin2bcd(t->time.tm_hour);
        err_ret = i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C_REG_ALARM_A_HOURS), regData);
        if(0 != err_ret)
        {
            err_out = err_ret;
            pr_err("[%s:%d]i2c w err %d\n", __FUNCTION__, __LINE__, err_ret);
            goto EXIT_PROC;
        }
    }

    /* enable ALARM A? */
    err_ret = i2c_smbus_read_byte_data(client, RS5C_ADDR(RS5C_REG_CTRL1));
    if(0 > err_ret)
    {
        err_out = err_ret;
        pr_err("[%s:%d]i2c r err %d\n", __FUNCTION__, __LINE__, err_ret);
        goto EXIT_PROC;
    }
    regData = err_ret;
    if(t->enabled)
    {
        regData |= (0b1 << 7);
    }
    else
    {
        regData &= ~((0b1 << 7));
    }
    err_ret = i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C_REG_CTRL1), regData);
    if(0 != err_ret)
    {
        err_out = err_ret;
        pr_err("[%s:%d]i2c w err %d\n", __FUNCTION__, __LINE__, err_ret);
        goto EXIT_PROC;
    }

EXIT_PROC:

    return err_out;
}

/* caller holds rtc->ops_lock */
static int bl5372_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
    int err = 0;
    struct bl5372 *bl5372 = i2c_get_clientdata(to_i2c_client(dev));
    void __user *uarg = (void __user *)arg;

    switch (cmd) {
        case RTC_WKALM_SET_DIRECTLY: {
            struct rtc_wkalrm alarm;
            if (copy_from_user(&alarm, uarg, sizeof(alarm))){
                return -EFAULT;
            }
            err = bl5372_set_alarm(bl5372, &alarm);
            break;
        }
    default:
        err = -ENOIOCTLCMD;
    }

    return err;
}

/* caller holds rtc->ops_lock */
static int bl5372_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
    return bl5372_get_datetime(to_i2c_client(dev), tm);
}

/* caller holds rtc->ops_lock */
static int bl5372_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
    return bl5372_set_datetime(to_i2c_client(dev), tm);
}

/* caller holds rtc->ops_lock */
static int bl5372_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
{
    struct bl5372 *bl5372 = i2c_get_clientdata(to_i2c_client(dev));
    return 0;
}

/* caller holds rtc->ops_lock */
static int bl5372_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
{
    struct bl5372 *bl5372 = i2c_get_clientdata(to_i2c_client(dev));
    return 0;
}

/* caller holds rtc->ops_lock */
static int bl5372_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
    struct bl5372 *bl5372 = i2c_get_clientdata(to_i2c_client(dev));

    return 0;
}

static int bl5372_clear_int_flags(struct bl5372 * bl5372)
{
    int err_out = 0, err_ret;
    u8 regData;
    struct i2c_client * client = bl5372->client;

    /* clean ALARM A interrupt flags */
    err_ret = i2c_smbus_read_byte_data(client, RS5C_ADDR(RS5C_REG_CTRL2));
    if(0 > err_ret)
    {
        err_out = err_ret;
        pr_err("[%s:%d]i2c r err %d\n", __FUNCTION__, __LINE__, err_ret);
        goto EXIT_PROC;
    }
    regData = err_ret;
    regData &= ~((0b1 << 2) | (0b1 << 1));
    err_ret = i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C_REG_CTRL2), regData);
    if(0 != err_ret)
    {
        err_out = err_ret;
        pr_err("[%s:%d]i2c w err %d\n", __FUNCTION__, __LINE__, err_ret);
        goto EXIT_PROC;
    }

EXIT_PROC:

    return err_out;
}

/* thread context, should lock rtc->ops_lock */
static irqreturn_t bl5372_irq(int irq, void *dev_id)
{
    struct bl5372       *bl5372 = dev_id;
    int err;
    struct mutex        *lock = &(bl5372->rtc->ops_lock);

    dev_dbg(&(bl5372->client->dev), "bl5372_irq\n");

    mutex_lock(lock);

    err = bl5372_clear_int_flags(bl5372);
    if(0 > err)
    {
        dev_err(&(bl5372->client->dev), "clr int err %d\n", err);
    }

    mutex_unlock(lock);

    return IRQ_HANDLED;
}

static const struct rtc_class_ops bl5372_rtc_ops = {
    .ioctl      = bl5372_rtc_ioctl,
    .read_time  = bl5372_rtc_read_time,
    .set_time   = bl5372_rtc_set_time,
    .read_alarm             = bl5372_rtc_getalarm,
    .set_alarm              = bl5372_rtc_setalarm,
    .alarm_irq_enable       = bl5372_rtc_alarm_irq_enable
};

static int bl5372_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int err_ret = 0;
    struct bl5372 *bl5372 = NULL;

    if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
    {
        err_ret = -ENODEV;
        goto EXIT_PROC;
    }

    /* check whether the device exists */
    {
        unsigned char buf[2];
        buf[0] = 0x00;
        struct i2c_msg detect_msg[] = {
            {
                .addr = client->addr,
                .len = 1,
                .buf = buf
            },
            {
                .addr = client->addr,
                .flags = I2C_M_RD,
                .len = 1,
                .buf = buf
            },
        };
        /* read registers */
        err_ret = i2c_transfer(client->adapter, detect_msg, sizeof(detect_msg)/sizeof(detect_msg[0]));
        if(sizeof(detect_msg)/sizeof(detect_msg[0]) != err_ret)
        {
            err_ret = -ENODEV;
            goto EXIT_PROC;
        }
        err_ret = 0;
    }

    /* Memory allocated with this function is automatically freed on driver detach */
    bl5372 = devm_kzalloc(&client->dev, sizeof(*bl5372), GFP_KERNEL);
    if (!bl5372)
    {
        err_ret = -ENOMEM;
        goto EXIT_PROC;
    }

    device_init_wakeup(&client->dev, 1);
    bl5372->client = client;
    i2c_set_clientdata(client, bl5372);

    /* The rtc_device returned from this function are automatically freed on driver detach. */
    bl5372->rtc = devm_rtc_device_register(&client->dev, DRIVER_NAME, &bl5372_rtc_ops, THIS_MODULE);
    if (IS_ERR(bl5372->rtc))
    {
        err_ret = PTR_ERR(bl5372->rtc);
        goto EXIT_PROC;
    }

    /* set 24hour system, no 32KHz output, clean interrupt flags */
    err_ret = i2c_smbus_read_byte_data(client, RS5C_ADDR(RS5C_REG_CTRL2));
    if(0 > err_ret)
    {
        pr_err("[%s:%d]i2c r err %d\n", __FUNCTION__, __LINE__, err_ret);
        goto EXIT_PROC;
    }
    u8 regData = err_ret;
    regData |= (0b1 << 5) | (0b1 << 3);
    regData &= ~((0b1 << 2) | (0b1 << 1));
    err_ret = i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C_REG_CTRL2), regData);
    if(0 != err_ret)
    {
        pr_err("[%s:%d]i2c w err %d\n", __FUNCTION__, __LINE__, err_ret);
        goto EXIT_PROC;
    }

    /* set alarm base param */
    do {
        // week 1~7
        err_ret = i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C_REG_ALARM_A_WDAY), 0x7F);
        if(0 != err_ret)
        {
            pr_err("[%s:%d]i2c w err %d\n", __FUNCTION__, __LINE__, err_ret);
            break;
        }
        // alarm A intterrupt to INTRA, no periodic output; low active level as interrupt level;
        err_ret = i2c_smbus_read_byte_data(client, RS5C_ADDR(RS5C_REG_CTRL1));
        if(0 > err_ret)
        {
            pr_err("[%s:%d]i2c r err %d\n", __FUNCTION__, __LINE__, err_ret);
            break;
        }
        u8 regData = err_ret;
        regData |= (0b11 << 4);
        regData &= ~((0b111));  /* periodic interrupt pin outputs high level. */
        err_ret = i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C_REG_CTRL1), regData);
        if(0 != err_ret)
        {
            pr_err("[%s:%d]i2c w err %d\n", __FUNCTION__, __LINE__, err_ret);
            break;
        }
    }while(false);
    err_ret = 0;    /* alarm err can be ignored. */

    dev_dbg(&(client->dev), "irq: %d\n", client->irq);
    if(0 < client->irq)
    {
        /* IRQs requested with this function will be automatically freed on driver detach */
        err_ret = devm_request_threaded_irq(&(client->dev), client->irq, NULL, bl5372_irq,
            (IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_FALLING), client->name, bl5372);
        if(0 != err_ret)
        {
            dev_err(&(client->dev), "unable to request IRQ(%d),err %d!\n", client->irq, err_ret);
            goto EXIT_PROC;
        }
        bl5372->irq_registered = true;
    }

EXIT_PROC:

    if(0 != err_ret)
    {
    }

    return err_ret;
}

static int bl5372_remove(struct i2c_client *client)
{
    int err_ret;
    struct bl5372 *bl5372 = i2c_get_clientdata(client);

    if(true == bl5372->irq_registered)
    {
        devm_free_irq(&(client->dev), client->irq, bl5372);
        bl5372->irq_registered = false;
    }

    /* clean interrupt flags */
    err_ret = bl5372_clear_int_flags(bl5372);
    if(0 != err_ret)
    {
    }

    return 0;
}

static const struct i2c_device_id bl5372_id[] = {
    { "bl5372", 0 },
    { }
};
MODULE_DEVICE_TABLE(i2c, bl5372_id);

#ifdef CONFIG_OF
static const struct of_device_id bl5372_of_match[] = {
    { .compatible = "beilin,bl5372" },
    {}
};
MODULE_DEVICE_TABLE(of, bl5372_of_match);
#endif

static struct i2c_driver bl5372_driver = {
    .driver     = {
        .name   = DRIVER_NAME,
        .owner  = THIS_MODULE,
        .of_match_table = of_match_ptr(bl5372_of_match),
    },
    .probe      = bl5372_probe,
    .remove     = bl5372_remove,
    .id_table   = bl5372_id,
};

module_i2c_driver(bl5372_driver);

MODULE_AUTHOR("nomivision");
MODULE_DESCRIPTION("Beilin BL5372 RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);


  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
# -*- coding: UTF-8 -*- from lib2to3.pgen2 import driver from appium import webdriver from appium.webdriver.common.appiumby import AppiumBy el1 = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="通讯录") el1.click() el2 = driver.find_element(by=AppiumBy.XPATH, value="/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout[1]/android.widget.FrameLayout/android.widget.ListView/android.widget.FrameLayout[3]/android.widget.RelativeLayout") el2.click() el3 = driver.find_element(by=AppiumBy.XPATH, value="/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout[2]/android.view.ViewGroup/android.view.ViewGroup/androidx.recyclerview.widget.RecyclerView/android.view.ViewGroup[1]/android.widget.TextView") el3.click() el4 = driver.find_element(by=AppiumBy.XPATH, value="/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout[2]/android.view.ViewGroup/android.view.ViewGroup/androidx.recyclerview.widget.RecyclerView/android.view.ViewGroup[8]") el4.click() el5 = driver.find_element(by=AppiumBy.XPATH, value="/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout[2]/android.view.ViewGroup/android.view.ViewGroup/androidx.recyclerview.widget.RecyclerView/android.view.ViewGroup[11]") el5.click()
06-08
根据你提供的代码,看起来你使用了 `lib2to3.pgen2.driver` 模块中的 `find_element` 方法。但是,`lib2to3.pgen2.driver` 模块实际上并没有这个方法,所以出现了 `AttributeError`。 我猜测你可能是想使用 Appium 的 `driver.find_element` 方法。如果是这样的话,你需要更改你的代码来正确导入 `appium.webdriver` 模块并使用它的 `driver` 属性。具体的修改如下: ```python # -*- coding: UTF-8 -*- from appium import webdriver from appium.webdriver.common.appiumby import AppiumBy # 创建 Appium driver desired_caps = {} desired_caps['platformName'] = 'Android' # 添加其他的 desired capabilities 选项... driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps) # 执行测试操作 el1 = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="通讯录") el1.click() el2 = driver.find_element(by=AppiumBy.XPATH, value="/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout[1]/android.widget.FrameLayout/android.widget.ListView/android.widget.FrameLayout[3]/android.widget.RelativeLayout") el2.click() el3 = driver.find_element(by=AppiumBy.XPATH, value="/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout[2]/android.view.ViewGroup/android.view.ViewGroup/androidx.recyclerview.widget.RecyclerView/android.view.ViewGroup[1]/android.widget.TextView") el3.click() el4 = driver.find_element(by=AppiumBy.XPATH, value="/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout[2]/android.view.ViewGroup/android.view.ViewGroup/androidx.recyclerview.widget.RecyclerView/android.view.ViewGroup[8]") el4.click() el5 = driver.find_element(by=AppiumBy.XPATH, value="/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout[2]/android.view.ViewGroup/android.view.ViewGroup/androidx.recyclerview.widget.RecyclerView/android.view.ViewGroup[11]") el5.click() # 关闭 driver driver.quit() ``` 注意,这里我使用了 `appium.webdriver` 模块的 `webdriver.Remote` 方法来创建 driver,然后使用 `driver.find_element` 方法来查找元素。最后,在测试结束后,我也关闭了 driver。你需要根据你的具体情况修改代码中的 `desired_caps` 和元素定位方式等内容。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值