1 /*
2  * Author: Jon Trulson <jtrulson@ics.com>
3  * Copyright (c) 2014 Intel Corporation.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include <iostream>
26 #include <string>
27 #include <stdexcept>
28 
29 #include "mpr121.h"
30 
31 using namespace upm;
32 using namespace std;
33 
34 
MPR121(int bus,uint8_t address)35 MPR121::MPR121(int bus, uint8_t address) : m_i2c(bus)
36 {
37   m_addr = address;
38   mraa::Result ret = m_i2c.address(m_addr);
39 
40   if (ret != mraa::SUCCESS)
41     {
42       throw std::invalid_argument(std::string(__FUNCTION__) +
43                                   ": mraa_i2c_address() failed");
44       return;
45     }
46 
47   m_buttonStates = 0;
48   m_overCurrentFault = false;
49 }
50 
writeBytes(uint8_t reg,uint8_t * buffer,int len)51 mraa::Result MPR121::writeBytes(uint8_t reg, uint8_t *buffer, int len)
52 {
53   if (!len || !buffer)
54     return mraa::SUCCESS;
55 
56   // create a buffer 1 byte larger than the supplied buffer,
57   // store the register in the first byte
58   uint8_t buf2[len + 1];
59 
60   buf2[0] = reg;
61 
62   // copy in the buffer after the reg byte
63   for (int i=1; i<(len + 1); i++)
64     buf2[i] = buffer[i-1];
65 
66   m_i2c.address(m_addr);
67 
68   return m_i2c.write(buf2, len + 1);
69 }
70 
readBytes(uint8_t reg,uint8_t * buffer,int len)71 int MPR121::readBytes(uint8_t reg, uint8_t *buffer, int len)
72 {
73   if (!len || !buffer)
74     return 0;
75 
76   // The usual m_i2c.read() does not work here, so we need to
77   // read each byte individually.
78   for (int i=0; i<len; i++)
79     buffer[i] = m_i2c.readReg(reg + i);
80 
81   return len;
82 }
83 
configAN3944()84 bool MPR121::configAN3944()
85 {
86   // Configure the mpr121 chip as recommended in the AN3944 MPR121
87   // Quick Start Guide
88 
89   mraa::Result rv;
90 
91   // First, turn off all electrodes by zeroing out the Electrode Configuration
92   // register.
93   // If this one fails, it's unlikely any of the others will succeed.
94   uint8_t eleConf = 0x00;
95   if ((rv = writeBytes(0x5e, &eleConf, 1)) != mraa::SUCCESS)
96     {
97       throw std::runtime_error(std::string(__FUNCTION__) +
98                                ": writeBytes(0x5e) failed");
99       return false;
100     }
101 
102   // Section A
103   // Filtering when data is greater than baseline
104   // regs 0x2b-0x2e
105   uint8_t sectA[] = { 0x01, 0x01, 0x00, 0x00 };
106   if ((rv = writeBytes(0x2b, sectA, 4)) != mraa::SUCCESS)
107     {
108       throw std::runtime_error(std::string(__FUNCTION__) +
109                                ": writeBytes(0x2b) failed");
110       return false;
111     }
112 
113   // Section B
114   // Filtering when data is less than baseline
115   // regs 0x2f-0x32
116   uint8_t sectB[] = { 0x01, 0x01, 0xff, 0x02 };
117   if ((rv = writeBytes(0x2f, sectB, 4)) != mraa::SUCCESS)
118     {
119       throw std::runtime_error(std::string(__FUNCTION__) +
120                                ": writeBytes(0x2f) failed");
121       return false;
122     }
123 
124   // Section C
125   // Touch Threshold/Release registers, ELE0-ELE11
126   // regs 0x41-0x58
127   //                __T_  __R_
128   uint8_t sectC[] = { 0x0f, 0x0a,
129                       0x0f, 0x0a,
130                       0x0f, 0x0a,
131                       0x0f, 0x0a,
132                       0x0f, 0x0a,
133                       0x0f, 0x0a,
134                       0x0f, 0x0a,
135                       0x0f, 0x0a,
136                       0x0f, 0x0a,
137                       0x0f, 0x0a,
138                       0x0f, 0x0a,
139                       0x0f, 0x0a };
140   if ((rv = writeBytes(0x41, sectC, 24)) != mraa::SUCCESS)
141     {
142       throw std::runtime_error(std::string(__FUNCTION__) +
143                                ": writeBytes(0x41) failed");
144       return false;
145     }
146 
147   // Section D
148   // Filter configuration
149   // reg 0x5d
150   uint8_t filterConf = 0x04;
151   if ((rv = writeBytes(0x5d, &filterConf, 1)) != mraa::SUCCESS)
152     {
153       throw std::runtime_error(std::string(__FUNCTION__) +
154                                ": writeBytes(0x5d) failed");
155       return false;
156     }
157 
158   // Section F
159   // Autoconfiguration registers
160   // regs 0x7b-0x7f
161   uint8_t sectF0 = 0x0b;
162   if ((rv = writeBytes(0x7b, &sectF0, 1)) != mraa::SUCCESS)
163     {
164       throw std::runtime_error(std::string(__FUNCTION__) +
165                                ": writeBytes(0x7b) failed");
166       return false;
167     }
168   uint8_t sectF1[] = { 0x9c, 0x65, 0x8c };
169   if ((rv = writeBytes(0x7d, sectF1, 3)) != mraa::SUCCESS)
170     {
171       throw std::runtime_error(std::string(__FUNCTION__) +
172                                ": writeBytes(0x7d) failed");
173       return false;
174     }
175 
176   // Section E - this one must be set last, and switches to run mode
177   // Enable all 12 electrodes, and set a pre-calibration to avoid
178   // excessive calibration delay on startup.
179   // reg 0x5e
180   eleConf = 0x8c;
181   if ((rv = writeBytes(0x5e, &eleConf, 1)) != mraa::SUCCESS)
182     {
183       throw std::runtime_error(std::string(__FUNCTION__) +
184                                ": writeBytes(0x5e) failed");
185       return false;
186     }
187 
188   return true;
189 }
190 
readButtons()191 void MPR121::readButtons()
192 {
193   uint8_t rv;
194   uint8_t buffer[2];
195 
196   // read in the 2 bytes at register 0x00-0x01, and setup the member
197   // variables accordingly.
198 
199   readBytes(0x00, buffer, 2);
200 
201   m_buttonStates = (buffer[0] | ((buffer[1] & 0x1f) << 8));
202   if (buffer[1] & 0x80)
203     m_overCurrentFault = true;
204   else
205     m_overCurrentFault = false;
206 
207   return;
208 }
209