10a7ce71fSopenharmony_ci/*
20a7ce71fSopenharmony_ci * Copyright (C) 2022 HiHope Open Source Organization .
30a7ce71fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
40a7ce71fSopenharmony_ci * you may not use this file except in compliance with the License.
50a7ce71fSopenharmony_ci * You may obtain a copy of the License at
60a7ce71fSopenharmony_ci *
70a7ce71fSopenharmony_ci *     http:// www.apache.org/licenses/LICENSE-2.0
80a7ce71fSopenharmony_ci *
90a7ce71fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
100a7ce71fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
110a7ce71fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
120a7ce71fSopenharmony_ci * See the License for the specific language governing permissions and
130a7ce71fSopenharmony_ci *
140a7ce71fSopenharmony_ci * limitations under the License.
150a7ce71fSopenharmony_ci */
160a7ce71fSopenharmony_ci
170a7ce71fSopenharmony_ci
180a7ce71fSopenharmony_ci#include "aht20.h"
190a7ce71fSopenharmony_ci
200a7ce71fSopenharmony_ci#include <stdio.h>
210a7ce71fSopenharmony_ci#include <string.h>
220a7ce71fSopenharmony_ci#include <unistd.h>
230a7ce71fSopenharmony_ci
240a7ce71fSopenharmony_ci#include "wifiiot_i2c.h"
250a7ce71fSopenharmony_ci#include "wifiiot_errno.h"
260a7ce71fSopenharmony_ci
270a7ce71fSopenharmony_ci#define AHT20_I2C_IDX WIFI_IOT_I2C_IDX_0
280a7ce71fSopenharmony_ci
290a7ce71fSopenharmony_ci#define AHT20_STARTUP_TIME     (20*1000) // 上电启动时间
300a7ce71fSopenharmony_ci#define AHT20_CALIBRATION_TIME (40*1000) // 初始化(校准)时间
310a7ce71fSopenharmony_ci#define AHT20_MEASURE_TIME     (75*1000) // 测量时间
320a7ce71fSopenharmony_ci
330a7ce71fSopenharmony_ci#define AHT20_DEVICE_ADDR   0x38
340a7ce71fSopenharmony_ci#define AHT20_READ_ADDR     ((0x38<<1)|0x1)
350a7ce71fSopenharmony_ci#define AHT20_WRITE_ADDR    ((0x38<<1)|0x0)
360a7ce71fSopenharmony_ci
370a7ce71fSopenharmony_ci#define AHT20_CMD_CALIBRATION       0xBE // 初始化(校准)命令
380a7ce71fSopenharmony_ci#define AHT20_CMD_CALIBRATION_ARG0  0x08
390a7ce71fSopenharmony_ci#define AHT20_CMD_CALIBRATION_ARG1  0x00
400a7ce71fSopenharmony_ci
410a7ce71fSopenharmony_ci/**
420a7ce71fSopenharmony_ci * 传感器在采集时需要时间,主机发出测量指令(0xAC)后,延时75毫秒以上再读取转换后的数据并判断返回的状态位是否正常。
430a7ce71fSopenharmony_ci * 若状态比特位[Bit7]为0代表数据可正常读取,为1时传感器为忙状态,主机需要等待数据处理完成。
440a7ce71fSopenharmony_ci **/
450a7ce71fSopenharmony_ci#define AHT20_CMD_TRIGGER       0xAC // 触发测量命令
460a7ce71fSopenharmony_ci#define AHT20_CMD_TRIGGER_ARG0  0x33
470a7ce71fSopenharmony_ci#define AHT20_CMD_TRIGGER_ARG1  0x00
480a7ce71fSopenharmony_ci
490a7ce71fSopenharmony_ci// 用于在无需关闭和再次打开电源的情况下,重新启动传感器系统,软复位所需时间不超过20 毫秒
500a7ce71fSopenharmony_ci#define AHT20_CMD_RESET      0xBA // 软复位命令
510a7ce71fSopenharmony_ci
520a7ce71fSopenharmony_ci#define AHT20_CMD_STATUS     0x71 // 获取状态命令
530a7ce71fSopenharmony_ci
540a7ce71fSopenharmony_ci/**
550a7ce71fSopenharmony_ci * STATUS 命令回复:
560a7ce71fSopenharmony_ci * 1. 初始化后触发测量之前,STATUS 只回复 1B 状态值;
570a7ce71fSopenharmony_ci * 2. 触发测量之后,STATUS 回复6B: 1B 状态值 + 2B 湿度 + 4b湿度 + 4b温度 + 2B 温度
580a7ce71fSopenharmony_ci *      RH = Srh / 2^20 * 100%
590a7ce71fSopenharmony_ci *      T  = St  / 2^20 * 200 - 50
600a7ce71fSopenharmony_ci **/
610a7ce71fSopenharmony_ci#define AHT20_STATUS_BUSY_SHIFT 7       // bit[7] Busy indication
620a7ce71fSopenharmony_ci#define AHT20_STATUS_BUSY_MASK  (0x1<<AHT20_STATUS_BUSY_SHIFT)
630a7ce71fSopenharmony_ci
640a7ce71fSopenharmony_ciuint8_t  aht20_status_busy(uint8_t status)
650a7ce71fSopenharmony_ci{
660a7ce71fSopenharmony_ci    return ((status & AHT20_STATUS_BUSY_MASK) >> (AHT20_STATUS_BUSY_SHIFT));
670a7ce71fSopenharmony_ci}
680a7ce71fSopenharmony_ci
690a7ce71fSopenharmony_ci#define AHT20_STATUS_MODE_SHIFT 5       // bit[6:5] Mode Status
700a7ce71fSopenharmony_ci#define AHT20_STATUS_MODE_MASK  (0x3<<AHT20_STATUS_MODE_SHIFT)
710a7ce71fSopenharmony_ci
720a7ce71fSopenharmony_ciuint8_t aht20_status_mode(uint8_t status)
730a7ce71fSopenharmony_ci{
740a7ce71fSopenharmony_ci    return ((status & AHT20_STATUS_MODE_MASK) >> (AHT20_STATUS_MODE_SHIFT))
750a7ce71fSopenharmony_ci}
760a7ce71fSopenharmony_ci                                        // bit[4] Reserved
770a7ce71fSopenharmony_ci#define AHT20_STATUS_CALI_SHIFT 3       // bit[3] CAL Enable
780a7ce71fSopenharmony_ci#define AHT20_STATUS_CALI_MASK  (0x1<<AHT20_STATUS_CALI_SHIFT)
790a7ce71fSopenharmony_ci
800a7ce71fSopenharmony_ciuint8_t aht20_status_cali(uint8_t status)
810a7ce71fSopenharmony_ci{
820a7ce71fSopenharmony_ci    return ((status & AHT20_STATUS_CALI_MASK) >> (AHT20_STATUS_CALI_SHIFT))
830a7ce71fSopenharmony_ci}
840a7ce71fSopenharmony_ci                                        // bit[2:0] Reserved
850a7ce71fSopenharmony_ci
860a7ce71fSopenharmony_ci#define AHT20_STATUS_RESPONSE_MAX 6
870a7ce71fSopenharmony_ci
880a7ce71fSopenharmony_ci#define AHT20_RESLUTION            (1<<20)  // 2^20
890a7ce71fSopenharmony_ci
900a7ce71fSopenharmony_ci#define AHT20_MAX_RETRY 10
910a7ce71fSopenharmony_ci#define TWO 2
920a7ce71fSopenharmony_ci#define THREE 3
930a7ce71fSopenharmony_ci#define FOUR 4
940a7ce71fSopenharmony_ci#define FIVE 5
950a7ce71fSopenharmony_ci#define EIGHT 8
960a7ce71fSopenharmony_ci#define FIFTY 50
970a7ce71fSopenharmony_ci#define ONE_HUNDRED 100
980a7ce71fSopenharmony_ci#define TWO_HUNDRED 200
990a7ce71fSopenharmony_ci
1000a7ce71fSopenharmony_cistatic uint32_t AHT20_Read(uint8_t* buffer, uint32_t buffLen)
1010a7ce71fSopenharmony_ci{
1020a7ce71fSopenharmony_ci    WifiIotI2cData data = { 0 };
1030a7ce71fSopenharmony_ci    data.receiveBuf = buffer;
1040a7ce71fSopenharmony_ci    data.receiveLen = buffLen;
1050a7ce71fSopenharmony_ci    uint32_t retval = I2cRead(AHT20_I2C_IDX, AHT20_READ_ADDR, &data);
1060a7ce71fSopenharmony_ci    if (retval != WIFI_IOT_SUCCESS) {
1070a7ce71fSopenharmony_ci        printf("I2cRead() failed, %0X!\n", retval);
1080a7ce71fSopenharmony_ci        return retval;
1090a7ce71fSopenharmony_ci    }
1100a7ce71fSopenharmony_ci    return WIFI_IOT_SUCCESS;
1110a7ce71fSopenharmony_ci}
1120a7ce71fSopenharmony_ci
1130a7ce71fSopenharmony_cistatic uint32_t AHT20_Write(uint8_t* buffer, uint32_t buffLen)
1140a7ce71fSopenharmony_ci{
1150a7ce71fSopenharmony_ci    WifiIotI2cData data = { 0 };
1160a7ce71fSopenharmony_ci    data.sendBuf = buffer;
1170a7ce71fSopenharmony_ci    data.sendLen = buffLen;
1180a7ce71fSopenharmony_ci    uint32_t retval = I2cWrite(AHT20_I2C_IDX, AHT20_WRITE_ADDR, &data);
1190a7ce71fSopenharmony_ci    if (retval != WIFI_IOT_SUCCESS) {
1200a7ce71fSopenharmony_ci        printf("I2cWrite(%02X) failed, %0X!\n", buffer[0], retval);
1210a7ce71fSopenharmony_ci        return retval;
1220a7ce71fSopenharmony_ci    }
1230a7ce71fSopenharmony_ci    return WIFI_IOT_SUCCESS;
1240a7ce71fSopenharmony_ci}
1250a7ce71fSopenharmony_ci
1260a7ce71fSopenharmony_ci// 发送获取状态命令
1270a7ce71fSopenharmony_cistatic uint32_t AHT20_StatusCommand(void)
1280a7ce71fSopenharmony_ci{
1290a7ce71fSopenharmony_ci    uint8_t statusCmd[] = { AHT20_CMD_STATUS };
1300a7ce71fSopenharmony_ci    return AHT20_Write(statusCmd, sizeof(statusCmd));
1310a7ce71fSopenharmony_ci}
1320a7ce71fSopenharmony_ci
1330a7ce71fSopenharmony_ci// 发送软复位命令
1340a7ce71fSopenharmony_cistatic uint32_t AHT20_ResetCommand(void)
1350a7ce71fSopenharmony_ci{
1360a7ce71fSopenharmony_ci    uint8_t resetCmd[] = {AHT20_CMD_RESET};
1370a7ce71fSopenharmony_ci    return AHT20_Write(resetCmd, sizeof(resetCmd));
1380a7ce71fSopenharmony_ci}
1390a7ce71fSopenharmony_ci
1400a7ce71fSopenharmony_ci// 发送初始化校准命令
1410a7ce71fSopenharmony_cistatic uint32_t AHT20_CalibrateCommand(void)
1420a7ce71fSopenharmony_ci{
1430a7ce71fSopenharmony_ci    uint8_t clibrateCmd[] = {AHT20_CMD_CALIBRATION, AHT20_CMD_CALIBRATION_ARG0, AHT20_CMD_CALIBRATION_ARG1};
1440a7ce71fSopenharmony_ci    return AHT20_Write(clibrateCmd, sizeof(clibrateCmd));
1450a7ce71fSopenharmony_ci}
1460a7ce71fSopenharmony_ci
1470a7ce71fSopenharmony_ci// 读取温湿度值之前, 首先要看状态字的校准使能位Bit[3]是否为 1(通过发送0x71可以获取一个字节的状态字),
1480a7ce71fSopenharmony_ci// 如果不为1,要发送0xBE命令(初始化),此命令参数有两个字节, 第一个字节为0x08,第二个字节为0x00。
1490a7ce71fSopenharmony_ciuint32_t AHT20_Calibrate(void)
1500a7ce71fSopenharmony_ci{
1510a7ce71fSopenharmony_ci    uint32_t retval = 0;
1520a7ce71fSopenharmony_ci    uint8_t buffer[AHT20_STATUS_RESPONSE_MAX] = { AHT20_CMD_STATUS };
1530a7ce71fSopenharmony_ci    memset_s(&buffer, sizeof(buffer), 0x0, sizeof(buffer));
1540a7ce71fSopenharmony_ci
1550a7ce71fSopenharmony_ci    retval = AHT20_StatusCommand();
1560a7ce71fSopenharmony_ci    if (retval != WIFI_IOT_SUCCESS) {
1570a7ce71fSopenharmony_ci        return retval;
1580a7ce71fSopenharmony_ci    }
1590a7ce71fSopenharmony_ci
1600a7ce71fSopenharmony_ci    retval = AHT20_Read(buffer, sizeof(buffer));
1610a7ce71fSopenharmony_ci    if (retval != WIFI_IOT_SUCCESS) {
1620a7ce71fSopenharmony_ci        return retval;
1630a7ce71fSopenharmony_ci    }
1640a7ce71fSopenharmony_ci
1650a7ce71fSopenharmony_ci    if (AHT20_STATUS_BUSY(buffer[0]) || !AHT20_STATUS_CALI(buffer[0])) {
1660a7ce71fSopenharmony_ci        retval = AHT20_ResetCommand();
1670a7ce71fSopenharmony_ci        if (retval != WIFI_IOT_SUCCESS) {
1680a7ce71fSopenharmony_ci            return retval;
1690a7ce71fSopenharmony_ci        }
1700a7ce71fSopenharmony_ci        usleep(AHT20_STARTUP_TIME);
1710a7ce71fSopenharmony_ci        retval = AHT20_CalibrateCommand();
1720a7ce71fSopenharmony_ci        usleep(AHT20_CALIBRATION_TIME);
1730a7ce71fSopenharmony_ci        return retval;
1740a7ce71fSopenharmony_ci    }
1750a7ce71fSopenharmony_ci
1760a7ce71fSopenharmony_ci    return WIFI_IOT_SUCCESS;
1770a7ce71fSopenharmony_ci}
1780a7ce71fSopenharmony_ci
1790a7ce71fSopenharmony_ci// 发送 触发测量 命令,开始测量
1800a7ce71fSopenharmony_ciuint32_t AHT20_StartMeasure(void)
1810a7ce71fSopenharmony_ci{
1820a7ce71fSopenharmony_ci    uint8_t triggerCmd[] = {AHT20_CMD_TRIGGER, AHT20_CMD_TRIGGER_ARG0, AHT20_CMD_TRIGGER_ARG1};
1830a7ce71fSopenharmony_ci    return AHT20_Write(triggerCmd, sizeof(triggerCmd));
1840a7ce71fSopenharmony_ci}
1850a7ce71fSopenharmony_ci
1860a7ce71fSopenharmony_ci// 接收测量结果,拼接转换为标准值
1870a7ce71fSopenharmony_ciuint32_t AHT20_GetMeasureResult(float* temp, float* humi)
1880a7ce71fSopenharmony_ci{
1890a7ce71fSopenharmony_ci    uint32_t retval = 0, i = 0;
1900a7ce71fSopenharmony_ci    if (temp == NULL || humi == NULL) {
1910a7ce71fSopenharmony_ci        return WIFI_IOT_FAILURE;
1920a7ce71fSopenharmony_ci    }
1930a7ce71fSopenharmony_ci
1940a7ce71fSopenharmony_ci    uint8_t buffer[AHT20_STATUS_RESPONSE_MAX] = { 0 };
1950a7ce71fSopenharmony_ci    memset_s(&buffer, sizeof(buffer), 0x0, sizeof(buffer));
1960a7ce71fSopenharmony_ci    retval = AHT20_Read(buffer, sizeof(buffer));  // recv status command result
1970a7ce71fSopenharmony_ci    if (retval != WIFI_IOT_SUCCESS) {
1980a7ce71fSopenharmony_ci        return retval;
1990a7ce71fSopenharmony_ci    }
2000a7ce71fSopenharmony_ci
2010a7ce71fSopenharmony_ci    for (i = 0; AHT20_STATUS_BUSY(buffer[0]) && i < AHT20_MAX_RETRY; i++) {
2020a7ce71fSopenharmony_ci        usleep(AHT20_MEASURE_TIME);
2030a7ce71fSopenharmony_ci        retval = AHT20_Read(buffer, sizeof(buffer));  // recv status command result
2040a7ce71fSopenharmony_ci        if (retval != WIFI_IOT_SUCCESS) {
2050a7ce71fSopenharmony_ci            return retval;
2060a7ce71fSopenharmony_ci        }
2070a7ce71fSopenharmony_ci    }
2080a7ce71fSopenharmony_ci    if (i >= AHT20_MAX_RETRY) {
2090a7ce71fSopenharmony_ci        printf("AHT20 device always busy!\r\n");
2100a7ce71fSopenharmony_ci        return WIFI_IOT_FAILURE;
2110a7ce71fSopenharmony_ci    }
2120a7ce71fSopenharmony_ci
2130a7ce71fSopenharmony_ci    uint32_t humiRaw = buffer[1];
2140a7ce71fSopenharmony_ci    humiRaw = (humiRaw << EIGHT) | buffer[TWO];
2150a7ce71fSopenharmony_ci    humiRaw = (humiRaw << FOUR) | ((buffer[THREE] & 0xF0) >> FOUR);
2160a7ce71fSopenharmony_ci    *humi = humiRaw / (float)AHT20_RESLUTION * ONE_HUNDRED;
2170a7ce71fSopenharmony_ci
2180a7ce71fSopenharmony_ci    uint32_t tempRaw = buffer[3] & 0x0F;
2190a7ce71fSopenharmony_ci    tempRaw = (tempRaw << EIGHT) | buffer[FOUR];
2200a7ce71fSopenharmony_ci    tempRaw = (tempRaw << EIGHT) | buffer[FIVE];
2210a7ce71fSopenharmony_ci    *temp = tempRaw / (float)AHT20_RESLUTION * TWO_HUNDRED - FIFTY;
2220a7ce71fSopenharmony_ci    return WIFI_IOT_SUCCESS;
2230a7ce71fSopenharmony_ci}
224