From 8df7c2928393a804db45a685311df14bf8a76f45 Mon Sep 17 00:00:00 2001
From: guowenxue <guowenxue@gmail.com>
Date: Tue, 12 Mar 2024 17:20:28 +0800
Subject: [PATCH] Add W25Q SPI Norflash modules support

---
 modules/sht20.c |  291 ++++++++++++++++++++++++++++++++++++++++------------------
 1 files changed, 201 insertions(+), 90 deletions(-)

diff --git a/modules/sht20.c b/modules/sht20.c
index d84877f..c3aa745 100644
--- a/modules/sht20.c
+++ b/modules/sht20.c
@@ -20,7 +20,6 @@
  *                  dtoverlay=i2c1,pins_2_3
  *
  ********************************************************************************/
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -39,11 +38,37 @@
 #include <linux/i2c.h>
 #include <linux/i2c-dev.h>
 
-int i2c_write(int fd, uint8_t slave_addr, uint8_t *data, int len);
-int i2c_read(int fd, uint8_t slave_addr, uint8_t *buf, int size);
-int sht20_checksum(uint8_t *data, int len, int8_t checksum);
+/* SHT2X 7-bit I2C slave address */
+#define SHT2X_CHIPADDR                  0x40
+
+/* SHT2X trigger command */
+#define SOFTRESET                       0xFE
+#define TRIGGER_TEMPERATURE_NO_HOLD     0xF3
+#define TRIGGER_HUMIDITY_NO_HOLD        0xF5
+
+/* Linux /dev/i2c-x device program API mode */
+enum
+{
+    MODE_IOCTL, /* I2C device API use ioctl() */
+    MODE_RDWR,  /* I2C device API use read()/write() */
+};
+
+typedef struct sht2x_s
+{
+    char           *dev;    /* SHT20 connect I2C device, /dev/i2c-N */
+    int             addr;   /* SHT20 7-bits slave address */
+    int             fd;     /* File description */
+    int             mode;   /* I2C device API use read/write or ioctl mode */
+} sht2x_t;
+
+int sht2x_init(sht2x_t *sht2x);
+int sht2x_get_serialnumber(sht2x_t *sht2x, uint8_t *serialnumber, int size);
+int sht2x_get_temp_humidity(sht2x_t *sht2x, float *temp, float *rh);
+
 static inline void msleep(unsigned long ms);
 static inline void dump_buf(const char *prompt, uint8_t *buf, int size);
+static int i2c_write(sht2x_t *sht2x, uint8_t *data, int len);
+static int i2c_read(sht2x_t *sht2x, uint8_t *buf, int size);
 
 static inline void banner(const char *progname)
 {
@@ -58,6 +83,7 @@
     printf(" %s is SHT20 temperature and humidity sensor program. \n", progname);
 
     printf(" -d[device  ]  Specify I2C device, such as /dev/i2c-1\n");
+    printf(" -m[mode    ]  Specify API mode, 0 for ioctl and 1 for read()/write()\n");
     printf(" -h[help    ]  Display this help information\n");
     printf(" -v[version ]  Display the program version\n");
 
@@ -68,14 +94,15 @@
 
 int main(int argc, char **argv)
 {
-    int             fd, rv;
+    int             rv;
     float           temp, rh;
-    char           *dev = "/dev/i2c-1";
-    char           *progname=NULL;
-    uint8_t         buf[4];
+    uint8_t         serialnumber[8];
+    char            *progname=NULL;
+    sht2x_t         sht2x;
 
     struct option long_options[] = {
         {"device", required_argument, NULL, 'd'},
+        {"mode", required_argument, NULL, 'm'},
         {"version", no_argument, NULL, 'v'},
         {"help", no_argument, NULL, 'h'},
         {NULL, 0, NULL, 0}
@@ -83,13 +110,21 @@
 
     progname = basename(argv[0]);
 
+    memset(&sht2x, 0, sizeof(sht2x));
+    sht2x.addr = SHT2X_CHIPADDR;
+    sht2x.dev = "/dev/i2c-1";
+
     /* Parser the command line parameters */
-    while ((rv = getopt_long(argc, argv, "d:vh", long_options, NULL)) != -1)
+    while ((rv = getopt_long(argc, argv, "d:m:vh", long_options, NULL)) != -1)
     {
         switch (rv)
         {
             case 'd': /*  Set I2C device path: /dev/i2c-1 */
-                dev = optarg;
+                sht2x.dev = optarg;
+                break;
+
+            case 'm': /*  Set I2C API mode: 0,1 */
+                sht2x.mode = atoi(optarg) ? MODE_RDWR : MODE_IOCTL;
                 break;
 
             case 'v':  /*  Get software version */
@@ -105,108 +140,165 @@
         }
     }
 
-
-    /*+--------------------------------+
-     *|     open /dev/i2c-x device     |
-     *+--------------------------------+*/
-    if( (fd=open(dev, O_RDWR)) < 0)
+    if( sht2x_init(&sht2x) < 0 )
     {
-        printf("i2c device '%s' open failed: %s\n", dev, strerror(errno));
+        printf("SHT2x initialize failure, maybe device not present!\n");
+        return 1;
+    }
+
+    if( sht2x_get_serialnumber(&sht2x, serialnumber, 8) < 0)
+    {
+        printf("SHT2x get serial number failure\n");
+        return 3;
+    }
+
+    if( sht2x_get_temp_humidity(&sht2x, &temp, &rh) < 0 )
+    {
+        printf("SHT2x get get temperature and relative humidity failure\n");
+        return 3;
+    }
+
+    printf("Temperature=%lf ℃ relative humidity=%lf.\n", temp, rh);
+
+    close(sht2x.fd);
+}
+
+int sht2x_softreset(sht2x_t *sht2x)
+{
+    uint8_t           buf[1];
+
+    if( !sht2x || sht2x->fd<0 )
+    {
+        printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ );
         return -1;
     }
 
-    /*+--------------------------------+
-     *|   software reset SHT20 sensor  |
-     *+--------------------------------+*/
-
-    buf[0] = 0xFE;
-    i2c_write(fd, 0x40, buf, 1);
+    /* software reset SHT2x */
+    buf[0] = SOFTRESET;
+    if( i2c_write(sht2x, buf, 1) < 0 )
+    {
+        return -2;
+    }
 
     msleep(50);
 
+    return 0;
+}
 
-    /*+--------------------------------+
-     *|   trigger temperature measure  |
-     *+--------------------------------+*/
+int sht2x_init(sht2x_t *sht2x)
+{
+    if( (sht2x->fd=open(sht2x->dev, O_RDWR)) < 0)
+    {
+        printf("i2c device open failed: %s\n", strerror(errno));
+        return -1;
+    }
 
-    buf[0] = 0xF3;
-    i2c_write(fd, 0x40, buf, 1);
+    if( MODE_RDWR == sht2x->mode )
+    {
+        /* set I2C mode and SHT2x slave address */
+        ioctl(sht2x->fd, I2C_TENBIT, 0);    /* Not 10-bit but 7-bit mode */
+        ioctl(sht2x->fd, I2C_SLAVE, SHT2X_CHIPADDR); /* set SHT2x slave address 0x40*/
+    }
+
+    if( sht2x_softreset(sht2x) < 0 )
+    {
+        printf("SHT2x softreset failure\n");
+        return -2;
+    }
+
+    return 0;
+}
+
+int sht2x_get_temp_humidity(sht2x_t *sht2x, float *temp, float *rh)
+{
+    uint8_t           buf[4];
+
+    if( !sht2x || !temp || !rh || sht2x->fd<0 )
+    {
+        printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ );
+        return -1;
+    }
+
+    /* send trigger temperature measure command and read the data */
+    memset(buf, 0, sizeof(buf));
+    buf[0]=TRIGGER_TEMPERATURE_NO_HOLD;
+    i2c_write(sht2x, buf, 1);
 
     msleep(85); /* datasheet: typ=66, max=85 */
 
     memset(buf, 0, sizeof(buf));
-    i2c_read(fd, 0x40, buf, 3);
+    i2c_read(sht2x, buf, 3);
     dump_buf("Temperature sample data: ", buf, 3);
+    *temp = 175.72 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 46.85;
 
-    if( !sht20_checksum(buf, 2, buf[2]) )
-    {
-        printf("Temperature sample data CRC checksum failure.\n");
-        goto cleanup;
-    }
-
-    temp = 175.72 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 46.85;
-
-
-    /*+--------------------------------+
-     *|    trigger humidity measure    |
-     *+--------------------------------+*/
-
-    buf[0] = 0xF5;
-    i2c_write(fd, 0x40, buf, 1);
+    /* send trigger humidity measure command and read the data */
+    memset(buf, 0, sizeof(buf));
+    buf[0] = TRIGGER_HUMIDITY_NO_HOLD;
+    i2c_write(sht2x, buf, 1);
 
     msleep(29); /* datasheet: typ=22, max=29 */
-
     memset(buf, 0, sizeof(buf));
-    i2c_read(fd, 0x40, buf, 3);
+
+    i2c_read(sht2x, buf, 3);
     dump_buf("Relative humidity sample data: ", buf, 3);
+    *rh = 125 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 6;
 
-    if( !sht20_checksum(buf, 2, buf[2]) )
-    {
-        printf("Relative humidity sample data CRC checksum failure.\n");
-        goto cleanup;
-    }
-
-    rh = 125 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 6;
-
-    /*+--------------------------------+
-     *|    print the measure result    |
-     *+--------------------------------+*/
-
-    printf("Temperature=%lf 'C relative humidity=%lf%%\n", temp, rh);
-
-cleanup:
-    close(fd);
     return 0;
 }
 
-int sht20_checksum(uint8_t *data, int len, int8_t checksum)
+int sht2x_get_serialnumber(sht2x_t *sht2x, uint8_t *serialnumber, int size)
 {
-    int8_t crc = 0;
-    int8_t bit;
-    int8_t byteCtr;
+    uint8_t           buf[4]={0x0};
 
-    //calculates 8-Bit checksum with given polynomial: x^8 + x^5 + x^4 + 1
-    for (byteCtr = 0; byteCtr < len; ++byteCtr)
+    if( !sht2x || sht2x->fd<0 || !serialnumber || size!=8 )
     {
-        crc ^= (data[byteCtr]);
-        for ( bit = 8; bit > 0; --bit)
-        {
-            /* x^8 + x^5 + x^4 + 1 = 0001 0011 0001 = 0x131 */
-            if (crc & 0x80) crc = (crc << 1) ^ 0x131;
-            else crc = (crc << 1);
-        }
+        printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ );
+        return -1;
     }
 
-    if (crc != checksum)
-        return 0;
-    else
-        return 1;
+    /* Read SerialNumber from Location 1 */
+    memset(buf, 0, sizeof(buf));
+    buf[0] = 0xfa;  /* command for readout on-chip memory */
+    buf[1] = 0x0f;  /* on-chip memory address */
+    i2c_write(sht2x, buf, 2);
+
+    memset(buf, 0, sizeof(buf));
+    i2c_read(sht2x, buf, 4);
+
+    if( !buf[0] && !buf[1] && !buf[2] && !buf[3] )
+    {
+        printf("ERROR: SHT2X device not detected!\n");
+        return -2;
+    }
+
+    serialnumber[5]=buf[0]; /* Read SNB_3 */
+    serialnumber[4]=buf[1]; /* Read SNB_2 */
+    serialnumber[3]=buf[2]; /* Read SNB_1 */
+    serialnumber[2]=buf[3]; /* Read SNB_0 */
+
+    /* Read SerialNumber from Location 2 */
+    memset(buf, 0, sizeof(buf) );
+    buf[0]=0xfc;  /* command for readout on-chip memory */
+    buf[1]=0xc9;  /* on-chip memory address */
+    i2c_write(sht2x, buf, 2);
+
+    memset(buf, 0, sizeof(buf) );
+    i2c_read(sht2x, buf, 4);
+
+    serialnumber[1]=buf[0]; /* Read SNC_1 */
+    serialnumber[0]=buf[1]; /* Read SNC_0 */
+    serialnumber[7]=buf[2]; /* Read SNA_1 */
+    serialnumber[6]=buf[3]; /* Read SNA_0 */
+
+    dump_buf("SHT2x Serial number: ", serialnumber, 8);
+
+    return 0;
 }
 
-int i2c_write(int fd, uint8_t slave_addr, uint8_t *data, int len)
+static int i2c_write(sht2x_t *sht2x, uint8_t *data, int len)
 {
-    struct i2c_rdwr_ioctl_data i2cdata;
-    int rv = 0;
+    struct i2c_rdwr_ioctl_data      i2cdata;
+    int                             rv = 0;
 
     if( !data || len<= 0)
     {
@@ -214,6 +306,14 @@
         return -1;
     }
 
+    /* I2C device program API: read()/write() */
+    if( MODE_RDWR == sht2x->mode )
+    {
+        write(sht2x->fd, data, len);
+        return 0;
+    }
+
+    /* I2C device program API: ioctl() */
     i2cdata.nmsgs = 1;
     i2cdata.msgs = malloc( sizeof(struct i2c_msg)*i2cdata.nmsgs );
     if ( !i2cdata.msgs )
@@ -222,7 +322,7 @@
         return -2;
     }
 
-    i2cdata.msgs[0].addr = slave_addr;
+    i2cdata.msgs[0].addr = sht2x->addr;
     i2cdata.msgs[0].flags = 0; //write
     i2cdata.msgs[0].len = len;
     i2cdata.msgs[0].buf = malloc(len);
@@ -235,7 +335,7 @@
     memcpy(i2cdata.msgs[0].buf, data, len);
 
 
-    if( ioctl(fd, I2C_RDWR, &i2cdata)<0 )
+    if( ioctl(sht2x->fd, I2C_RDWR, &i2cdata)<0 )
     {
         printf("%s() ioctl failure: %s\n", __func__, strerror(errno));
         rv = -4;
@@ -252,10 +352,10 @@
     return rv;
 }
 
-int i2c_read(int fd, uint8_t slave_addr, uint8_t *buf, int size)
+static int i2c_read(sht2x_t *sht2x, uint8_t *buf, int size)
 {
-    struct i2c_rdwr_ioctl_data i2cdata;
-    int rv = 0;
+    struct i2c_rdwr_ioctl_data      i2cdata;
+    int                             rv = 0;
 
     if( !buf || size<= 0)
     {
@@ -263,6 +363,14 @@
         return -1;
     }
 
+    /* I2C device program API: read()/write() */
+    if( MODE_RDWR == sht2x->mode )
+    {
+        read(sht2x->fd, buf, size);
+        return 0;
+    }
+
+    /* I2C device program API: ioctl() */
     i2cdata.nmsgs = 1;
     i2cdata.msgs = malloc( sizeof(struct i2c_msg)*i2cdata.nmsgs );
     if ( !i2cdata.msgs )
@@ -271,13 +379,13 @@
         return -2;
     }
 
-    i2cdata.msgs[0].addr = slave_addr;
+    i2cdata.msgs[0].addr = sht2x->addr;
     i2cdata.msgs[0].flags = I2C_M_RD; //read
     i2cdata.msgs[0].len = size;
     i2cdata.msgs[0].buf = buf;
     memset(buf, 0, size);
 
-    if( ioctl(fd, I2C_RDWR, &i2cdata)<0 )
+    if( ioctl(sht2x->fd, I2C_RDWR, &i2cdata)<0 )
     {
         printf("%s() ioctl failure: %s\n", __func__, strerror(errno));
         rv = -4;
@@ -286,6 +394,10 @@
     free( i2cdata.msgs );
     return rv;
 }
+
+/*+----------------+
+ *| Misc functions |
+ *+----------------+*/
 
 static inline void msleep(unsigned long ms)
 {
@@ -304,7 +416,6 @@
     }
 
     nanosleep(&cSleep, 0);
-    return ;
 }
 
 static inline void dump_buf(const char *prompt, uint8_t *buf, int size)
@@ -318,7 +429,7 @@
 
     if( prompt )
     {
-        printf("%-32s ", prompt);
+        printf("%s ", prompt);
     }
 
     for(i=0; i<size; i++)

--
Gitblit v1.9.1