1/*
2 * Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.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#include <unistd.h>
29#include <stdlib.h>
30#include <string.h>
31#include <pthread.h>
32#include <math.h>
33
34#include "mma7455.h"
35
36using namespace upm;
37
38MMA7455::MMA7455 (int bus, int devAddr) : m_i2ControlCtx(bus) {
39    unsigned char data   = 0;
40    int           nBytes = 0;
41
42    m_name = "MMA7455";
43
44    m_controlAddr = devAddr;
45    m_bus = bus;
46
47    mraa::Result error = m_i2ControlCtx.address(m_controlAddr);
48    if (error != mraa::SUCCESS) {
49        throw std::runtime_error(std::string(__FUNCTION__) +
50                                 ": mraa_i2c_address() failed");
51        return;
52    }
53
54    // setting GLVL 0x1 (64LSB/g) and MODE 0x1 (Measurement Mode)
55    data = (BIT (MMA7455_GLVL0) | BIT (MMA7455_MODE0));
56    error = i2cWriteReg (MMA7455_MCTL, &data, 0x1);
57    if (error != mraa::SUCCESS) {
58        throw std::runtime_error(std::string(__FUNCTION__) +
59                                 ": writing mode register failed");
60        return;
61    }
62
63    if (mraa::SUCCESS != calibrate ()) {
64        throw std::runtime_error(std::string(__FUNCTION__) +
65                                 ": calibrate() failed");
66        return;
67    }
68}
69
70mraa::Result
71MMA7455::calibrate () {
72    mraa::Result error = mraa::SUCCESS;
73    int i = 0;
74
75    accelData xyz;
76    xyz.value.x = xyz.value.y = xyz.value.z = 0;
77
78    do {
79        error = readData (&xyz.value.x, &xyz.value.y, &xyz.value.z);
80        if (mraa::SUCCESS != error) {
81            return error;
82        }
83
84        xyz.value.x += 2 * -xyz.value.x;
85        xyz.value.y += 2 * -xyz.value.y;
86        xyz.value.z += 2 * -(xyz.value.z - 64);
87
88        error = i2cWriteReg (MMA7455_XOFFL,  (unsigned char *) &xyz, 0x6);
89        if (error != mraa::SUCCESS) {
90            return error;
91        }
92
93    } while ( ++i < 3 );
94
95    return error;
96}
97
98mraa::Result
99MMA7455::readData (short * ptrX, short * ptrY, short * ptrZ) {
100    accelData xyz;
101    unsigned char data = 0;
102    int nBytes = 0;
103
104    /*do {
105        nBytes = i2cReadReg (MMA7455_STATUS, &data, 0x1);
106    } while ( !(data & MMA7455_DRDY) && nBytes == mraa::SUCCESS);
107
108    if (nBytes == mraa::SUCCESS) {
109        std::cout << "NO_GDB :: 1" << std::endl;
110        return mraa::SUCCESS;
111    }*/
112
113    nBytes = i2cReadReg (MMA7455_XOUTL, (unsigned char *) &xyz, 0x6);
114    if (nBytes == 0) {
115        std::cout << "NO_GDB :: 2" << std::endl;
116        return mraa::ERROR_UNSPECIFIED;
117    }
118
119    if (xyz.reg.x_msb & 0x02) {
120        xyz.reg.x_msb |= 0xFC;
121    }
122
123    if (xyz.reg.y_msb & 0x02) {
124        xyz.reg.y_msb |= 0xFC;
125    }
126
127    if (xyz.reg.z_msb & 0x02) {
128        xyz.reg.z_msb |= 0xFC;
129    }
130
131    // The result is the g-force in units of 64 per 'g'.
132    *ptrX = xyz.value.x;
133    *ptrY = xyz.value.y;
134    *ptrZ = xyz.value.z;
135
136    return mraa::SUCCESS;
137}
138
139#ifdef SWIGJAVA
140short *MMA7455::readData() {
141    short *v = new short[3];
142    readData(&v[0], &v[1], &v[2]);
143    return v;
144}
145#endif
146
147int
148MMA7455::i2cReadReg (unsigned char reg, uint8_t *buffer, int len) {
149    if (mraa::SUCCESS != m_i2ControlCtx.address(m_controlAddr)) {
150        throw std::runtime_error(std::string(__FUNCTION__) +
151                                 ": mraa_i2c_address() failed");
152        return 0;
153    }
154
155    if (mraa::SUCCESS != m_i2ControlCtx.writeByte(reg)) {
156        throw std::runtime_error(std::string(__FUNCTION__) +
157                                 ": mraa_i2c_write_byte() failed");
158        return 0;
159    }
160
161    return (int) m_i2ControlCtx.read(buffer, len);
162}
163
164mraa::Result
165MMA7455::i2cWriteReg (unsigned char reg, uint8_t *buffer, int len) {
166    mraa::Result error = mraa::SUCCESS;
167
168    uint8_t data[len + 1];
169    data[0] = reg;
170    memcpy(&data[1], buffer, len);
171
172    error = m_i2ControlCtx.address (m_controlAddr);
173    if (error != mraa::SUCCESS) {
174        throw std::runtime_error(std::string(__FUNCTION__) +
175                                 ": mraa_i2c_address() failed");
176        return error;
177    }
178    error = m_i2ControlCtx.write (data, len + 1);
179    if (error != mraa::SUCCESS) {
180        throw std::runtime_error(std::string(__FUNCTION__) +
181                                 ": mraa_i2c_write() failed");
182        return error;
183    }
184
185    return error;
186}
187