tmp75 userspace driver
[linux-gpio-pinout] / i2c-userspace / tmp.c
1 // https://github.com/ManuelSchneid3r/RaspberryPi/raw/master/sensors/src/tmp.c
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <linux/i2c-dev.h>
6 #include <fcntl.h>
7 #include <unistd.h>
8 #include <sys/ioctl.h>
9 #include <getopt.h>
10 #include <math.h>
11
12 void print_usage(char * appname) {
13     printf("Usage: %s  [--resolution|-r<0-3>][--faultqueue|-f<0-3>][--oneshot|--nooneshot][--activehigh|--activelow][--interruptmode|--comparatormode][--shutdownmode|--noshutdownmode][--query] <i2c char device> <hex address>\n", appname);
14 }
15
16 void print_help(char * appname) {
17   print_usage(appname);
18   printf(
19       "\n"
20       "\t--shutdownmode, --noshutdownmode\n"
21       "\t\tThe Shutdown Mode allows the user to save maximum power by shutting down all device circuitry other than the serial interface, which reduces current consumption to typically less than 0.1 μA.\n\n"
22       "\t--oneshot, --nooneshot\n"
23       "\t\tThe TMP175 and TMP75 feature a One-Shot Temperature Measurement Mode. When the device is in Shutdown Mode, writing 1 to the OS bit will start a single temperature conversion. The device will return to the shutdown state at the completion of the single conversion. This is useful to reduce power consumption in the TMP175 and TMP75 when continuous temperature monitoring is not required.\n\n"
24       "\t--interruptmode, --comparatormode\n"
25       "\t\tThe Thermostat Mode bit of the TMP175 and TMP75 indicates to the device whether to operate in Comparator Mode or Interrupt Mode (Alert pin). In Comparator mode, the ALERT pin is activated when the temperature equals or exceeds the value in the T(HIGH) register and it remains active until the temperature falls below the value in the T(LOW)register. In Interrupt mode, the ALERT pin is activated when the temperature exceeds T(HIGH) or goes below T(LOW) registers. The ALERT pin is cleared when the host controller reads the temperature register. For more information see the sensors datasheet.\n\n"
26       "\t--activehigh, --activelow\n"
27       "\t\tThe Polarity Bit of the TMP175 lets the user adjust the polarity of the ALERT pin output. If the POL bit is set to 0 (default), the ALERT pin becomes active low. When POL bit is set to 1, the ALERT pin becomes active high and the state of the ALERT pin is inverted.\n\n"
28       "\t--faultqueue, -f=N\n"
29       "\t\tA fault condition is defined as when the measured temperature exceeds the user-defined limits set in the THIGH and TLOW Registers. Additionally, the number of fault conditions required to generate an alert may be programmed using the Fault Queue. The Fault Queue is provided to prevent a false alert as a result of environmental noise. The Fault Queue requires consecutive fault measurements in order to trigger the alert function.\n\n"
30       "\t--resolution, -r={0, 1, 2, 3}\n"
31       "\t\tThe Converter Resolution Bits control the resolution of the internal analog-to-digital (ADC) converter. This control allows the user to maximize efficiency by programming for higher resolution or faster conversion time. \n\n"
32       "\tR\tRESOLUTION\t(TYPICAL) CONVERSION TIME \n"
33       "\t0\t0.5°C\t\t27.5 ms\n"
34       "\t1\t0.25°C\t\t55 ms\n"
35       "\t2\t0.125°C\t\t110 ms\n"
36       "\t3\t0.0625°C\t220 ms\n"
37       "\t--query, -q\n"
38       "\t\tQueries the current cofiguration.\n\n"
39       "\t--help\n"
40       "\t\tPrint this help\n\n"
41       "Author: Manuel Schneider manuelschneid3r@googles mail server\n"
42       );
43 }
44
45 void err_write(int fd, const void *buf, size_t count) {
46   if ((write(fd, buf, count)) != count) {
47     printf("Error writing to i2c slave.\n");
48     exit(1);
49   }
50 }
51
52 void err_read(int fd, void *buf, size_t count) {
53   if (read(fd, buf, count) != count) {
54     printf("Unable to read from slave.\n");
55     exit(1);
56   }
57 }
58
59 struct config_t {
60   int OS;   // Oneshot mode bool
61   int RES;  // Resolution 0-3
62   int FQ;   // Faultqueue 0-3
63   int POL;  // Polarity bool
64   int TM;   // Termostat xor
65   int SD;   // Shutdownmode bool
66 };
67
68 int main(int argc, char **argv)
69 {
70   static struct config_t config = {-1,-1,-1,-1,-1,-1};
71   static int query = 0;
72   static int c;
73   static int help = 0;
74
75   static struct option long_options[] =
76   {
77     {"oneshot",         no_argument,       &config.OS,  1},
78     {"nooneshot",       no_argument,       &config.OS,  0},
79     {"resolution",      required_argument, 0,           'r'},
80     {"faultqueue",      required_argument, 0,           'f'},
81     {"activehigh",      no_argument,       &config.POL, 1},
82     {"activelow",       no_argument,       &config.POL, 0},
83     {"interruptmode",   no_argument,       &config.TM,  1},
84     {"comparatormode",  no_argument,       &config.TM,  0},
85     {"shutdownmode",    no_argument,       &config.SD,  1},
86     {"noshutdownmode",  no_argument,       &config.SD,  0},
87     {"query",           no_argument,       0,           'q'},
88     {"help",            no_argument,       &help,       1},
89     {0, 0, 0, 0}
90   };
91
92   /*
93    * Get the parameters and set the relevant flags for operation.
94    */
95   int option_index = 0;
96   while ((c = getopt_long (argc, argv, "qr:f:",
97                            long_options, &option_index)) != -1)
98   {
99     switch (c)
100     {
101     case 0:
102       // getopt_long set flag to val
103       break;
104     case 'q':
105       query = 1;
106       break;
107     case 'f':
108       config.FQ = atoi(optarg);
109       if (config.FQ < 0 || config.FQ > 3){
110         printf("Invalid fault queue parameter\n");
111         exit(1);
112       }
113       break;
114     case 'r':
115       config.RES = atoi(optarg);
116       if (config.RES < 0 || config.RES > 3){
117         printf("Invalid resoltion parameter\n");
118         exit(1);
119       }
120       break;
121     case '?':
122       /* getopt_long already printed an error message. */
123       return 1;
124     default:
125       abort ();
126     }
127   }
128
129   // Print help if requested
130   if (help==1) {
131     print_help(argv[0]);
132     exit(0);
133   }
134
135   // Print usage mesage in case of a wrong amount of params
136   if ((argc-optind) != 2){
137     print_usage(argv[0]);
138     exit(1);
139   }
140
141   /*
142    * Now start with the initializaton of the communication
143    */
144   // Open port for reading and writing
145   int fd;
146   if ((fd = open(argv[optind], O_RDWR)) < 0) {
147     printf("Failed to open i2c port. Root?\n");
148     exit(1);
149   }
150
151   // Set the port options and the address of the device we wish to speak to
152   int  address = strtol(argv[optind+1], NULL, 0);
153   if (ioctl(fd, I2C_SLAVE, address) < 0) {
154     printf("Unable to get bus access to talk to slave.\n");
155     exit(1);
156   }
157
158
159   /*
160    * If the program was called with any of the configuration parameters get the
161    * config resister, modifiy it and write it bac to the IC.
162    */
163   if (config.OS  != -1 || config.RES != -1 || config.FQ  != -1 ||
164       config.POL != -1 || config.TM  != -1 || config.SD  != -1) {
165     // Set register pointer on IC to config register
166     unsigned char buf[2] = {1, 0};
167     err_write(fd, buf, 1);
168
169     // Read configuration register
170     err_read(fd, buf+1, 1);
171
172     // Set or unset the bits
173     if (config.OS != -1)
174       config.OS ? buf[1]|(1<<7) : buf[1]&~(1<<7);
175     if (config.RES != -1){
176       buf[1]&=~(3<<5); // Unset the resolution
177       buf[1]|=config.RES<<5; //Set the resolution
178     }
179     if (config.FQ != -1){
180       buf[1]&=~(3<<3); // Unset the FQ
181       buf[1]|=config.FQ<<3; //Set the FQ
182     }
183     if (config.POL != -1)
184       config.POL ? buf[1]|(1<<2) : buf[1]&~(1<<2) ;
185     if (config.TM != -1)
186       config.TM ? buf[1]|(1<<1) : buf[1]&~(1<<1) ;
187     if (config.SD != -1)
188       config.SD ? buf[1]|(1<<0) : buf[1]&~(1<<0) ;
189
190     // Write the register back to the IC
191     err_write(fd, buf, 2);
192
193     // Query an pretty print the config
194     query = 1;
195   }
196
197
198   /*
199    * If this is a query prettyprint the config register to stdout
200    * */
201   if (query) {
202     // Set register pointer on IC to config register
203     unsigned char buf[2] = {1, 0};
204     err_write(fd, buf, 1);
205
206     // Read configuration register
207     err_read(fd, buf+1, 1);
208
209     // Pretty print config register
210     int resolution = ((buf[1] & (3<<5)) >> 5);
211     int fault_queue = ((buf[1] & (3<<3)) >> 3);
212     printf("Oneshot:         %s\n", (buf[1] & (1<<7)) ? "Enabled" : "Disabled" );
213     printf("Resolution:      %d (%.4f)\n", resolution, 1/pow(2, 1 + resolution));
214     printf("Fault queue:     %d\n", fault_queue);
215     printf("Alert pin:       Active %s\n", (buf[1] & (1<<2)) ? "high" : "low" );
216     printf("Thermostat mode: %s mode\n", (buf[1] & (1<<1)) ? "Interrupt" : "Comparator" );
217     printf("Shutdown mode:   %s\n", (buf[1] & (1<<0)) ? "Enabled" : "Disabled" );
218     return 0;
219   }
220
221   /*
222    * If this was not a config query get the temperature and quit
223    */
224   // Send register to read from. "0"/temperature register
225   unsigned char buf[2]={0,0};
226   err_write(fd, buf, 1);
227
228   // Read back data into buf[]
229   err_read(fd, buf, 2);
230
231   // Compute the result
232   signed short data = (buf[0]<<8)|buf[1];
233   printf("%.1f\n", (float)data/256);
234
235   return 0;
236 }
237