1 /*
2  * Author: Jon Trulson <jtrulson@ics.com>
3  * Copyright (c) 2015 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 <stdexcept>
27 #include <string>
28 
29 #include "mma7660.h"
30 
31 using namespace upm;
32 using namespace std;
33 
34 
MMA7660(int bus,uint8_t address)35 MMA7660::MMA7660(int bus, uint8_t address)
36 {
37   m_addr = address;
38   m_isrInstalled = false;
39 
40   // setup our i2c link
41   if ( !(m_i2c = mraa_i2c_init(bus)) )
42     {
43       throw std::invalid_argument(std::string(__FUNCTION__) +
44                                   ": mraa_i2c_init() failed");
45       return;
46     }
47 
48   mraa_result_t rv;
49 
50   if ( (rv = mraa_i2c_address(m_i2c, m_addr)) != MRAA_SUCCESS)
51     {
52       throw std::invalid_argument(std::string(__FUNCTION__) +
53                                   ": mraa_i2c_address() failed");
54       return;
55     }
56 }
57 
~MMA7660()58 MMA7660::~MMA7660()
59 {
60   if (m_isrInstalled)
61     uninstallISR();
62 
63   setModeStandby();
64   mraa_i2c_stop(m_i2c);
65 }
66 
writeByte(uint8_t reg,uint8_t byte)67 bool MMA7660::writeByte(uint8_t reg, uint8_t byte)
68 {
69   mraa_result_t rv = mraa_i2c_write_byte_data(m_i2c, byte, reg);
70 
71   if (rv != MRAA_SUCCESS)
72     {
73       return false;
74     }
75 
76   return true;
77 }
78 
readByte(uint8_t reg)79 uint8_t MMA7660::readByte(uint8_t reg)
80 {
81   return mraa_i2c_read_byte_data(m_i2c, reg);
82 }
83 
getRawValues(int * x,int * y,int * z)84 void MMA7660::getRawValues(int *x, int *y, int *z)
85 {
86   *x = getVerifiedAxis(REG_XOUT);
87   *y = getVerifiedAxis(REG_YOUT);
88   *z = getVerifiedAxis(REG_ZOUT);
89 }
90 
91 #ifdef JAVACALLBACK
getRawValues()92 int *MMA7660::getRawValues()
93 {
94   int *values = new int[3];
95   getRawValues(&values[0], &values[1], &values[2]);
96   return values;
97 }
98 #endif
99 
setModeActive()100 void MMA7660::setModeActive()
101 {
102   uint8_t modeReg = readByte(REG_MODE);
103 
104   // The D2 (TON bit) should be cleared, and the MODE bit set
105 
106   modeReg &= ~MODE_TON;
107   modeReg |= MODE_MODE;
108 
109   writeByte(REG_MODE, modeReg);
110 }
111 
setModeStandby()112 void MMA7660::setModeStandby()
113 {
114   uint8_t modeReg = readByte(REG_MODE);
115 
116   // the D0 (mode bit) and D2 (TON bit) should be cleared.
117 
118   modeReg &= ~MODE_TON;
119   modeReg &= ~MODE_MODE;
120 
121   writeByte(REG_MODE, modeReg);
122 }
123 
124 // read an axis value, verifying it's validity
getVerifiedAxis(MMA7660_REG_T axis)125 int MMA7660::getVerifiedAxis(MMA7660_REG_T axis)
126 {
127   // We only want one of the 3 axes
128 
129   if (axis > 2)
130     {
131       throw std::out_of_range(std::string(__FUNCTION__) +
132                               ": axis must be 0, 1, or 2.");
133       return 0;
134     }
135 
136   // we need to check the alert bit and sign bits if the alert bit is
137   // set, this means that the register was being updated when the
138   // register was read, so re-read until it's clear.
139 
140   uint8_t val;
141   do {
142     val = readByte(axis);
143 
144     // check alert bit
145   } while (val & 0x40);
146 
147   // shift the sign bit over, and compensate
148   return (char(val << 2) / 4);
149 }
150 
151 // read the tilt register, verifying it's validity
getVerifiedTilt()152 uint8_t MMA7660::getVerifiedTilt()
153 {
154   // we need to check the alert bit and sign bits if the alert bit is
155   // set, this means that the register was being updated when the
156   // register was read, so re-read until it's clear.
157 
158   uint8_t val;
159   do {
160     val = readByte(REG_TILT);
161 
162     // check alert bit
163   } while (val & 0x40);
164 
165   return val;
166 }
167 
tiltBackFront()168 uint8_t MMA7660::tiltBackFront()
169 {
170   uint8_t val = getVerifiedTilt();
171 
172   // mask off the bits we don't care about
173   val &= 0x03;
174   return val;
175 }
176 
tiltLandscapePortrait()177 uint8_t MMA7660::tiltLandscapePortrait()
178 {
179   uint8_t val = getVerifiedTilt();
180 
181   // mask off the bits we don't care about
182   val >>= 2;
183   val &= 0x07;
184   return val;
185 }
186 
tiltTap()187 bool MMA7660::tiltTap()
188 {
189   uint8_t val = getVerifiedTilt();
190 
191   if (val & 0x20)
192     return true;
193   else
194     return false;
195 }
196 
tiltShake()197 bool MMA7660::tiltShake()
198 {
199   uint8_t val = getVerifiedTilt();
200 
201   if (val & 0x80)
202     return true;
203   else
204     return false;
205 }
206 
207 #ifdef JAVACALLBACK
installISR(int pin,IsrCallback * cb)208 void MMA7660::installISR(int pin, IsrCallback *cb)
209 {
210         installISR(pin, generic_callback_isr, cb);
211 }
212 #endif
213 
installISR(int pin,void (* isr)(void *),void * arg)214 void MMA7660::installISR(int pin, void (*isr)(void *), void *arg)
215 {
216   if (m_isrInstalled)
217     uninstallISR();
218 
219   if ( !(m_gpio = mraa_gpio_init(pin)) )
220     {
221       throw std::invalid_argument(std::string(__FUNCTION__) +
222                                   ": mraa_gpio_init() failed, invalid pin?");
223       return;
224     }
225 
226   mraa_gpio_dir(m_gpio, MRAA_GPIO_IN);
227 
228   // install our interrupt handler
229   mraa_gpio_isr(m_gpio, MRAA_GPIO_EDGE_RISING,
230                 isr, arg);
231   m_isrInstalled = true;
232 }
233 
uninstallISR()234 void MMA7660::uninstallISR()
235 {
236   if (!m_isrInstalled)
237     return;
238 
239   mraa_gpio_isr_exit(m_gpio);
240   m_isrInstalled = false;
241   mraa_gpio_close(m_gpio);
242 }
243 
setInterruptBits(uint8_t ibits)244 bool MMA7660::setInterruptBits(uint8_t ibits)
245 {
246   return writeByte(REG_INTSU, ibits);
247 }
248 
setSampleRate(MMA7660_AUTOSLEEP_T sr)249 bool MMA7660::setSampleRate(MMA7660_AUTOSLEEP_T sr)
250 {
251   return writeByte(REG_SR, sr);
252 }
253 
getAcceleration(float * ax,float * ay,float * az)254 void MMA7660::getAcceleration(float *ax, float *ay, float *az)
255 {
256   int x, y, z;
257 
258   getRawValues(&x, &y, &z);
259 
260   // 21.33, typical counts/g
261 
262   *ax = x/21.33;
263   *ay = y/21.33;
264   *az = z/21.33;
265 }
266 
267 #ifdef JAVACALLBACK
getAcceleration()268 float *MMA7660::getAcceleration()
269 {
270   float *values = new float[3];
271   getAcceleration(&values[0], &values[1], &values[2]);
272   return values;
273 }
274 #endif
275 
276