From 5347abf61b167f3014ec7e0d21c95a9284a58689 Mon Sep 17 00:00:00 2001 From: Roman Bazalevskiy Date: Wed, 12 Apr 2017 20:05:42 +0300 Subject: [PATCH] Initial fork + minor fixes for BMP085 (mBar output) + shell scripts for ADS1115 and DS1307 --- Makefile | 33 ++++ ad5602_test.c | 60 +++++++ ads1115 | 33 ++++ am2321.c | 303 ++++++++++++++++++++++++++++++++ bh1750.c | 85 +++++++++ bmp085.c | 212 ++++++++++++++++++++++ ds1621.c | 134 ++++++++++++++ etraxi2c.h | 49 ++++++ gethwclock | 13 ++ i2c_errno.h | 20 +++ i2cget_bmp180.example | 17 ++ ina219.c | 400 ++++++++++++++++++++++++++++++++++++++++++ lcdd.c | 394 +++++++++++++++++++++++++++++++++++++++++ lm75.c | 49 ++++++ mcp_rw.c | 297 +++++++++++++++++++++++++++++++ pcf8574_1.c | 52 ++++++ pcf8574_2.c | 56 ++++++ pcf8574_3.c | 49 ++++++ pcf8574_4.c | 50 ++++++ pcf8591_1.c | 95 ++++++++++ pcf8591_2.c | 73 ++++++++ pcf8591_3.c | 66 +++++++ pcf8591_4.c | 112 ++++++++++++ pcf8591d.c | 67 +++++++ sethwclock | 26 +++ sht21.c | 110 ++++++++++++ smbus.c | 228 ++++++++++++++++++++++++ smbus.h | 59 +++++++ syncfromhwclock | 3 + 29 files changed, 3145 insertions(+) create mode 100644 Makefile create mode 100644 ad5602_test.c create mode 100644 ads1115 create mode 100644 am2321.c create mode 100644 bh1750.c create mode 100644 bmp085.c create mode 100644 ds1621.c create mode 100644 etraxi2c.h create mode 100644 gethwclock create mode 100644 i2c_errno.h create mode 100644 i2cget_bmp180.example create mode 100644 ina219.c create mode 100644 lcdd.c create mode 100644 lm75.c create mode 100644 mcp_rw.c create mode 100644 pcf8574_1.c create mode 100644 pcf8574_2.c create mode 100644 pcf8574_3.c create mode 100644 pcf8574_4.c create mode 100644 pcf8591_1.c create mode 100644 pcf8591_2.c create mode 100644 pcf8591_3.c create mode 100644 pcf8591_4.c create mode 100644 pcf8591d.c create mode 100644 sethwclock create mode 100644 sht21.c create mode 100644 smbus.c create mode 100644 smbus.h create mode 100644 syncfromhwclock diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e27fcce --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ + +STAGING_DIR=/var/www/builder/data/trunk/build_ng/openwrt/staging_dir +export STAGING_DIR +CFLAGS=-I. +# +# Atheros +CC= ~/trunk/build_ng/openwrt/staging_dir/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-uclibc-gcc +# +# Broadcom +#CC= ~/trunk/build_ng/openwrt/staging_dir/toolchain-mips_gcc-4.6-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-uclibc-gcc + + + +ina219: + $(CC) -o ina219 ina219.c + +bmp085: + $(CC) -o bmp085 bmp085.c smbus.c + +lm75: + $(CC) -o lm75 lm75.c + +ds1621: + $(CC) -o ds1621 ds1621.c + +bh1750: + $(CC) -o bh1750 bh1750.c smbus.c + +lcdd: + $(CC) -o lcdd lcdd.c + +mcp_rw: + $(CC) -o mcp mcp_rw.c smbus.c diff --git a/ad5602_test.c b/ad5602_test.c new file mode 100644 index 0000000..4b67a3d --- /dev/null +++ b/ad5602_test.c @@ -0,0 +1,60 @@ +/* + AD5602_test1.c + --------------------- + set the output voltage from the D/A + ----------------------------------- + + 1) send the i2c address + 2) send HI_byte + 3) send LO_byte + + usage :- type with spaces but without the < > +
+*/ + +#include +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + int i2c; + int HI_byte; /* last 4 bits are output byte HI bits */ + int LO_byte; /* first 4 bits are output byte LO bits */ + int buf[1]; /* use to feed the i2c driver */ + int address; /* i2c bus address */ + + if (argc != 4) /* report error if we are not getting just 3 inputs after the program name */ + { + printf("Error. usage (decimal): %s AD5602_test1 address HI_byte LO_byte\n", argv[0]); + } + + address = atoi(argv[1]); /* address is the first number after the program name */ + // address bits are 0 0 0 1 1 1 0 R/W as per manual + // the 1 0 before R/W is for the address pin (pin 1) open-circuit + // the R/W is 0 for write. Linux see the chip address as 0000 1110 (0E) - shifts a bit to the left - odd! + HI_byte = atoi(argv[2]); /* HI_byte is 0 0 0 0 D7 D6 D5 D4 */ + LO_byte = atoi(argv[3]); /* LO_byte is D3 D2 D1 D0 X X X X (X = anything) */ + + i2c = open("/dev/i2c/0",O_RDWR); /* open the i2c-bus number 0 */ + + ioctl(i2c,I2C_SLAVE,address); /* set the i2c-bus address of the chip we will talk to */ + + buf[0] = HI_byte; /* HI_byte */ + buf[1] = LO_byte; /* LO_byte */ + + + write(i2c,buf,2); /* we send 2 bytes */ + + printf("%d\n", buf[0]); /* just to prove it ran!*/ + printf("%d\n", buf[1]); + + i2c = close(i2c); +} + +// AD5602_test1 14 0 0 gives 0 volts +// AD5602_test1 14 8 0 gives 2.5 volts 8 = 08 00001000 0 = 00 00000000 +// AD5602_test1 14 15 240 gives 5 volts 15 = 0F 00001111 240 = F0 11110000 + diff --git a/ads1115 b/ads1115 new file mode 100644 index 0000000..2f1e824 --- /dev/null +++ b/ads1115 @@ -0,0 +1,33 @@ +#!/bin/sh + +I2CBUS=0 +I2CADDR=0x48 + +if [ "$1" == "" ] +then + pin=0 +else + pin=$1 +fi + +case "$pin" in + "0") CFG="0xc583" ;; + "1") CFG="0xc593" ;; + "2") CFG="0xc5a3" ;; + "3") CFG="0xc5b3" ;; + *) echo "Bad pin number $pin, must be 0..3" ; exit 1 ;; +esac + +i2cset -y 0 0x48 1 $CFG w +RES=`i2cget -y 0 0x48 1 w` +until [ "$RES" = "$CFG" ] ; do + RES=`i2cget -y 0 0x48 1 w` +done +X=`i2cget -y 0 0x48 0 w` + +XX="0x0`echo $X | cut -c 5-6``echo $X | cut -c 3`" +VIND=$(( ( $XX + 32768 / 40960 ) * 20480 / 32768 )) +VIN=$(( $VIND / 10 )) +VINF=$(( $VIND - $VIN * 10 )) + +printf "VIN$pin (mv) %d.%01d\n" $VIN $VINF diff --git a/am2321.c b/am2321.c new file mode 100644 index 0000000..abe84bc --- /dev/null +++ b/am2321.c @@ -0,0 +1,303 @@ +/* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* +* Project Home - https://github.com/takagi/am2321 +* +*/ + +#include +#include +#include /* for O_RDWR */ +#include /* for memcpy */ +#include /* for I2C_SLAVE */ + +#include /* add by paulerr*/ +#include /* add by paulerr*/ + + +/* I2C character device */ +#define I2C_DEVICE "/dev/i2c-0" + +/* I2C address of AM2321 sensor in 7 bits + * - the first 7 bits should be passed to ioctl system call + * because the least 1 bit of the address represents read/write + * and the i2c driver takes care of it + */ +#define AM2321_ADDR (0xB8 >> 1) + + +/* + * udelay function + */ + +long timeval_to_usec( struct timeval tm ) { + return tm.tv_sec * 1000000 + tm.tv_usec; +} + +void udelay( long us ) { + struct timeval current; + struct timeval start; + + gettimeofday( &start, NULL ); + do { + gettimeofday( ¤t, NULL ); + } while( timeval_to_usec( current ) - timeval_to_usec( start ) < us ); +} + + +/* + * CRC16 + */ + +unsigned short crc16( unsigned char *ptr, unsigned char len ) { + unsigned short crc = 0xFFFF; + unsigned char i; + + while( len-- ) + { + crc ^= *ptr++; + for( i = 0; i < 8; i++ ) { + if( crc & 0x01 ) { + crc >>= 1; + crc ^= 0xA001; + } else { + crc >>= 1; + } + } + } + + return crc; +} + +unsigned char crc16_low( unsigned short crc ) { + return crc & 0xFF; +} + +unsigned char crc16_high( unsigned short crc ) { + return crc >> 8; +} + + +/* + * st_am2321 Structure + */ + +typedef struct { + unsigned char data[8]; +} st_am2321; + +void __check_crc16( st_am2321 measured ) { + unsigned short crc_m, crc_s; + + crc_m = crc16( measured.data, 6 ); + crc_s = (measured.data[7] << 8) + measured.data[6]; + if ( crc_m != crc_s ) { + fprintf( stderr, "am2321: CRC16 does not match\n" ); + exit( 1 ); + } + + return; +} + +st_am2321 __st_am2321( unsigned char* data ) { + st_am2321 result; + memcpy( result.data, data, 8 ); + __check_crc16( result ); + return result; +} + +void am2321_dump( st_am2321 measured ) { + printf( "[ 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ]\n", + measured.data[0], measured.data[1], + measured.data[2], measured.data[3], + measured.data[4], measured.data[5], + measured.data[6], measured.data[7] ); + return; +} + +short __am2321_temperature( st_am2321 measured ) { + return (measured.data[4] << 8) + measured.data[5]; +} + +short am2321_temperature_integral( st_am2321 measured ) { + return __am2321_temperature( measured ) / 10; +} + +short am2321_temperature_fraction( st_am2321 measured ) { + return __am2321_temperature( measured ) % 10; +} + +short __am2321_humidity( st_am2321 measured ) { + return (measured.data[2] << 8) + measured.data[3]; +} + +short am2321_humidity_integral( st_am2321 measured ) { + return __am2321_humidity( measured ) / 10; +} + +short am2321_humidity_fraction( st_am2321 measured ) { + return __am2321_humidity( measured ) % 10; +} + + +/* + * Measurement function + */ + +st_am2321 am2321() { + int fd; + int ret; + int retry_cnt; + unsigned char data[8]; + + /* open I2C device */ + fd = open( I2C_DEVICE, O_RDWR ); + if ( fd < 0 ) { + perror( "am2321(1)" ); + exit( 1 ); + } + + /* set address of I2C device in 7 bits */ + ret = ioctl( fd, I2C_SLAVE, AM2321_ADDR ); + if ( ret < 0 ) { + perror( "am2321(2)" ); + exit( 2 ); + } + + retry_cnt = 0; + retry: + + /* wake I2C device up */ + write( fd, NULL, 0); + + /* write measurement request */ + data[0] = 0x03; data[1] = 0x00; data[2] = 0x04; + ret = write( fd, data, 3 ); + if ( ret < 0 && retry_cnt++ < 5 ) { + fprintf( stderr, "am2321: retry\n" ); + udelay( 1000 ); + goto retry; + } + if ( ret < 0 ) { + perror( "am2321(3)" ); + exit( 3 ); + } + + /* wait for having measured */ + udelay( 1500 ); + + /* read measured result */ + memset( data, 0x00, 8 ); + ret = read( fd, data, 8 ); + if ( ret < 0 ) { + perror( "am2321(4)" ); + exit( 4 ); + } + + /* close I2C device */ + close( fd ); + + return __st_am2321( data ); +} + +st_am2321 am2321_stub() { + unsigned char data[] = { 0x03, 0x04, 0x01, 0x41, + 0x00, 0xEA, 0x21, 0x8F }; + return __st_am2321( data ); +} + + +/* + * Print functions + */ + +void print_am2321( st_am2321 measured ) { + printf( "%d.%d %d.%d\n", + am2321_temperature_integral( measured ), + am2321_temperature_fraction( measured ), + am2321_humidity_integral( measured ), + am2321_humidity_fraction( measured ) ); + return; +} + +void print_am2321_human_readable( st_am2321 measured ) { + printf( "Temperature (C)\t\t%d.%d\n", + am2321_temperature_integral( measured ), + am2321_temperature_fraction( measured ) ); + printf( "Humidity (%%)\t\t%d.%d\n", + am2321_humidity_integral( measured ), + am2321_humidity_fraction( measured ) ); + return; +} + +/* + * Main + */ + +#define OPT_HUMAN_READABLE 0x1 +#define OPT_STUB 0x2 + +int print_help() { + fprintf( stderr, + "Usage: am2321 [-r] [-s]\n" + "Get temperature and humidity measured with Aosong's AM2321 sensor.\n" + " -r human readable output\n" + " -s not measure with AM2321, instead stub of 23.4[C] and 32.1[%]\n" ); + exit( 1 ); +} + +int parse_options( int argc, char* argv[]) { + int options = 0; + int flags = 0; + + while( 1+flags < argc && argv[1+flags][0] == '-' ) { + switch( argv[1+flags][1] ) { + case 'r': options |= OPT_HUMAN_READABLE; break; + case 's': options |= OPT_STUB; break; + default: + fprintf( stderr, "am2321: Unsupported option \"%s\"\n", argv[1+flags] ); + print_help(); + exit( 1 ); + } + flags++; + } + + return options; +} + +int is_opt_human_readable( int options ) { + return options & OPT_HUMAN_READABLE; +} + +int is_opt_stub( int options ) { + return options & OPT_STUB; +} + +int main( int argc, char* argv[] ) { + int options; + st_am2321 measured; + + /* parse the given options */ + options = parse_options( argc, argv ); + + /* measure temperature and humidity */ + measured = ! is_opt_stub( options ) ? am2321() : am2321_stub(); + + /* print measured temperature and humidity */ + if ( ! is_opt_human_readable( options ) ) { + print_am2321( measured ); + } else { + print_am2321_human_readable( measured ); + } + + return 0; +} diff --git a/bh1750.c b/bh1750.c new file mode 100644 index 0000000..798fe6c --- /dev/null +++ b/bh1750.c @@ -0,0 +1,85 @@ +/* + Sample code for the BH1750 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "smbus.h" + +#define BH1750FVI_I2C_ADDRESS 0x23 // ADDR > 0.7 VCC) +//#define BH1750FVI_I2C_ADDRESS 0x53 // ADDR < 0.3 VCC) +#define DEBUG 0 + +#define PowerDown 0x00 +#define PowerOn 0x01 +#define Reset 0x07 +#define ContinuHigh 0x10 +#define ContinuLow 0x13 +#define OneTimeHigh 0x20 +#define OneTimeLow 0x23 + +int main(int argc, char **argv) +{ + int fd; + char *fileName = "/dev/i2c-0"; + int retCode; + int readSize; + unsigned int res; + unsigned int lux; + char buf[5]; + int i; + + // Open port for reading and writing + if ((fd = open(fileName, O_RDWR)) < 0) { + printf("open error\n"); + exit(1); + } + + // Set the port options and set the address of the device + if (ioctl(fd, I2C_SLAVE, BH1750FVI_I2C_ADDRESS) < 0) { + printf("ioctl error\n"); + close(fd); + exit(1); + } + + retCode=i2c_smbus_write_byte(fd, PowerOn); +if(DEBUG)printf("Power On retCode=%d\n",retCode); + if (retCode < 0) { + printf("PowerOn error\n"); + close(fd); + exit(1); + } + + retCode=i2c_smbus_write_byte(fd, ContinuHigh); +if(DEBUG)printf("ContinuHigh retCode=%d\n",retCode); + if (retCode < 0) { + printf("ContinuHigh error\n"); + close(fd); + exit(1); + } + + // Set i<10 for more one check + for(i=0;i<1;i++) { + sleep(3); + readSize = read (fd, buf, 2); +if(DEBUG)printf("read readSize=%d %x %x\n",readSize,buf[0],buf[1]); + + res = buf[0]*256+buf[1]; +if(DEBUG)printf("res=%x\n",res); + lux = res / 1.2; + // printf("Lux=%d\n",lux); + printf("Brightness (Lux)\t%0.1f\n", ((double)lux)); + } + + retCode=i2c_smbus_write_byte(fd, PowerDown); + close(fd); + + exit (0); +} \ No newline at end of file diff --git a/bmp085.c b/bmp085.c new file mode 100644 index 0000000..c8127dd --- /dev/null +++ b/bmp085.c @@ -0,0 +1,212 @@ +/* + Sample code for the BMP085 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "smbus.h" + +#define BMP085_I2C_ADDRESS 0x77 + +const unsigned char BMP085_OVERSAMPLING_SETTING = 3; + +// Calibration values - These are stored in the BMP085 +short int ac1; +short int ac2; +short int ac3; +unsigned short int ac4; +unsigned short int ac5; +unsigned short int ac6; +short int b1; +short int b2; +short int mb; +short int mc; +short int md; + +int b5; + +unsigned int temperature, pressure; + + +// Open a connection to the bmp085 +// Returns a file id +int bmp085_i2c_Begin() +{ + int fd; + char *fileName = "/dev/i2c-0"; + + // Open port for reading and writing + if ((fd = open(fileName, O_RDWR)) < 0) + exit(1); + + // Set the port options and set the address of the device + if (ioctl(fd, I2C_SLAVE, BMP085_I2C_ADDRESS) < 0) { + close(fd); + exit(1); + } + + return fd; +} + +// Read two words from the BMP085 and supply it as a 16 bit integer +__s32 bmp085_i2c_Read_Int(int fd, __u8 address) +{ + __s32 res = i2c_smbus_read_word_data(fd, address); + if (res < 0) { + close(fd); + exit(1); + } + + // Convert result to 16 bits and swap bytes + res = ((res<<8) & 0xFF00) | ((res>>8) & 0xFF); + + return res; +} + +//Write a byte to the BMP085 +void bmp085_i2c_Write_Byte(int fd, __u8 address, __u8 value) +{ + if (i2c_smbus_write_byte_data(fd, address, value) < 0) { + close(fd); + exit(1); + } +} + +// Read a block of data BMP085 +void bmp085_i2c_Read_Block(int fd, __u8 address, __u8 length, __u8 *values) +{ + if(i2c_smbus_read_i2c_block_data(fd, address,length,values)<0) { + close(fd); + exit(1); + } +} + + +void bmp085_Calibration() +{ + int fd = bmp085_i2c_Begin(); + ac1 = bmp085_i2c_Read_Int(fd,0xAA); + ac2 = bmp085_i2c_Read_Int(fd,0xAC); + ac3 = bmp085_i2c_Read_Int(fd,0xAE); + ac4 = bmp085_i2c_Read_Int(fd,0xB0); + ac5 = bmp085_i2c_Read_Int(fd,0xB2); + ac6 = bmp085_i2c_Read_Int(fd,0xB4); + b1 = bmp085_i2c_Read_Int(fd,0xB6); + b2 = bmp085_i2c_Read_Int(fd,0xB8); + mb = bmp085_i2c_Read_Int(fd,0xBA); + mc = bmp085_i2c_Read_Int(fd,0xBC); + md = bmp085_i2c_Read_Int(fd,0xBE); + close(fd); +} + +// Read the uncompensated temperature value +unsigned int bmp085_ReadUT() +{ + unsigned int ut = 0; + int fd = bmp085_i2c_Begin(); + + // Write 0x2E into Register 0xF4 + // This requests a temperature reading + bmp085_i2c_Write_Byte(fd,0xF4,0x2E); + + // Wait at least 4.5ms + usleep(5000); + + // Read the two byte result from address 0xF6 + ut = bmp085_i2c_Read_Int(fd,0xF6); + + // Close the i2c file + close (fd); + + return ut; +} + +// Read the uncompensated pressure value +unsigned int bmp085_ReadUP() +{ + unsigned int up = 0; + int fd = bmp085_i2c_Begin(); + + // Write 0x34+(BMP085_OVERSAMPLING_SETTING<<6) into register 0xF4 + // Request a pressure reading w/ oversampling setting + bmp085_i2c_Write_Byte(fd,0xF4,0x34 + (BMP085_OVERSAMPLING_SETTING<<6)); + + // Wait for conversion, delay time dependent on oversampling setting + usleep((2 + (3<> (8-BMP085_OVERSAMPLING_SETTING); + + return up; +} + +// Calculate pressure given uncalibrated pressure +// Value returned will be in units of XXXXX +unsigned int bmp085_GetPressure(unsigned int up) +{ + int x1, x2, x3, b3, b6, p; + unsigned int b4, b7; + + b6 = b5 - 4000; + // Calculate B3 + x1 = (b2 * (b6 * b6)>>12)>>11; + x2 = (ac2 * b6)>>11; + x3 = x1 + x2; + b3 = (((((int)ac1)*4 + x3)<>2; + + // Calculate B4 + x1 = (ac3 * b6)>>13; + x2 = (b1 * ((b6 * b6)>>12))>>16; + x3 = ((x1 + x2) + 2)>>2; + b4 = (ac4 * (unsigned int)(x3 + 32768))>>15; + + b7 = ((unsigned int)(up - b3) * (50000>>BMP085_OVERSAMPLING_SETTING)); + if (b7 < 0x80000000) + p = (b7<<1)/b4; + else + p = (b7/b4)<<1; + + x1 = (p>>8) * (p>>8); + x1 = (x1 * 3038)>>16; + x2 = (-7357 * p)>>16; + p += (x1 + x2 + 3791)>>4; + + return p; +} + +// Calculate temperature given uncalibrated temperature +// Value returned will be in units of 0.1 deg C +unsigned int bmp085_GetTemperature(unsigned int ut) +{ + int x1, x2; + + x1 = (((int)ut - (int)ac6)*(int)ac5) >> 15; + x2 = ((int)mc << 11)/(x1 + md); + b5 = x1 + x2; + + unsigned int result = ((b5 + 8)>>4); + + return result; +} + +int main(int argc, char **argv) +{ + bmp085_Calibration(); + temperature = bmp085_GetTemperature(bmp085_ReadUT()); + pressure = bmp085_GetPressure(bmp085_ReadUP()); + + printf("Temperature (C)\t\t%0.1f\n", ((double)temperature)/10); + printf("Pressure (mBar)\t%0.2f\n", ((double)pressure)/100); + // printf("Pressure (mmHg)\t%0.2f\n", ((double)pressure)/100*0.75006375541921); + // printf("Pressure (mmHg)\t\t%0.2f\n", ((double)pressure)/100*0.750061683); + return 0; +} \ No newline at end of file diff --git a/ds1621.c b/ds1621.c new file mode 100644 index 0000000..30e858e --- /dev/null +++ b/ds1621.c @@ -0,0 +1,134 @@ +/* Test DS1621 sur interface I2C GPIO Fonera (3/2008) */ +/* Inspir de "Un bus i2c pour La Fonera" */ +/* http://www.lefinnois.net/wp/index.php/2007/05/05/un-bus-i2c-pour-la-fonera/ */ + +/* Affichage de la t */ +/* Par domos domos78freefr */ +/* http://vesta.homelinux.net/ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define I2C_SLAVE 0x0703 // Change slave address + +static int i2c_fd ; +int res ; + +#define DEVICE "/dev/i2c-0" +#define ds1621_addr 0x9E >> 1 // 0x4f - Address (A0+A1+A2 to Vcc) + + +/*------------------------------------------------------------------------------*/ +/* Fonctions i2c */ +/*------------------------------------------------------------------------------*/ +void i2c_init() +{ + if ((i2c_fd = open(DEVICE, O_RDWR)) < 0) + { + fprintf(stderr, "Erreur ouverture port: %s (%d)\n", strerror(errno), errno); + exit(EXIT_FAILURE); + } +} + +//----------------------------------------------------------------------------- +void SelectSlave(unsigned char slaveaddr) +{ + if (ioctl(i2c_fd, I2C_SLAVE, slaveaddr) < 0) + { + fprintf(stderr, "Erreur selection esclave i2c: %s (%d)\n", strerror(errno), errno); + close ( i2c_fd ) ; + exit(EXIT_FAILURE) ; + } +} + +/*------------------------------------------------------------------------------*/ +/* Fonctions DS1621 */ +/*------------------------------------------------------------------------------*/ +int i2c_init_ds1621(unsigned char addr) +{ + int res ; + char buff[10] ; + + SelectSlave(addr) ; + buff[0] = 0xAC ; + buff[1] = 0x01 ; + res = write( i2c_fd, buff, 2 ); + if ( res < 0 ) + { + printf("Erreur init DS1621 addr 0x%x: '%s', Abandon programme !", addr, strerror(errno)); + close ( i2c_fd ); + exit(1) ; + } + /* start temperature conversion */ + errno = 0 ; + buff[0] = 0xEE ; + write( i2c_fd, buff, 1 ); + sleep(1) ; + return 1 ; +} + +//----------------------------------------------------------------------------- +double i2c_gettemp_ds1621(unsigned char addr) +{ + int k, count, slope, temp; + char buff[10] ; + + SelectSlave(addr) ; + /* stop conversion */ + errno = 0 ; + buff[0] = 0x22 ; + + if ( write( i2c_fd, buff, 1 ) < 0 ) return 255 ; // Write retourne -1 et strerror(errno))='Remote I/O error' si adr. i2c non connecte. + else + { + /* Temperature reading (1 Celsius degree precision) */ + buff[0] = 0xAA ; + write( i2c_fd, buff, 1 ); + read(i2c_fd, buff, 1) ; + temp = buff[0] ; + /* Counter reading (fraction of degree) ) */ + buff[0] = 0xA8 ; + write( i2c_fd, buff, 1 ); + read(i2c_fd, buff, 1) ; + count = buff[0] ; + /* slope reading */ + buff[0] = 0xA9 ; + write( i2c_fd, buff, 1 ); + read(i2c_fd, buff, 1) ; + slope = buff[0] ; + k = temp; + if (slope != 0) + { + k = temp*100-25+(100*(slope-count))/slope; + } + /* start temperature conversion */ + buff[0] = 0xEE ; + write( i2c_fd, buff, 1 ); + return (float)k/100 ; + } +} + +/*------------------------------------------------------------------------------*/ +int main ( int argc, char ** argv ) +{ + // Init i2c. + i2c_init() ; + + // Init ds1621. + i2c_init_ds1621(ds1621_addr) ; + + // Affiche la t. + printf("%2.1f\n", i2c_gettemp_ds1621(ds1621_addr) ) ; + + close ( i2c_fd ); +} + +/*------------------------------------------------------------------------------*/ + diff --git a/etraxi2c.h b/etraxi2c.h new file mode 100644 index 0000000..9d5c9bf --- /dev/null +++ b/etraxi2c.h @@ -0,0 +1,49 @@ +#ifndef _LINUX_ETRAXI2C_H +#define _LINUX_ETRAXI2C_H + +/* etraxi2c _IOC_TYPE, bits 8 to 15 in ioctl cmd */ + +#define ETRAXI2C_IOCTYPE 44 + +/* supported ioctl _IOC_NR's */ + +/* in write operations, the argument contains both i2c + * slave, register and value. + */ + +#define I2C_WRITEARG(slave, reg, value) (((slave) << 16) | ((reg) << 8) | (value)) +#define I2C_READARG(slave, reg) (((slave) << 16) | ((reg) << 8)) + +#define I2C_ARGSLAVE(arg) ((arg) >> 16) +#define I2C_ARGREG(arg) (((arg) >> 8) & 0xff) +#define I2C_ARGVALUE(arg) ((arg) & 0xff) + +#define I2C_WRITEREG 0x1 /* write to an I2C register */ +#define I2C_READREG 0x2 /* read from an I2C register */ + +/* +EXAMPLE usage: + + i2c_arg = I2C_WRITEARG(STA013_WRITE_ADDR, reg, val); + ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_WRITEREG), i2c_arg); + + i2c_arg = I2C_READARG(STA013_READ_ADDR, reg); + val = ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_READREG), i2c_arg); + +*/ + +/* Extended part */ +#define I2C_READ 0x4 /* reads from I2C device */ +#define I2C_WRITE 0x3 /* writes to I2C device */ +#define I2C_WRITEREAD 0x5 /* writes to I2C device where to start reading */ + +typedef struct _I2C_DATA +{ + unsigned char slave; /* I2C address (8-bit representation) of slave device */ + unsigned char wbuf[256]; /* Write buffer (length = 256 bytes) */ + unsigned int wlen; /* Number of bytes to write from wbuf[] */ + unsigned char rbuf[256]; /* Read buffer (length = 256 bytes) */ + unsigned int rlen; /* Number of bytes to read into rbuf[] */ +} I2C_DATA; + +#endif diff --git a/gethwclock b/gethwclock new file mode 100644 index 0000000..27265d5 --- /dev/null +++ b/gethwclock @@ -0,0 +1,13 @@ +#!/bin/sh + +I2CBUS=0 +I2CADDR=0x68 + +sec=`i2cget -y $I2CBUS $I2CADDR 0` +min=`i2cget -y $I2CBUS $I2CADDR 1` +hour=`i2cget -y $I2CBUS $I2CADDR 2` +day=`i2cget -y $I2CBUS $I2CADDR 4` +month=`i2cget -y $I2CBUS $I2CADDR 5` +year=`i2cget -y $I2CBUS $I2CADDR 6` + +echo 20${year:2:2}-${month:2:2}-${day:2:2} ${hour:2:2}:${min:2:2}:${sec:2:2} diff --git a/i2c_errno.h b/i2c_errno.h new file mode 100644 index 0000000..a517b6f --- /dev/null +++ b/i2c_errno.h @@ -0,0 +1,20 @@ +#ifndef _I2C_ERRNO_H +#define _I2C_ERRNO_H + +#define EI2CNOERRORS 0 /* All fine */ +#define EI2CBUSNFREE 1 /* I2C bus not free */ +#define EI2CWADDRESS 2 /* Address write failed */ +#define EI2CRADDRESS 3 /* Address read failed */ +#define EI2CSENDDATA 4 /* Sending data failed */ +#define EI2CRECVDATA 5 /* Receiving data failed */ +#define EI2CSTRTCOND 6 /* Start condition failed */ +#define EI2CRSTACOND 7 /* Repeated start condition failed */ +#define EI2CSTOPCOND 8 /* Stop condition failed */ +#define EI2CNOSNDBYT 9 /* Number of send bytes is 0, while there's a send buffer defined */ +#define EI2CNOSNDBUF 10 /* No send buffer defined, while number of send bytes is not 0 */ +#define EI2CNORCVBYT 11 /* Number of receive bytes is 0, while there's a receive buffer defined */ +#define EI2CNORCVBUF 12 /* No receive buffer defined, while number of receive bytes is not 0 */ +#define EI2CNOACKNLD 13 /* No acknowledge received from slave */ +#define EI2CNOMNUMBR 14 /* No MAJOR number received from kernel while registering the device */ + +#endif /* _I2C_ERRNO_H */ diff --git a/i2cget_bmp180.example b/i2cget_bmp180.example new file mode 100644 index 0000000..828d16b --- /dev/null +++ b/i2cget_bmp180.example @@ -0,0 +1,17 @@ +#!/bin/sh +# +# More info: http://cyber-place.ru/showpost.php?p=7797&postcount=82 + +RAWTEMP=$(i2cget -y 0 0x40 0xe3 w) +RAWHUMI=$(i2cget -y 0 0x40 0xe5 w) + +if (echo "$RAWTEMP"| grep -Eq '0x[0-9a-f]{4}'); then + HEXORDERED=$(echo "$RAWTEMP"|sed -r 's/0x([0-9a-f]{2})([0-9a-f]{2})/0x\2\1/') + DECRAW=$(($HEXORDERED)) + echo $DECRAW | awk -v tem=${DECRAW} '{ printf "%.2f stC\n", -46.85+((tem*175.72)/65536)}' +fi +if (echo "$RAWHUMI"| grep -Eq '0x[0-9a-f]{4}'); then + HEXORDERED=$(echo "$RAWHUMI"|sed -r 's/0x([0-9a-f]{2})([0-9a-f]{2})/0x\2\1/') + DECRAW=$(($HEXORDERED)) + echo $DECRAW | awk -v hum=${DECRAW} '{ printf "%.2f %%RH\n", -6+((hum*125)/65536)}' +fi \ No newline at end of file diff --git a/ina219.c b/ina219.c new file mode 100644 index 0000000..9cf3de6 --- /dev/null +++ b/ina219.c @@ -0,0 +1,400 @@ +/* +* INA219 util - part of PowerCape by AndiceLabs +* +* Copyright (C) 2014 AndiceLabs admin@andicelabs.com http://andicelabs.com +* Copyright (C) 2014 Zig Fisher flyrouter@gmail.com http://zftlab.org +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* +* Example run and output: +* +* OpenWRT:~# ina219 -b 0 -i 60 +* +* 22:49 12168mV 134.2mA +* 22:50 12168mV 239.9mA +* 22:51 12168mV 134.7mA +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CONFIG_REG 0 +#define SHUNT_REG 1 +#define BUS_REG 2 +#define POWER_REG 3 +#define CURRENT_REG 4 +#define CALIBRATION_REG 5 + +#define AVR_ADDRESS 0x21 +#define INA_ADDRESS 0x40 + +typedef enum { + OP_DUMP, + OP_VOLTAGE, + OP_CURRENT, + OP_MONITOR, + OP_NONE +} op_type; + +op_type operation = OP_DUMP; + +int interval = 60; +int i2c_bus = 0; +int i2c_address = INA_ADDRESS; +int handle; +int whole_numbers = 0; + + +void msleep( int msecs ) +{ + usleep( msecs * 1000 ); +} + + +int i2c_read( void *buf, int len ) +{ + int rc = 0; + + if ( read( handle, buf, len ) != len ) + { + printf( "I2C read failed: %s\n", strerror( errno ) ); + rc = -1; + } + + return rc; +} + + +int i2c_write( void *buf, int len ) +{ + int rc = 0; + + if ( write( handle, buf, len ) != len ) + { + printf( "I2C write failed: %s\n", strerror( errno ) ); + rc = -1; + } + + return rc; +} + + +int register_read( unsigned char reg, unsigned short *data ) +{ + int rc = -1; + unsigned char bite[ 4 ]; + + bite[ 0 ] = reg; + if ( i2c_write( bite, 1 ) == 0 ) + { + if ( i2c_read( bite, 2 ) == 0 ) + { + *data = ( bite[ 0 ] << 8 ) | bite[ 1 ]; + rc = 0; + } + } + + return rc; +} + + +int register_write( unsigned char reg, unsigned short data ) +{ + int rc = -1; + unsigned char bite[ 4 ]; + + bite[ 0 ] = reg; + bite[ 1 ] = ( data >> 8 ) & 0xFF; + bite[ 2 ] = ( data & 0xFF ); + + if ( i2c_write( bite, 3 ) == 0 ) + { + rc = 0; + } + + return rc; +} + + +void show_usage( char *progname ) +{ + fprintf( stderr, "Usage: %s \n", progname ); + fprintf( stderr, " Mode (required):\n" ); + fprintf( stderr, " -h --help Show usage.\n" ); + fprintf( stderr, " -i --interval Set interval for monitor mode.\n" ); + fprintf( stderr, " -w --whole Show whole numbers only. Useful for scripts.\n" ); + fprintf( stderr, " -v --voltage Show battery voltage in mV.\n" ); + fprintf( stderr, " -c --current Show battery current in mA.\n" ); + fprintf( stderr, " -a --address Override I2C address of INA219 from default of 0x%02X.\n", i2c_address ); + fprintf( stderr, " -b --bus Override I2C bus from default of %d.\n", i2c_bus ); + exit( 1 ); +} + + +void parse( int argc, char *argv[] ) +{ + while( 1 ) + { + static const struct option lopts[] = + { + { "address", 0, 0, 'a' }, + { "bus", 0, 0, 'b' }, + { "current", 0, 0, 'c' }, + { "help", 0, 0, 'h' }, + { "interval", 0, 0, 'i' }, + { "voltage", 0, 0, 'v' }, + { "whole", 0, 0, 'w' }, + { NULL, 0, 0, 0 }, + }; + int c; + + c = getopt_long( argc, argv, "a:b:chi:vw", lopts, NULL ); + + if( c == -1 ) + break; + + switch( c ) + { + case 'a': + { + errno = 0; + i2c_address = (int)strtol( optarg, NULL, 0 ); + if ( errno != 0 ) + { + fprintf( stderr, "Unknown address parameter %s.\n", optarg ); + exit( 1 ); + } + break; + } + + case 'b': + { + errno = 0; + i2c_bus = (int)strtol( optarg, NULL, 0 ); + if ( errno != 0 ) + { + fprintf( stderr, "Unknown bus parameter %s.\n", optarg ); + exit( 1 ); + } + break; + } + + case 'c': + { + operation = OP_CURRENT; + break; + } + + default: + case 'h': + { + operation = OP_NONE; + show_usage( argv[ 0 ] ); + break; + } + + case 'i': + { + operation = OP_MONITOR; + interval = atoi( optarg ); + if ( ( interval == 0 ) && ( errno != 0 ) ) + { + fprintf( stderr, "Invalid interval value\n" ); + exit( 1 ); + } + break; + } + + case 'v': + { + operation = OP_VOLTAGE; + break; + } + + case 'w': + { + whole_numbers = 1; + break; + } + } + } +} + + +int get_voltage( float *mv ) +{ + short bus; + + if ( register_read( BUS_REG, (unsigned short*)&bus ) != 0 ) + { + return -1; + } + + *mv = ( float )( ( bus & 0xFFF8 ) >> 1 ); + return 0; +} + + +int get_current( float *ma ) +{ + short shunt; + + if ( register_read( SHUNT_REG, &shunt ) != 0 ) + { + return -1; + } + + *ma = (float)shunt / 10; + return 0; +} + + +void show_current( void ) +{ + float ma; + + if ( get_current( &ma ) ) + { + fprintf( stderr, "Error reading current\n" ); + return; + } + + if ( whole_numbers ) + { + printf( "%4.0f\n", ma ); + } + else + { + printf( "%04.1f\n", ma ); + } +} + + +void show_voltage( void ) +{ + float mv; + + if ( get_voltage( &mv ) ) + { + fprintf( stderr, "Error reading voltage\n" ); + return; + } + printf( "%4.0f\n", mv ); +} + + +void show_voltage_current( void ) +{ + float mv, ma; + + if ( get_current( &ma ) || get_voltage( &mv ) ) + { + fprintf( stderr, "Error reading voltage/current\n" ); + return; + } + + if ( whole_numbers ) + { + printf( "%04.0fmV %4.0fmA\n", mv, ma ); + } + else + { + printf( "%04.0fmV %04.1fmA\n", mv, ma ); + } +} + + +void monitor( void ) +{ + struct tm *tmptr; + time_t seconds; + + while ( 1 ) + { + seconds = time( NULL ); + tmptr = localtime( &seconds ); + printf( "%02d:%02d ", tmptr->tm_hour, tmptr->tm_min ); + show_voltage_current(); + sleep( interval ); + } +} + + +int main( int argc, char *argv[] ) +{ + char filename[ 20 ]; + + parse( argc, argv ); + + snprintf( filename, 19, "/dev/i2c-%d", i2c_bus ); + handle = open( filename, O_RDWR ); + if ( handle < 0 ) + { + fprintf( stderr, "Error opening bus %d: %s\n", i2c_bus, strerror( errno ) ); + exit( 1 ); + } + + if ( ioctl( handle, I2C_SLAVE, i2c_address ) < 0 ) + { + fprintf( stderr, "Error setting address %02X: %s\n", i2c_address, strerror( errno ) ); + exit( 1 ); + } + + switch ( operation ) + { + case OP_DUMP: + { + show_voltage_current(); + break; + } + + case OP_VOLTAGE: + { + show_voltage(); + break; + } + + case OP_CURRENT: + { + show_current(); + break; + } + + case OP_MONITOR: + { + monitor(); + break; + } + + default: + case OP_NONE: + { + break; + } + } + + close( handle ); + return 0; +} + diff --git a/lcdd.c b/lcdd.c new file mode 100644 index 0000000..8cdd85f --- /dev/null +++ b/lcdd.c @@ -0,0 +1,394 @@ +/* Simple daemon to communicate with Newhaven I2C LCD module. + * + * This is a trivial interface for Newhaven LCD module connected to a Linux machine + * over an I2C interface. Any standard Linux I2C bus should work (including USB I2C + * adapters that correctly hook into the i2c kernel driver framework). + * + * Opens a named pipe at /dev/lcd which can be written to by other applications. + * Text written to this file will appear on the LCD. + * Send a bell ('\b')to clear the screen. + * + * Tested with NHD-0420D3Z-FL-GBW (Digikey part number NHD-0420D3Z-FL-GBW-ND). + * http://www.newhavendisplay.com/specs/NHD-0420D3Z-FL-GBW.pdf + * http://www.newhavendisplay.com/index.php?main_page=product_info&cPath=253&products_id=922 + * + * FIXME how to do other commands etc. + * FIXME some rate limiting should be added... the I2C controller on the LCD + * module gets confused if you write to it too fast. + * + * Hardware note: + * To enable I2C mode of LCD, Pads of R1 must be jumpered on back of LCD + * See the manual for the LCD module. + * + * ./lcdd -a 0x47 -d /dev/i2c-4 -f /dev/lcd -n + * + * Hugo Vincent, June 2009 - https://github.com/hugovincent/i2c-lcdd + * Daemonization based on code by Peter Lombardo , 2006 + */ + + +#define _GNU_SOURCE // for strsignal() + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DAEMON_NAME "lcdd" +#define PID_FILE "/var/run/lcdd.pid" + +#define LCD_ADDR 0x27 + +//#define DEBUG + +static int daemonize = 1, running = 1, have_lcd = 1; +static jmp_buf my_jmp_buf; + +#define LOG_MSG(format, ...) if (daemonize == 1) \ + syslog(LOG_INFO, format, ##__VA_ARGS__); \ +else \ +printf("i2c-lcdd: " format "\n", ##__VA_ARGS__); + +void usage(int argc, char **argv) +{ + if (argc >=1) + { + printf("Usage: %s -a 0x50 -d /dev/i2c-3 -f /dev/lcd -n -?\n", argv[0]); + printf(" Options:\n"); + printf(" -a\tI2C slave address (in hex) for LCD module\n"); + printf(" -d\tI2C device\n"); + printf(" -f\tnamed pipe for input\n"); + printf(" -n\tDon't daemonize.\n"); + printf(" -?\tShow this help screen.\n"); + } +} + +void signal_handler(int sig) +{ + LOG_MSG("received signal %s - exiting", strsignal(sig)); + running = 0; +} + +void i2c_send(int fd, uint8_t *buf, int count) +{ + if (have_lcd) + { + if (write(fd, buf, count) != count) + { + LOG_MSG("error writing to I2C: %s", strerror(errno)); + longjmp(my_jmp_buf, EXIT_FAILURE); + //exit(EXIT_FAILURE); + } + } + else + { +#ifdef DEBUG + static char tmp[1024]; + strncpy(tmp, buf, count); + tmp[count] = 0; + printf("I2C send: \"%s\"\n", tmp); +#endif + } +} + +uint8_t linenum_to_cursor(int linenum) +{ + switch (linenum) + { + case 1: + return 0x40; + break; + case 2: + return 0x14; + break; + case 3: + return 0x54; + break; + case 0: + default: + return 0x0; + break; + } +} + +#define min(a, b) ((a <= b) ? a : b) + +void handle_pipe_input(int i2c_fd, char *buffer, int size) +{ + // FIXME this should handle escape sequences (other than \b, \n) too + + static int line_number = 0; + + // LCD clear + if (size >= 1 && buffer[0] == '\b') + { + uint8_t bytes[] = {0xFE, 0x51}; + i2c_send(i2c_fd, bytes, sizeof(bytes)); + buffer++; size--; + line_number = 0; + } + + // Split input into lines + char *line = strtok(buffer, "\n"); + while (line != NULL) + { + // Because of weird cursor positioning on the LCD module, if we write + // more than 20 characters on line 1 it'll flow over onto line 3, (or + // off line 2 on to line 4). Thus, we limit lines to 20 chars. + + i2c_send(i2c_fd, line, min(strlen(line), 20)); + line_number = (line_number < 3) ? (line_number + 1) : 0; + + // Go to specified line + uint8_t bytes[] = {0xFE, 0x45, 0x0}; + bytes[2] = linenum_to_cursor(line_number); + i2c_send(i2c_fd, bytes, sizeof(bytes)); + + // Get next line + line = strtok(NULL, "\n"); + } +} + +int main(int argc, char **argv) +{ + char device[64] = "/dev/i2c-3", fifo_name[64] = "/dev/lcd"; + int addr = LCD_ADDR, addr_sscanf_ret = 1; + + // Setup signal handling before we start + signal(SIGHUP, signal_handler); + siginterrupt(SIGHUP, 1); + signal(SIGQUIT, signal_handler); + siginterrupt(SIGQUIT, 1); + signal(SIGTERM, signal_handler); + siginterrupt(SIGTERM, 1); + signal(SIGINT, signal_handler); + siginterrupt(SIGINT, 1); + + int c; + while( (c = getopt(argc, argv, "a:d:f:n?")) != -1) { + switch(c){ + case 'a': + addr_sscanf_ret = sscanf(optarg, "0x%x", &addr); + break; + case 'd': + strncpy(device, optarg, sizeof(device)); + break; + case 'f': + strncpy(fifo_name, optarg, sizeof(fifo_name)); + break; + case 'n': + daemonize = 0; + break; + case '?': + default: + usage(argc, argv); + exit(0); + break; + } + } + + // Setup syslog logging + if (daemonize == 1) + { + setlogmask(LOG_UPTO(LOG_INFO)); + openlog(DAEMON_NAME, LOG_CONS, LOG_USER); + } + LOG_MSG("daemon starting up"); + + // Check sscanf above worked (delayed until after syslog is initialized) + if (addr_sscanf_ret != 1) + LOG_MSG("supplied address invalid, using 0x%02x", addr); + + // Our process ID and Session ID + pid_t pid, sid; + + if (daemonize) + { + // Fork off the parent process + pid = fork(); + if (pid < 0) + { + LOG_MSG("failed to fork daemon process"); + exit(EXIT_FAILURE); + } + + // If we got a good PID, then we can exit the parent process + if (pid > 0) + exit(EXIT_SUCCESS); + + // Change the file mode mask + umask(0); + + // Create a new SID for the child process + sid = setsid(); + if (sid < 0) + { + LOG_MSG("failed to set daemon process SID"); + exit(EXIT_FAILURE); + } + + // Change the current working directory + if ((chdir("/")) < 0) + { + LOG_MSG("failed to change daemon working directory"); + exit(EXIT_FAILURE); + } + + // Close out the standard file descriptors + close(STDIN_FILENO); +#ifndef DEBUG + close(STDOUT_FILENO); +#endif + close(STDERR_FILENO); + } + + //************************************************************************ + + addr >>= 1; // to suit LCD addressing sematics of Newhaven LCD modules + + // Initialise FIFO on which to accept input + if (mkfifo(fifo_name, S_IRWXU) < 0) + { + if (errno != EEXIST) + { + LOG_MSG("error creating named pipe for input: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + else + { + LOG_MSG("warning, named pipe already exists: %s", strerror(errno)); + // FIXME unlink and reopen + } + } + + // Connect to I2C LCD and set slave address + int i2c_fd = open(device, O_RDWR); + if (i2c_fd < 0) + { + LOG_MSG("error opening device: %s", strerror(errno)); + have_lcd = 0; + goto nolcd; + } + if (ioctl(i2c_fd, I2C_SLAVE, addr) < 0) + { + LOG_MSG("error setting I2C slave address: %s", strerror(errno)); + close(i2c_fd); + have_lcd = 0; + } + +nolcd: + if (setjmp(my_jmp_buf) == EXIT_FAILURE) + goto exit1; + + if (!have_lcd) + { + LOG_MSG("could not open I2C LCD, printing to stdout for debugging"); + } + else + { + LOG_MSG("using Nehaven LCD attached to %s at real address 0x%x", device, addr); + + // Initialise LCD + uint8_t bytes[] = {0xFE, 0x41}; // LCD on + i2c_send(i2c_fd, bytes, sizeof(bytes)); + bytes[1] = 0x51; // LCD clear + i2c_send(i2c_fd, bytes, sizeof(bytes)); + + uint8_t *string = (uint8_t*)" Initialising..."; + i2c_send(i2c_fd, string, strlen((char*)string)); + } + + char buffer[256]; + int fifo_fd = -1; + struct pollfd fds = { .events = POLLIN }; + + // Main Loop: read on named pipe, output on LCD + while (running) + { + if (fifo_fd == -1) + { +#ifdef DEBUG + LOG_MSG("waiting for connection on %s...", fifo_name); +#endif + fifo_fd = open(fifo_name, O_RDONLY); // this will block until other end of pipe is opened + if (fifo_fd < 0) + { + if (errno == EINTR) + continue; + LOG_MSG("error opening named pipe for input: %s", strerror(errno)); + goto exit3; + } + fds.fd = fifo_fd; +#ifdef DEBUG + LOG_MSG("connected, accepting input on %s", fifo_name); +#endif + } + + // Wait for input on the named pipe + int poll_ret = poll(&fds, 1, 1000); + if (poll_ret == 1 && fds.revents | POLLIN) + { + memset(&buffer, 0, sizeof(buffer)); + int bytes_read = read(fifo_fd, &buffer, sizeof(buffer)); + + // Write input to LCD + if (bytes_read > 0) + handle_pipe_input(i2c_fd, buffer, bytes_read); + else if (bytes_read == 0) + { +#ifdef DEBUG + LOG_MSG("named pipe closed"); +#endif + close(fifo_fd); + fifo_fd = -1; + } + else + { + LOG_MSG("error reading from named pipe: %s", strerror(errno)); + goto exit1; + } + } + else if (poll_ret < 0 && running) + { + LOG_MSG("error waiting for input on named pipe: %s", strerror(errno)); + goto exit1; + } + else + { + // Timeout in poll(), no need to worry (timeout is only enabled as insurance anyway) + } + } + + LOG_MSG("daemon exiting cleanly"); + + close(fifo_fd); + unlink(fifo_name); + if (have_lcd) + close(i2c_fd); + + return 0; + + // Cleanup on error +exit1: + if (have_lcd) + close(i2c_fd); +exit2: + close(fifo_fd); +exit3: + unlink(fifo_name); + LOG_MSG("daemon exiting with failure"); + exit(EXIT_FAILURE); +} + diff --git a/lm75.c b/lm75.c new file mode 100644 index 0000000..499ded5 --- /dev/null +++ b/lm75.c @@ -0,0 +1,49 @@ + /* + LM75_address.c + -------------- + 1) set the i2c address of the LM75 + * R/W pulse at end of address byte not included in address 1-0-0-1-A2-A1-A0 + * example - all lines to 0V - 1001000 = decimal 72 + 2) calculate the temperature + 3) print it + usage :- type (without the < >) +
+*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "smbus.h" + +int main(int argc, char** argv) +{ + int address; /* i2c bus address */ + + if (argc != 2) /* report error if we are not getting just 1 input after the program name */ + { + printf("Error. usage: %s i2c_chip_address\n", argv[0]); + } + address = atoi(argv[1]); /* address is the first number after the program name */ + + + int f = open("/dev/i2c-0",O_RDWR); + char buf[2]; + if (f>0) { + ioctl(f,I2C_SLAVE,address); + if (-1 == read(f,buf,2)) { + printf("read error.\n"); + } else { /* calculate the temperature*/ + int temp = buf[0]*256+buf[1]; + temp >>=7; + if (temp>512) + temp &= -1; + printf("Temperature (C)\t\t%g\n", (float)temp/2.0); + } + } + return close(f); + } diff --git a/mcp_rw.c b/mcp_rw.c new file mode 100644 index 0000000..81bf7cd --- /dev/null +++ b/mcp_rw.c @@ -0,0 +1,297 @@ +#include +#include +#include +#include +#include +#include +#include +#include +// Строки ниже необходимы для rasbian/debian.В Suse должны быть закаментированы. +#include +#include "smbus.h" + +#define mcp_I2C_ADDRESS 0x20 // адрес устройства в сети i2c,задается перемычками A0,A1,A2 на микросхеме. + + +// ниже 2 строки задают направление порта ,1 - на ввод,0 - на вывод. +#define mcp_bank_a 0b00000100 //байты 7 по 0 порт +#define mcp_bank_b 0b00000000 //байты 8 по 15 порт +// следущие 2 строки-подтяжка резистором 100 кОм на +, 1 - включен.Актуально для режима на ввод. +#define gppu_bank_a 0b00000100 //байты 7 по 0 порт +#define gppu_bank_b 0b00000000 //байты 8 по 15 порт +// регистры 02 03 для инвертирования +#define iopol_bank_a 0b00000110 //байты 7 по 0 порт +#define iopol_bank_b 0b00000000 //байты 8 по 15 порт + + + + + +int fd; +unsigned int utv; +int l=1; +int x=0; + +// Open a connection to the mcp +// Returns a file id +int mcp_i2c_Begin() +{ + + char *fileName = "/dev/i2c-7"; // указать Ваш адрес + + // Open port for reading and writing + if ((fd = open(fileName, O_RDWR)) < 0){ + printf("i2c device not found \n"); + exit(1); + } + // Set the port options and set the address of the device + if (ioctl(fd, I2C_SLAVE, mcp_I2C_ADDRESS) < 0) { + close(fd); + printf("on i2c mcp device not found \n"); + exit(1); + } + + return fd; +} + +// Read a byte to mcp +__s32 mcp_i2c_Read_byte(int fd, __u8 address) +{ + __s32 res = i2c_smbus_read_byte_data(fd, address); + if (res < 0) { + printf("error \n"); + close(fd); + exit(1); + } + + return res; +} + +//Write a byte to mcp +void mcp_i2c_Write_Byte(int fd, __u8 address, __u8 value) +{ + if (i2c_smbus_write_byte_data(fd, address, value) < 0) { + close(fd); + exit(1); + } +} +// чтение состояния порта +int mcp_read (int mcppin) +{ + if (mcppin < 0 || mcppin >15) { + printf("Please select a valid GPIO pin \n"); + exit(1); + } + + int fd = mcp_i2c_Begin(); + int regbank; + +if (mcppin < 8){ + + mcp_i2c_Write_Byte(fd,0x00,mcp_bank_a); + mcp_i2c_Write_Byte(fd,0x0c,gppu_bank_a); + + regbank=0x12; + +//printf("bank A\n"); +} else { + + mcp_i2c_Write_Byte(fd,0x01,mcp_bank_b); + mcp_i2c_Write_Byte(fd,0x0d,gppu_bank_b); + + regbank=0x13; + mcppin=mcppin-8; + + // printf("bank B\n"); +} + + utv = mcp_i2c_Read_byte(fd,regbank); + + while(x < mcppin) + { + x = x+ 1; + l=l*2; +} + + +if (utv & l) return 1; +else return 0; + +close(fd); + +} + + +// запрос таблицы статусов портов +void mcp_state_in () { + int fd = mcp_i2c_Begin(); + utv = mcp_i2c_Read_byte(fd,0x12); + // printf ("--%d--\n",utv); + while(x < 8) + { + + if ((mcp_bank_a & l)) { + if ((utv & l)) printf ("%d 1\n",x); + else printf ("%d 0\n",x); + +} else printf ("%d -\n",x); + l=l*2; + x = x+ 1; + +} + + x=0; + l=1; + + utv = mcp_i2c_Read_byte(fd,0x13); +// printf ("--%d--\n",utv); + while(x < 8) + { + if ((mcp_bank_b & l)) { + if ((utv & l)) printf ("%d 1\n",x+8); + else printf ("%d 0\n",x+8); + + } else printf ("%d -\n",x+8); + l=l*2; + x = x+ 1; +} + +close(fd); + +} +// установка состояния порта +void mcp_write (int mcppin,int mcpst) +{ + if (mcppin < 0 || mcppin >15) { + printf("Please select a valid GPIO pin \n"); + exit(1); + } + if (mcpst != 0 && mcpst != 1) { + printf("Не верно задан статус порта 0 или 1\n"); + exit(1); + } + + int fd = mcp_i2c_Begin(); + int regbank; + +if (mcppin < 8){ + + mcp_i2c_Write_Byte(fd,0x00,mcp_bank_a); + mcp_i2c_Write_Byte(fd,0x0c,gppu_bank_a); + + regbank=0x14; + +//printf("bank A\n"); +} else { + + mcp_i2c_Write_Byte(fd,0x01,mcp_bank_b); + mcp_i2c_Write_Byte(fd,0x0d,gppu_bank_b); + + regbank=0x15; + mcppin=mcppin-8; + + // printf("bank B\n"); +} + + utv = mcp_i2c_Read_byte(fd,regbank); + + while(x < mcppin) + { + x = x+ 1; + l=l*2; +} + + +if (!(utv & l) && mcpst==1) mcp_i2c_Write_Byte(fd,regbank,utv+l); +if (utv & l && mcpst==0) mcp_i2c_Write_Byte(fd,regbank,utv-l); + +close(fd); + +} + + +// запрос таблицы статусов портов +void mcp_state_out () { + int fd = mcp_i2c_Begin(); + utv = mcp_i2c_Read_byte(fd,0x14); + // printf ("--%d--\n",utv); + while(x < 8) + { + + if (!(mcp_bank_a & l)) { + if ((utv & l)) printf ("%d 1\n",x); + else printf ("%d 0\n",x); + +} else printf ("%d -\n",x); + l=l*2; + x = x+ 1; + +} + + x=0; + l=1; + + utv = mcp_i2c_Read_byte(fd,0x15); +// printf ("--%d--\n",utv); + while(x < 8) + { + if (!(mcp_bank_b & l)) { + if ((utv & l)) printf ("%d 1\n",x+8); + else printf ("%d 0\n",x+8); + + } else printf ("%d -\n",x+8); + l=l*2; + x = x+ 1; +} + +close(fd); + +} +// основное тело программы + +int main(int argc, char **argv) + +{ + if (argc == 1) { + printf("%s <команда>\nin -чтение данных из порта,установленых на ввод\nout-установка состояния порта,установленного на вывод.\n", argv[0]); + return 1; + } + else if (argc == 2) { + if(strcmp(argv[1], "out") == 0) mcp_state_out(); + else if(strcmp(argv[1], "in") == 0) mcp_state_in(); + else printf("Нет такой команды\n"); + return 1; + } + + if(strcmp(argv[1], "out") == 0) { + + if (argc != 4) { + printf("Настройка порта: %s <порт> <состояние>\n", argv[0]); + +return 1; +} +int mcppin = atoi(argv[2]); +int mcpst = atoi(argv[3]); + +mcp_write (mcppin,mcpst); + + + } + else if(strcmp(argv[1], "in")== 0) { + if (argc != 3) { + printf("Чтение одного порта: %s <порт>\n", argv[0]); + mcp_state_in(); + return 1; + } + int mcppin = atoi(argv[2]); + + printf ("%d\n",mcp_read (mcppin)); + + } + + + + + + return 0; +} \ No newline at end of file diff --git a/pcf8574_1.c b/pcf8574_1.c new file mode 100644 index 0000000..f2b8236 --- /dev/null +++ b/pcf8574_1.c @@ -0,0 +1,52 @@ +/* +PCF8574_addr_byteout_slug.c +---------------------- +Send address and byte to switch lines on 8 line port of i2c bus PCF8574 +----------------------------------------------------------------------- + +1) send the i2c address +2) send byte to set the 8 port lines on or off + +usage :- type with spaces but without the < > + + +Home Page - http://www.sunspot.co.uk/Projects/SWEEX/slug/i2c/slug_i2c.html + +*/ +#include +#include +#include +#include +#include +#include +#define I2C_SLAVE0x0703/* Change slave address*/ + +int i2c; +char filename[20]; +unsigned long address; + +int rc; +unsigned char data[1]; +int main(int argc, char *argv[]) +{ +if (argc != 3) { /* error if we are not getting just 2 inputs after the program name */ +fprintf(stderr, "usage: %s
\n",argv[0]); +exit(1); +} + +/* address is the first number after the program name */ +address = atoi(argv[1]); +/* the byte to send out to the PC8574 is the second number +place it into the first element of the buf array */ +data[0] = atoi(argv[2]); + +i2c = open("/dev/i2c-0",O_RDWR); /* open the device dev/i2c-0 */ + +rc=ioctl(i2c,I2C_SLAVE,address); /* set the i2c chip address */ + +write(i2c,data,1) ; /* send the byte */ + +i2c = close(i2c); +return(0); +} + diff --git a/pcf8574_2.c b/pcf8574_2.c new file mode 100644 index 0000000..04af8c3 --- /dev/null +++ b/pcf8574_2.c @@ -0,0 +1,56 @@ +/* +PCF8574_addr_read_slug.c +------------------- +read the data on the 8 line port of an i2c bus PCF8574 +------------------------------------------------------ + +1) set the i2c address of the PCF8574 +2) send data 255 to turn off all 8 lines - make them inputs +3) read the data on the 8 port lines as a byte +usage :- type (without the < >) + + +Home Page - http://www.sunspot.co.uk/Projects/SWEEX/slug/i2c/slug_i2c.html + +*/ + +#include +#include +#include +#include +#include +#include +#define I2C_SLAVE0x0703/* Change slave address*/ + +int i2c; +char filename[20]; +unsigned long address; +int rc; +unsigned char data[1]; +int byte; /* the 8 bit byte that represents the data present on the 8 wire port */ + +int main(int argc, char ** argv) +{ +if (argc != 2) { /* error if we are not getting just 1 input after the program name */ +fprintf(stderr, "usage: %s
\n",argv[0]); +exit(1); +} + +/* address is the first number after the program name */ +address = atoi(argv[1]); + +i2c = open("/dev/i2c-0",O_RDWR); /* open the device dev/i2c-0 */ +rc=ioctl(i2c,I2C_SLAVE,address); /* set the i2c chip address */ + +data[0] = 255; +write(i2c,data,1); /* we send 255 to make all lines go off, ready for input data */ + +read(i2c,data,1); /* now data(0) contains the byte of data on the 8 port lines*/ + +byte = data[0]; + +printf("BYTE = %d \n", byte); +/* BYTE value is 0-256)*/ +i2c = close(i2c); +return(0); +} diff --git a/pcf8574_3.c b/pcf8574_3.c new file mode 100644 index 0000000..1ea2493 --- /dev/null +++ b/pcf8574_3.c @@ -0,0 +1,49 @@ +/* + PCF8574_addr_byteout.c + ---------------------- + Send address and byte to switch lines on 8 line port of i2c bus PCF8574 + ----------------------------------------------------------------------- + + 1) send the i2c address + 2) send byte to set the 8 port lines on or off + + usage :- type with spaces but without the < > +
+ +*/ + +#include +#include +#include +#include +#include + + int i2c; + int buf[1]; + int address; + +int main(int argc, char** argv) +{ + if (argc != 3) /* error if we are not getting just 2 inputs after the program name */ + { + printf("Error. usage: %s i2c_chip_address byte_to_send_out\n", argv[0]); + } + +/* address is the first number after the program name */ + address = atoi(argv[1]); + +/* the byte to send out to the PC8574 is the second number */ + +/* place it into the first element of the buf array */ + buf[0] = atoi(argv[2]); + + i2c = open("/dev/i2c/0",O_RDWR); /* open the device on i2c-bus number 0*/ + + ioctl(i2c,I2C_SLAVE, address); /* set the i2c chip address */ + + write(i2c,buf,1); /* send the byte */ + + i2c = close(i2c); + +} + diff --git a/pcf8574_4.c b/pcf8574_4.c new file mode 100644 index 0000000..d07add9 --- /dev/null +++ b/pcf8574_4.c @@ -0,0 +1,50 @@ +/* + PCF8574_addr_read.c + ------------------- +read the data on the 8 line port of an i2c bus PCF8574 +------------------------------------------------------ + +1) set the i2c address of the PCF8574 +2) send data 255 to turn off all 8 lines - make them inputs +3) read the data on the 8 port lines as a byte + usage :- type (without the < >) + +*/ + +#include +#include +#include +#include +#include + + int i2c; + int buf[1]; + int address; /* i2c bus address of the PCF8574 */ + int byte; /* the 8 bit byte that represents the data present on the 8 wire port */ + +int main(int argc, char** argv) +{ + if (argc != 2) /* report error if we are not getting just 1 input after the program name */ + { + printf("Error. usage: %s i2c_chip_address\n", argv[0]); + } + + address = atoi(argv[1]); /* address is the first number after the program name */ + + i2c = open("/dev/i2c/0",O_RDWR); /* open the i2c-bus number 0 */ + + ioctl(i2c,I2C_SLAVE, address); /* set the address of the chip we will talk to */ + + buf[0] = 255; + write(i2c,buf,1); /* we send 255 to make all lines go off, ready for input data */ + + read(i2c,buf,1); /* now buf(0) contains the byte of data on the 8 port lines*/ + + byte = buf[0]; + + printf("BYTE = %d \n", byte); +/* BYTE value is 0-256)*/ + + i2c = close(i2c); +} + diff --git a/pcf8591_1.c b/pcf8591_1.c new file mode 100644 index 0000000..17954ea --- /dev/null +++ b/pcf8591_1.c @@ -0,0 +1,95 @@ +/* +PCF8591-all-lines_addr_V-slug.c +--------------------- +read the voltage on all A/D lines (0-3) and set the output voltage on the D/A pin +--------------------------------------------------------------------------------- + +1) send the i2c address +3) send byte for D/A out +3) read all 4 A/D lines +usage :- type with spaces but without the < > +
+(even if the D/A pin is unused type in any value 0-255) +*/ + +#include +#include +#include +#include +#include +#include +#define I2C_SLAVE0x0703/* Change slave address*/ +int i2c; +int AD_line; /* line number 0-3 */ +int V_out; /* value for the D/A out line */ +unsigned char buf[1]; /* use to feed the i2c driver */ +unsigned long address; /* i2c bus address */ +int byte_in_0; /* the 8 bit byte that represents the voltage on the AD_line */ +int AD_line_0; /* volts byte on line number 0 */ +int AD_line_1; /* volts byte on line number 1 */ +int AD_line_2; /* volts byte on line number 2 */ +int AD_line_3; /* volts byte on line number 3 */ +int rc; + +int main(int argc, char** argv) +{ +if (argc != 3) /* report error if we are not getting just 2 inputs after the program name */ + +{ + +printf("Error. usage: %s i2c_chip_address D/A_Vout(0-255)\n", argv[0]); + +} + +address = atoi(argv[1]); /* address is the first number after the program name */ + +V_out = atoi(argv[2]); /* A/D input line 0-3 */ + +i2c = open("/dev/i2c-0",O_RDWR); /* open the device dev/i2c-0 */ +rc=ioctl(i2c,I2C_SLAVE,address); /* set the i2c chip address */ + +AD_line = 0 + 64; /* enable the D/A output pin 0*/ +buf[0] = AD_line; /* A/D input line number is the first data byte sent */ +buf[1] = V_out; /* D/A out value is the second data byte sent */ +write(i2c,buf,2); /* we send 2 bytes */ +read(i2c,buf,1); /* buf(0) contains the byte of data in the chip cache */ +sleep (1); /* do it again */ +read(i2c,buf,1); /* buf(0) now contains the byte of data from the most recent analogue input*/ +AD_line_0 = buf[0]; + +AD_line = 1 + 64; /* enable the D/A output pin 0*/ +buf[0] = AD_line; /* A/D input line number is the first data byte sent */ +buf[1] = V_out; /* D/A out value is the second data byte sent */ +write(i2c,buf,2); /* we send 2 bytes */ +read(i2c,buf,1); /* buf(0) contains the byte of data in the chip cache */ +//sleep (1); /* do it again */ +// read(i2c,buf,1); /* buf(0) now contains the byte of data from the most recent analogue input*/ +AD_line_1 = buf[0]; + +AD_line = 2 + 64; /* enable the D/A output pin 0*/ +buf[0] = AD_line; /* A/D input line number is the first data byte sent */ +buf[1] = V_out; /* D/A out value is the second data byte sent */ +write(i2c,buf,2); /* we send 2 bytes */ +read(i2c,buf,1); /* buf(0) contains the byte of data in the chip cache */ +//sleep (1); /* do it again */ +// read(i2c,buf,1); /* buf(0) now contains the byte of data from the most recent analogue input*/ +AD_line_2 = buf[0]; + +AD_line = 3 + 64; /* enable the D/A output pin 0*/ +buf[0] = AD_line; /* A/D input line number is the first data byte sent */ +buf[1] = V_out; /* D/A out value is the second data byte sent */ +write(i2c,buf,2); /* we send 2 bytes */ +read(i2c,buf,1); /* buf(0) contains the byte of data in the chip cache */ +//sleep (1); /* do it again */ +// read(i2c,buf,1); /* buf(0) now contains the byte of data from the most recent analogue input*/ +AD_line_3 = buf[0]; + +printf("A/D line 0 = %d \n", AD_line_0, " "); +printf("A/D line 1 = %d \n", AD_line_1, " "); +printf("A/D line 2 = %d \n", AD_line_2, " "); +printf("A/D line 3 = %d \n", AD_line_3, " "); +/*AD_line_x goes 0 to 255 as voltage input goes from 0 to supply voltage*/ + +i2c = close(i2c); +return(0); +} diff --git a/pcf8591_2.c b/pcf8591_2.c new file mode 100644 index 0000000..cbbc2ed --- /dev/null +++ b/pcf8591_2.c @@ -0,0 +1,73 @@ +/* + PCF8591_addr_line.c + ------------------- + read the voltage on one A/D line (0-3) and set the output voltage on the D/A pin + -------------------------------------------------------------------------------- + + 1) send the i2c address as decimal + 2) send A/D line number (program adds 64 to enable D/A in control register) + 3) send byte for D/A out + 4) read the chosen A/D - print it as a raw decimal 0 to 255 + 5) save the chosen port value to /var/www/ramdisk/AtoD.dat + usage :- type with spaces but without the < > +
+ (even if the D/A pin is unused type in any value 0-255) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "smbus.h" + + +int main(int argc, char** argv) +{ + int i2c; + int AD_line; /* line number 0-3 */ + int V_out; /* value for the D/A out line */ + int buf[1]; /* use to feed the i2c driver */ + int address; /* i2c bus address */ + int byte_in_0; /* the 8 bit byte that represents the voltage on the AD_line */ + + if (argc != 4) /* report error if we are not getting just 3 inputs after the program name */ + { + printf("Error. usage: %s i2c_chip_address A/D_line_(0-3) D/A_Vout(0-255)\n", argv[0]); + } + + address = atoi(argv[1]); /* address is the first number after the program name */ + AD_line = atoi(argv[2]); /* A/D input line 0-3 */ + AD_line = AD_line + 64; /* enable the D/A output pin */ + V_out = atoi(argv[3]); /* A/D input line 0-3 */ + + i2c = open("/dev/i2c/0",O_RDWR); /* open the i2c-bus number 0 */ + + ioctl(i2c,I2C_SLAVE, address); /* set the i2c-bus address of the chip we will talk to */ + + buf[0] = AD_line; /* A/D input line number is the first data byte sent */ + buf[1] = V_out; /* D/A out value is the second data byte sent */ + + write(i2c,buf,2); /* we send 2 bytes */ + + read(i2c,buf,1); /* buf(0) contains the byte of data in the chip cache */ + /* do it again */ + read(i2c,buf,1); /* buf(0) now contains the byte of data from the most recent analogue input*/ + + printf("BYTE = %d \n", buf[0]); + printf("%d\n", buf[0]); + /* buf[0] is an integer. It goes 0 to 255 as voltage input goes from 0 to supply voltage*/ + + //save AtoD byte to ramdisk + FILE *f; + f = fopen("/tmp/AtoD.dat","w"); + fprintf(f, "%d", buf[0]); + fclose(f); + + i2c = close(i2c); +} + + diff --git a/pcf8591_3.c b/pcf8591_3.c new file mode 100644 index 0000000..acb0e4a --- /dev/null +++ b/pcf8591_3.c @@ -0,0 +1,66 @@ +/* +PCF8591_address_channel_Vout.c +------------------------------ +read the voltage on one A/D lines (0-3) and set the output voltage on the D/A pin +--------------------------------------------------------------------------------- + +1) send the i2c address +2) choose channel 0-3 +3) send byte for D/A out +3) read channel volts as (0 to 255) / 255 x 5V +usage :- type with spaces but without the < > +
+(even if the D/A pin is unused type in any value 0-255) +*/ + +#include +#include +#include +#include +#include +#include +#define I2C_SLAVE0x0703/* Change slave address*/ +int i2c; +int channel; /* line number 0-3 */ +int V_out; /* value for the D/A out line */ +unsigned char buf[1]; /* use to feed the i2c driver */ +unsigned long address; /* i2c bus address */ +int byte_in_0; /* the 8 bit byte that represents the voltage on the AD_line */ +int AD_input; /* volts byte on chosen channel */ + +int rc; + +int main(int argc, char** argv) +{ +if (argc != 4) /* report error if we are not getting just 3 inputs after the program name */ +{ +printf("Error. usage: %s i2c_chip_address channel_to_read D/A_Vout(0-255)\n", argv[0]); +} + +address = atoi(argv[1]); /* decimal address is the first number after the program name */ +channel = atoi(argv[2]); /* choose A to D line to read 0-3 */ +V_out = atoi(argv[3]); /* volts out as decimal 0-255 */ + +i2c = open("/dev/i2c-0",O_RDWR); /* open the device dev/i2c-0 */ +rc=ioctl(i2c,I2C_SLAVE,address); /* set the i2c chip address */ + +channel = channel + 64; /* enable the D/A output */ +buf[0] = channel; /* A/D input line number is the first data byte sent */ +buf[1] = V_out; /* D/A out value is the second data byte sent */ +write(i2c,buf,2); /* we send 2 bytes */ +read(i2c,buf,1); /* buf(0) contains the byte of data in the chip cache */ +usleep (1000); /* do it again */ +read(i2c,buf,1); /* buf(0) now contains the byte of data from the most recent analogue input*/ +AD_input = buf[0]; + + + +printf("%d", AD_input); + + + +/*AD_line_x goes 0 to 255 as voltage input goes from 0 to supply voltage*/ + +i2c = close(i2c); +return(0); +} diff --git a/pcf8591_4.c b/pcf8591_4.c new file mode 100644 index 0000000..0a40ad6 --- /dev/null +++ b/pcf8591_4.c @@ -0,0 +1,112 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "smbus.h" +#include /* sudo apt-get install libncurses5-dev */ + +// gcc -o pcf8591_2 -lncurses pcf8591_2.c + +int main( int argc, char **argv ) +{ + int i; + int r; + int fd; + int aout; + unsigned char command[2]; + unsigned char value[4]; + unsigned char str[8]; + useconds_t delay = 5000; + + char *dev = "/dev/i2c-0"; + int addr = 0x48; + + int j; + int key; + + initscr(); + noecho(); + cbreak(); + nodelay(stdscr, true); + curs_set(0); + printw("PCF8591"); + + mvaddstr(10, 0, "Brightness"); + mvaddstr(12, 0, "Temperature"); + mvaddstr(14, 0, "?"); + mvaddstr(16, 0, "Resistor"); + refresh(); + fd = open(dev, O_RDWR ); + if(fd < 0) + { + perror("Opening i2c device node\n"); + return 1; + } + + r = ioctl(fd, I2C_SLAVE, addr); + if(r < 0) + { + perror("Selecting i2c device\n"); + } + + command[1] = 0; + aout = 0; + while(1) + { + for(i = 0; i < 4; i++) + { + command[1]=aout++; + command[0] = 0x40 | ((i + 1) & 0x03); // output enable | read input i + r = write(fd, &command, 2); + usleep(delay); + // the read is always one step behind the selected input + r = read(fd, &value[i], 1); + if(r != 1) + { + perror("reading i2c device\n"); + } + usleep(delay); + + sprintf(str, "%3d", value[i]); + mvaddstr(10+i+i, 12, str); + value[i] = value[i] / 4; + move(10 + i + i, 16); + + for(j = 0; j < 64; j++) + { + if(j < value[i]) + { + addch('*'); + } + else + { + addch(' '); + } + } + } + refresh(); + + key = getch(); + if(key == 43) + { + command[1]++; + } + else if(key == 45) + { + command[1]--; + } + else if(key > -1) + { + break; + } + } + + endwin(); + close(fd); + printf("%d\n", key); + return(0); +} \ No newline at end of file diff --git a/pcf8591d.c b/pcf8591d.c new file mode 100644 index 0000000..3613538 --- /dev/null +++ b/pcf8591d.c @@ -0,0 +1,67 @@ +//*************************************************** +// pcf8591d.c +// +// Example to read A/D values from a +// 4 channel / 8 bit AD converter PCF8591 +// through I2C using the I2C driver improved by +// Geert Vancompernolle +// http://www.acmesystems.it/?id=10 +//*************************************************** + +#include "stdio.h" +#include "stdlib.h" +#include "unistd.h" +#include "sys/ioctl.h" +#include "fcntl.h" +#include "time.h" +#include "string.h" + +#include "i2c_errno.h" +#include "etraxi2c.h" + + +int main( int argc, char **argv ) { + int rtc; + int fd_i2c; + I2C_DATA i2c_d; + int ch; + + printf("Reading from a PCF8591 (4 chanel A/D at 8 bits with I2C bus)\n"); + + fd_i2c = open( "/dev/i2c-0", O_RDWR ); + if (fd_i2c<=0) { + printf( "Open error on /dev/i2c\n" ); + exit( 1 ); + } + + // PCF8591 address scheme + // | 1 | 0 | 0 | 1 | A2 | A1 | A0 | R/W | +// i2c_d.slave =(0x09<<4)|(0x01<<1); + + i2c_d.slave = 0x48; + + for (ch=0;ch<=3;ch++) { + // Select the A/D channel + i2c_d.wbuf[0] = ch; + i2c_d.wlen = 1; + if ((rtc=ioctl(fd_i2c,_IO( ETRAXI2C_IOCTYPE, I2C_WRITE), &i2c_d))!=EI2CNOERRORS) { + close(fd_i2c); + printf( "Error %d on line %d\n",rtc,__LINE__); + return ( -1 ); + } + + i2c_d.rlen = 3; + if ((rtc=ioctl(fd_i2c,_IO( ETRAXI2C_IOCTYPE, I2C_READ), &i2c_d))!=EI2CNOERRORS) { + close(fd_i2c); + printf( "Error %d on line %d\n",rtc,__LINE__); + return ( -1 ); + } + + // Show the voltage level + printf("Chanel %d = %.2fv (%02X hex)\n",ch,i2c_d.rbuf[2]*0.012941,i2c_d.rbuf[2]); + } + + close(fd_i2c); + return(0); +} + diff --git a/sethwclock b/sethwclock new file mode 100644 index 0000000..40e94d7 --- /dev/null +++ b/sethwclock @@ -0,0 +1,26 @@ +#!/bin/sh + +I2CBUS=0 +I2CADDR=0x68 + +if [ "$1" == "" ] +then + date=`date -u +%Y%m%d%H%M%S` +else + date=$1 +fi + +year=${date:2:2} +month=${date:4:2} +day=${date:6:2} + +hour=${date:8:2} +min=${date:10:2} +sec=${date:12:2} + +i2cset -y $I2CBUS $I2CADDR 0 0x$sec +i2cset -y $I2CBUS $I2CADDR 1 0x$min +i2cset -y $I2CBUS $I2CADDR 2 0x$hour +i2cset -y $I2CBUS $I2CADDR 4 0x$day +i2cset -y $I2CBUS $I2CADDR 5 0x$month +i2cset -y $I2CBUS $I2CADDR 6 0x$year diff --git a/sht21.c b/sht21.c new file mode 100644 index 0000000..4a415a6 --- /dev/null +++ b/sht21.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include + +#include /* add by paulerr*/ + + +#define CHIP "/dev/i2c-0" +#define CHIP_ADDR 0x40 //HTU21D地址 +#define READ_TEMP 0XE3 //温度转换命令 +#define READ_HUM 0XE5 //湿度转换命令 + +/* More info: https://github.com/kingmacth/Openwet-SDK/tree/master/package/HTU21D */ + +unsigned char HTU21D_Check_CRC(unsigned short int message_from_sensor,unsigned char check_value_from_sensor); + +int main() + +{ + printf("hello,this is HTU21D tester \n"); + int fd =open(CHIP, O_RDWR); + if (fd< 0) { + printf("open"CHIP"failed \n"); + goto exit; + } + + if (ioctl(fd,I2C_SLAVE_FORCE, CHIP_ADDR) < 0) { /*设置芯片地址 */ + printf("oictl:setslave address failed\n"); + goto close; + } + + struct i2c_msg msg; + + unsigned char rddata[3]; + unsigned char rdaddr[2] = {0x10, 0}; /* 将要读取的数据在芯片中的偏移量 */ + unsigned char TempAddr[2] = {0xe3, 0}; /* 发送E3读取温度 */ + unsigned char HumAddr[2] = {0xE5, 0}; /* 发送E5读取湿度 */ + unsigned short int tmp_dat,CRC_Result; + float Temp,Hum; + /*printf("inputa char you want to write to E2PROM\n"); + wrbuf[2]= getchar(); + printf("writereturn:%d, write data:%x\n", write(fd, wrbuf, 1), wrbuf[2]); + sleep(5);*/ + //printf("Read temp!\n",write(fd, TempAddr, 1)); /* 开启温度转换 */ + write(fd, TempAddr, 1); + usleep(100000); + read(fd, &rddata, 3); //读取两字节温度一字节校验 + + tmp_dat=rddata[0]; + tmp_dat=tmp_dat<<8; + tmp_dat=tmp_dat+rddata[1]; + //printf("rddata:%x%02x,%x\n", rddata[0], rddata[1],rddata[2]); + CRC_Result=HTU21D_Check_CRC(tmp_dat,rddata[2]); + //printf("CRC=%x,%x\n",CRC_Result ,tmp_dat);//CRC校验 + if(CRC_Result==0) + { + Temp=(tmp_dat*175.72)/65536-46.85; + printf("Temp=%.2f\n",Temp); + } + //printf("Read hum!\n",write(fd, HumAddr, 1)); /* 开启湿度转换 */ + write(fd, HumAddr, 1); + usleep(100000); + read(fd, &rddata, 3); //读取两字节湿度一字节校验 + + tmp_dat=rddata[0]; + tmp_dat=tmp_dat<<8; + tmp_dat=tmp_dat+rddata[1]; + //printf("rddata:%x%02x,%x\n", rddata[0], rddata[1],rddata[2]); + CRC_Result=HTU21D_Check_CRC(tmp_dat,rddata[2]); + //printf("CRC=%x,%x\n",CRC_Result ,tmp_dat);//CRC校验 + if(CRC_Result==0) + { + Temp=(tmp_dat*125)/65536-6; + printf("Hum=%.2f%%RH\n",Temp); + } + +close: + close(fd); +exit: + return 0; + +} + +//************************************************************************************************************** +//两个参数一个是传感器的源数据,另一个是传感器得出的CRC校验值 +//如果校验通过返回0,不通过返回非0 +//From: http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html +//POLYNOMIAL = 0x0131 = x^8 + x^5 + x^4 + 1 : http://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks +#define SHIFTED_DIVISOR 0x988000 //This is the 0x0131 polynomial shifted to farthest left of three bytes +//************************************************************************************************************** +unsigned char HTU21D_Check_CRC(unsigned short int message_from_sensor,unsigned char check_value_from_sensor) +{ +unsigned char i; +//Test cases from datasheet: +//message = 0xDC, checkvalue is 0x79 +//message = 0x683A, checkvalue is 0x7C +//message = 0x4E85, checkvalue is 0x6B +unsigned int remainder = (unsigned int)message_from_sensor << 8; //Pad with 8 bits because we have to add in the check value +unsigned int divsor = (unsigned int)SHIFTED_DIVISOR; +remainder |= check_value_from_sensor; //Add on the check value +for (i = 0 ; i < 16 ; i++) //Operate on only 16 positions of max 24. The remaining 8 are our remainder and should be zero when we're done. +{ +if( remainder & (unsigned int)1<<(23 - i) ) //Check if there is a one in the left position +remainder ^= divsor; +divsor>>=1;//Rotatethedivsormax16timessothatwehave8bitsleftofaremainder +} +return(unsigned char)remainder; +} diff --git a/smbus.c b/smbus.c new file mode 100644 index 0000000..623519e --- /dev/null +++ b/smbus.c @@ -0,0 +1,228 @@ +/* + smbus.c - SMBus level access helper functions + + Copyright (C) 1995-97 Simon G. Vogl + Copyright (C) 1998-99 Frodo Looijaard + Copyright (C) 2012 Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. +*/ + +#include +#include "smbus.h" // NB: Path changed! +#include +#include +#include +#include + +//NB: Added by John Burns +#ifndef NULL +#define NULL 0 +#endif + +/* Compatibility defines */ +#ifndef I2C_SMBUS_I2C_BLOCK_BROKEN +#define I2C_SMBUS_I2C_BLOCK_BROKEN I2C_SMBUS_I2C_BLOCK_DATA +#endif +#ifndef I2C_FUNC_SMBUS_PEC +#define I2C_FUNC_SMBUS_PEC I2C_FUNC_SMBUS_HWPEC_CALC +#endif + +__s32 i2c_smbus_access(int file, char read_write, __u8 command, + int size, union i2c_smbus_data *data) +{ + struct i2c_smbus_ioctl_data args; + __s32 err; + + args.read_write = read_write; + args.command = command; + args.size = size; + args.data = data; + + err = ioctl(file, I2C_SMBUS, &args); + if (err == -1) + err = -errno; + return err; +} + + +__s32 i2c_smbus_write_quick(int file, __u8 value) +{ + return i2c_smbus_access(file, value, 0, I2C_SMBUS_QUICK, NULL); +} + +__s32 i2c_smbus_read_byte(int file) +{ + union i2c_smbus_data data; + int err; + + err = i2c_smbus_access(file, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data); + if (err < 0) + return err; + + return 0x0FF & data.byte; +} + +__s32 i2c_smbus_write_byte(int file, __u8 value) +{ + return i2c_smbus_access(file, I2C_SMBUS_WRITE, value, + I2C_SMBUS_BYTE, NULL); +} + +__s32 i2c_smbus_read_byte_data(int file, __u8 command) +{ + union i2c_smbus_data data; + int err; + + err = i2c_smbus_access(file, I2C_SMBUS_READ, command, + I2C_SMBUS_BYTE_DATA, &data); + if (err < 0) + return err; + + return 0x0FF & data.byte; +} + +__s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value) +{ + union i2c_smbus_data data; + data.byte = value; + return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_BYTE_DATA, &data); +} + +__s32 i2c_smbus_read_word_data(int file, __u8 command) +{ + union i2c_smbus_data data; + int err; + + err = i2c_smbus_access(file, I2C_SMBUS_READ, command, + I2C_SMBUS_WORD_DATA, &data); + if (err < 0) + return err; + + return 0x0FFFF & data.word; +} + +__s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value) +{ + union i2c_smbus_data data; + data.word = value; + return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_WORD_DATA, &data); +} + +__s32 i2c_smbus_process_call(int file, __u8 command, __u16 value) +{ + union i2c_smbus_data data; + data.word = value; + if (i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_PROC_CALL, &data)) + return -1; + else + return 0x0FFFF & data.word; +} + +/* Returns the number of read bytes */ +__s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values) +{ + union i2c_smbus_data data; + int i, err; + + err = i2c_smbus_access(file, I2C_SMBUS_READ, command, + I2C_SMBUS_BLOCK_DATA, &data); + if (err < 0) + return err; + + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; +} + +__s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, + const __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_BLOCK_DATA, &data); +} + +/* Returns the number of read bytes */ +/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you + ask for less than 32 bytes, your code will only work with kernels + 2.6.23 and later. */ +__s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length, + __u8 *values) +{ + union i2c_smbus_data data; + int i, err; + + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; + data.block[0] = length; + + err = i2c_smbus_access(file, I2C_SMBUS_READ, command, + length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN : + I2C_SMBUS_I2C_BLOCK_DATA, &data); + if (err < 0) + return err; + + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; +} + +__s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length, + const __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_I2C_BLOCK_BROKEN, &data); +} + +/* Returns the number of read bytes */ +__s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length, + __u8 *values) +{ + union i2c_smbus_data data; + int i, err; + + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + + err = i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_BLOCK_PROC_CALL, &data); + if (err < 0) + return err; + + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; +} diff --git a/smbus.h b/smbus.h new file mode 100644 index 0000000..b7facf6 --- /dev/null +++ b/smbus.h @@ -0,0 +1,59 @@ +/* + smbus.h - SMBus level access helper functions + + Copyright (C) 1995-97 Simon G. Vogl + Copyright (C) 1998-99 Frodo Looijaard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. +*/ + +#ifndef LIB_I2C_SMBUS_H +#define LIB_I2C_SMBUS_H + +#include +#include + +extern __s32 i2c_smbus_access(int file, char read_write, __u8 command, + int size, union i2c_smbus_data *data); + +extern __s32 i2c_smbus_write_quick(int file, __u8 value); +extern __s32 i2c_smbus_read_byte(int file); +extern __s32 i2c_smbus_write_byte(int file, __u8 value); +extern __s32 i2c_smbus_read_byte_data(int file, __u8 command); +extern __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value); +extern __s32 i2c_smbus_read_word_data(int file, __u8 command); +extern __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value); +extern __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value); + +/* Returns the number of read bytes */ +extern __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values); +extern __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, + const __u8 *values); + +/* Returns the number of read bytes */ +/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you + ask for less than 32 bytes, your code will only work with kernels + 2.6.23 and later. */ +extern __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length, + __u8 *values); +extern __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length, + const __u8 *values); + +/* Returns the number of read bytes */ +extern __s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length, + __u8 *values); + +#endif /* LIB_I2C_SMBUS_H */ diff --git a/syncfromhwclock b/syncfromhwclock new file mode 100644 index 0000000..e07d3ba --- /dev/null +++ b/syncfromhwclock @@ -0,0 +1,3 @@ +#!/bin/sh + +date -u -s "`gethwclock`" -- 2.34.1