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 #pragma once
25 
26 #include <string>
27 #include <mraa/i2c.h>
28 #include <mraa/gpio.h>
29 
30 #if defined(SWIGJAVA) || defined(JAVACALLBACK)
31 #include "../IsrCallback.h"
32 #endif
33 
34 #define MMA7660_I2C_BUS 0
35 #define MMA7660_DEFAULT_I2C_ADDR 0x4c
36 
37 namespace upm {
38 
39   /**
40    * @brief MMA7660 I2C 3-Axis Digital Accelerometer library
41    * @defgroup mma7660 libupm-mma7660
42    * @ingroup seeed i2c gpio accelerometer
43    */
44   /**
45    * @library mma7660
46    * @sensor mma7660
47    * @comname MMA7660 3-Axis Digital Accelerometer
48    * @altname Grove 3-Axis Digital Accelerometer (1.5g)
49    * @type accelerometer
50    * @man seeed
51    * @con i2c gpio
52    *
53    * @brief API for the MMA7660 I2C 3-Axis Digital Accelerometer
54    *
55    * UPM module for the MMA7660 I2C 3-axis digital accelerometer.
56    * This device supports a variety of capabilities, including the
57    * generation of interrupts for various conditions, tilt and basic
58    * gesture detection, and X/Y/Z-axis measurements of g-forces
59    * being applied (up to 1.5g)
60    *
61    * This module was tested with the Grove 3-Axis Digital
62    * Accelerometer (1.5g)
63    *
64    * @image html mma7660.jpg
65    * @snippet mma7660.cxx Interesting
66    */
67   class MMA7660 {
68   public:
69 
70     // MMA7660 registers
71     typedef enum { REG_XOUT       = 0x00,
72                    REG_YOUT       = 0x01,
73                    REG_ZOUT       = 0x02,
74                    REG_TILT       = 0x03,
75                    REG_SRST       = 0x04, // Sampling Rate Status
76                    REG_SPCNT      = 0x05, // sleep count
77                    REG_INTSU      = 0x06, // Interrupt setup
78                    REG_MODE       = 0x07, // operating mode
79                    REG_SR         = 0x08, // auto-wake/sleep, SPS, and debounce
80                    REG_PDET       = 0x09, // tap detection
81                    REG_PD         = 0x0a  // tap debounce count
82                    // 0x0b-0x1f reserved
83     } MMA7660_REG_T;
84 
85     // interrupt enable register bits
86     typedef enum { INTR_NONE          = 0x00, // disabled
87                    INTR_FBINT         = 0x01, // front/back
88                    INTR_PLINT         = 0x02, // up/down/right/left
89                    INTR_PDINT         = 0x04, // tap detection
90                    INTR_ASINT         = 0x08, // exit auto-sleep
91                    INTR_GINT          = 0x10, // measurement intr
92                    INTR_SHINTZ        = 0x20, // shake on Z
93                    INTR_SHINTY        = 0x40, // shake on Y
94                    INTR_SHINTX        = 0x80 // shake on X
95     } MMA7660_INTR_T;
96 
97     // operating mode register bits
98     typedef enum { MODE_MODE          = 0x01, // determines mode with MODE_TON
99                    // 0x02 reserved
100                    MODE_TON           = 0x04, // determines mode with MODE_MODE
101                    MODE_AWE           = 0x08, // auto-wake
102                    MODE_ASE           = 0x10, // auto-sleep
103                    MODE_SCPS          = 0x20, // sleep count prescale
104                    MODE_IPP           = 0x40, // intr out push-pull/open drain
105                    MODE_IAH           = 0x80  // intr active low/high
106     } MMA7660_MODE_T;
107 
108     // tilt BackFront (BF) bits
109     typedef enum { BF_UNKNOWN          = 0x00,
110                    BF_LYING_FRONT      = 0x01,
111                    BF_LYING_BACK       = 0x02
112     } MMA7660_TILT_BF_T;
113 
114     // tilt LandscapePortrait (LP) bits
115     typedef enum { LP_UNKNOWN          = 0x00,
116                    LP_LANDSCAPE_LEFT   = 0x01,
117                    LP_LANDSCAPE_RIGHT  = 0x02,
118                    LP_VERT_DOWN        = 0x05,
119                    LP_VERT_UP          = 0x06
120     } MMA7660_TILT_LP_T;
121 
122     // sample rate (auto-sleep) values
123     typedef enum { AUTOSLEEP_120   = 0x00,
124                    AUTOSLEEP_64    = 0x01,
125                    AUTOSLEEP_32    = 0x02,
126                    AUTOSLEEP_16    = 0x03,
127                    AUTOSLEEP_8     = 0x04,
128                    AUTOSLEEP_4     = 0x05,
129                    AUTOSLEEP_2     = 0x06,
130                    AUTOSLEEP_1     = 0x07
131     } MMA7660_AUTOSLEEP_T;
132 
133     /**
134      * MMA7660 constructor
135      *
136      * @param bus I2C bus to use
137      * @param address Address for this sensor; default is 0x55
138      */
139     MMA7660(int bus, uint8_t address = MMA7660_DEFAULT_I2C_ADDR);
140 
141     /**
142      * MMA7660 destructor
143      */
144     ~MMA7660();
145 
146     /**
147      * Writes a byte value into a register
148      *
149      * @param reg Register location to write into
150      * @param byte Byte to write
151      * @return True if successful
152      */
153     bool writeByte(uint8_t reg, uint8_t byte);
154 
155     /**
156      * Reads a byte value from a register
157      *
158      * @param reg Register location to read from
159      * @return Value in a specified register
160      */
161     uint8_t readByte(uint8_t reg);
162 
163     /**
164      * Reads the current value of conversion
165      *
166      * @param x Returned x value
167      * @param y Returned y value
168      * @param z Returned z value
169      */
170     void getRawValues(int *x, int *y, int *z);
171 
172 #if defined(SWIGJAVA) || defined(JAVACALLBACK)
173     /**
174      * Reads the current value of conversion
175      *
176      * @return Array containing x, y, z. Free using delete.
177      */
178     int *getRawValues();
179 #endif
180 
181     /**
182      * Gets the computed acceleration
183      *
184      * @param ax Returned computed acceleration of the X-axis
185      * @param ay Returned computed acceleration of the Y-axis
186      * @param az Returned computed acceleration of the Z-axis
187      */
188     void getAcceleration(float *ax, float *ay, float *az);
189 
190 #if defined(SWIGJAVA) || defined(JAVACALLBACK)
191     /**
192      * Gets the computed acceleration
193      *
194      * @return Array containing x, y, z. Free using delete.
195      */
196     float *getAcceleration();
197 #endif
198 
199     /**
200      * Reads an axis, verifying its validity. The value passed must
201      * be one of REG_XOUT, REG_YOUT, or REG_ZOUT.
202      *
203      * @param axis Axis to read
204      * @return Axis value
205      */
206     int getVerifiedAxis(MMA7660_REG_T axis);
207 
208     /**
209      * Reads the tilt register, verifying its validity
210      *
211      * @return Tilt value
212      */
213     uint8_t getVerifiedTilt();
214 
215     /**
216      * Puts the device in the active mode. In this mode, register
217      * writes are not allowed. Place the device in the standby mode before
218      * attempting to write registers.
219      *
220      */
221     void setModeActive();
222 
223     /**
224      * Puts the device in the standby (power saving) mode. Note: when in
225      * the standby mode, there is no valid data in the registers. In
226      * addition, the only way to write a register is to put the
227      * device in the standby mode.
228      *
229      */
230     void setModeStandby();
231 
232     /**
233      * Reads tiltBackFront bits
234      *
235      * The value returned is one of the MMA7660_TILT_BF_T values
236      *
237      * @return Bits corresponding to the BackFront tilt status
238      */
239     uint8_t tiltBackFront();
240 
241     /**
242      * Reads tiltLandscapePortrait bits
243      *
244      * The value returned is one of the MMA7660_TILT_LP_T values
245      *
246      * @return Bits corresponding to the LandscapePortrait tilt status
247      */
248     uint8_t tiltLandscapePortrait();
249 
250     /**
251      * Reads the tiltTap status
252      *
253      * @return True if a tap is detected
254      */
255     bool tiltTap();
256 
257     /**
258      * Reads the tiltShake status
259      *
260      * @return True if a shake is detected
261      */
262     bool tiltShake();
263 
264     /**
265      * Installs an interrupt service routine (ISR) to be called when
266      * an interrupt occurs
267      *
268      * @param pin GPIO pin to use as the interrupt pin
269      * @param fptr Pointer to a function to be called on interrupt
270      * @param arg Pointer to an object to be supplied as an
271      * argument to the ISR.
272      */
273 #if defined(SWIGJAVA) || defined(JAVACALLBACK)
274     void installISR(int pin, IsrCallback *cb);
275 #else
276     void installISR(int pin, void (*isr)(void *), void *arg);
277 #endif
278     /**
279      * Uninstalls the previously installed ISR
280      *
281      */
282     void uninstallISR();
283 
284     /**
285      * Enables interrupt generation based on passed interrupt bits.
286      * The bits are a bitmask of the requested MMA7660_INTR_T values.
287      * Note: the device must be in the standby mode to set this register.
288      *
289      * @param ibits Sets the requested interrupt bits
290      * @return True if successful
291      */
292     bool setInterruptBits(uint8_t ibits);
293 
294     /**
295      * Sets the sampling rate of the sensor. The value supplied must
296      * be one of the MMA7660_AUTOSLEEP_T values.
297      *
298      * @param sr One of the MMA7660_AUTOSLEEP_T values
299      * @return True if successful
300      */
301     bool setSampleRate(MMA7660_AUTOSLEEP_T sr);
302 
303   private:
304 #if defined(SWIGJAVA) || defined(JAVACALLBACK)
305     void installISR(int pin, void (*isr)(void *), void *arg);
306 #endif
307 
308     bool m_isrInstalled;
309     mraa_i2c_context m_i2c;
310     mraa_gpio_context m_gpio;
311     uint8_t m_addr;
312   };
313 }
314 
315 
316