1765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang/*
2765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * Author: Jon Trulson <jtrulson@ics.com>
3765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * Copyright (c) 2015 Intel Corporation.
4765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang *
5765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * Permission is hereby granted, free of charge, to any person obtaining
6765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * a copy of this software and associated documentation files (the
7765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * "Software"), to deal in the Software without restriction, including
8765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * without limitation the rights to use, copy, modify, merge, publish,
9765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * distribute, sublicense, and/or sell copies of the Software, and to
10765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * permit persons to whom the Software is furnished to do so, subject to
11765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * the following conditions:
12765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang *
13765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * The above copyright notice and this permission notice shall be
14765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * included in all copies or substantial portions of the Software.
15765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang *
16765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang */
24765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
25765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang#include <unistd.h>
26765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang#include <math.h>
27765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang#include <iostream>
28765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang#include <string>
29765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang#include <stdexcept>
30765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
31765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang#include "pca9685.h"
32765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
33765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangusing namespace upm;
34765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangusing namespace std;
35765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
36765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
37765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun ZhangPCA9685::PCA9685(int bus, uint8_t address, bool raw)
38765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{
39765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  m_addr = address;
40765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
41765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // setup our i2c link
42765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if ( raw )
43765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    {
44765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      m_i2c = mraa_i2c_init_raw(bus);
45765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
46765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  else
47765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    {
48765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      m_i2c = mraa_i2c_init(bus);
49765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
50765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
51765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if ( !m_i2c)
52765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    {
53765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      throw std::invalid_argument(std::string(__FUNCTION__) +
54765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                                  ": mraa_i2c_init() failed");
55765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return;
56765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
57765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
58765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  mraa_result_t rv;
59765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
60765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if ( (rv = mraa_i2c_address(m_i2c, m_addr)) != MRAA_SUCCESS)
61765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    {
62765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      throw std::runtime_error(std::string(__FUNCTION__) +
63765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                               ": mraa_i2c_address() failed");
64765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return;
65765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
66765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
67765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // enable auto-increment mode by default
68765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  enableAutoIncrement(true);
69765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
70765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // enable restart by default.
71765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  enableRestart(true);
72765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
73765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
74765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun ZhangPCA9685::~PCA9685()
75765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{
76765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  setModeSleep(true);
77765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  mraa_i2c_stop(m_i2c);
78765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
79765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
80765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::writeByte(uint8_t reg, uint8_t byte)
81765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{
82765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  mraa_result_t rv = mraa_i2c_write_byte_data(m_i2c, byte, reg);
83765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
84765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (rv != MRAA_SUCCESS)
85765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    {
86765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      throw std::runtime_error(std::string(__FUNCTION__) +
87765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                               ": mraa_i2c_write_byte_data() failed");
88765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return false;
89765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
90765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
91765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return true;
92765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
93765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
94765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::writeWord(uint8_t reg, uint16_t word)
95765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{
96765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  mraa_result_t rv = mraa_i2c_write_word_data(m_i2c, word, reg);
97765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
98765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (rv != MRAA_SUCCESS)
99765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    {
100765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      throw std::runtime_error(std::string(__FUNCTION__) +
101765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                               ": mraa_i2c_write_word_data() failed");
102765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return false;
103765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
104765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
105765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return true;
106765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
107765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
108765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhanguint8_t PCA9685::readByte(uint8_t reg)
109765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{
110765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return mraa_i2c_read_byte_data(m_i2c, reg);
111765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
112765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
113765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhanguint16_t PCA9685::readWord(uint8_t reg)
114765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{
115765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return mraa_i2c_read_word_data(m_i2c, reg);
116765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
117765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
118765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::setModeSleep(bool sleep)
119765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{
120765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  uint8_t mode1 = readByte(REG_MODE1);
121765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  uint8_t restartBit = mode1 & MODE1_RESTART;
122765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
123765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (sleep)
124765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    mode1 |= MODE1_SLEEP;
125765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  else
126765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    mode1 &= ~MODE1_SLEEP;
127765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
128765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // if we are waking up, then preserve but don't write restart bit if set
129765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (!sleep && restartBit)
130765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    mode1 &= ~MODE1_RESTART;
131765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
132765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  writeByte(REG_MODE1, mode1);
133765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
134765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // Need a delay of 500us after turning sleep mode off for the oscillator
135765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // to stabilize
136765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (!sleep)
137765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    usleep(500);
138765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
139765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // now check to see if we want to (and can) restart when waking up
140765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (restartBit && m_restartEnabled && !sleep)
141765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    {
142765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      mode1 |= restartBit;
143765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      writeByte(REG_MODE1, mode1);
144765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
145765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
146765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return true;
147765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
148765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
149765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::enableAutoIncrement(bool ai)
150765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{
151765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  uint8_t mode1 = readByte(REG_MODE1);
152765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
153765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (ai)
154765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    mode1 |= MODE1_AI;
155765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  else
156765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    mode1 &= ~MODE1_AI;
157765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
158765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return writeByte(REG_MODE1, mode1);
159765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
160765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
161765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::ledFullOn(uint8_t led, bool val)
162765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{
163765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (led > 15 && (led != PCA9685_ALL_LED))
164765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    {
165765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      throw std::out_of_range(std::string(__FUNCTION__) +
166765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                              ": led value must be between 0-15 or " +
167765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                              "PCA9685_ALL_LED (255)");
168765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return false;
169765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
170765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
171765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // figure out the register offset (*_ON_H)
172765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  uint8_t regoff;
173765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
174765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (led == PCA9685_ALL_LED)
175765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    regoff = REG_ALL_LED_ON_H;
176765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  else
177765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    regoff = REG_LED0_ON_L + (led * 4) + 1;
178765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
179765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  uint8_t bits = readByte(regoff);
180765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
181765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (val)
182765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    bits |= 0x10;
183765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  else
184765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    bits &= ~0x10;
185765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
186765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return writeByte(regoff, bits);
187765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
188765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
189765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::ledFullOff(uint8_t led, bool val)
190765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{
191765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (led > 15 && (led != PCA9685_ALL_LED))
192765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    {
193765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      throw std::out_of_range(std::string(__FUNCTION__) +
194765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                              ": led value must be between 0-15 or " +
195765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                              "PCA9685_ALL_LED (255)");
196765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return false;
197765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
198765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
199765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // figure out the register offset (*_OFF_H)
200765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  uint8_t regoff;
201765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
202765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (led == PCA9685_ALL_LED)
203765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    regoff = REG_ALL_LED_OFF_H;
204765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  else
205765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    regoff = REG_LED0_ON_L + (led * 4) + 3;
206765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
207765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  uint8_t bits = readByte(regoff);
208765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
209765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (val)
210765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    bits |= 0x10;
211765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  else
212765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    bits &= ~0x10;
213765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
214765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return writeByte(regoff, bits);
215765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
216765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
217765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::ledOnTime(uint8_t led, uint16_t time)
218765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{
219765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (led > 15 && (led != PCA9685_ALL_LED))
220765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    {
221765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      throw std::out_of_range(std::string(__FUNCTION__) +
222765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                              ": led value must be between 0-15 or " +
223765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                              "PCA9685_ALL_LED (255)");
224765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return false;
225765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
226765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
227765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (time > 4095)
228765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    {
229765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      throw std::out_of_range(std::string(__FUNCTION__) +
230765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                              ": time value must be between 0-4095");
231765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return false;
232765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
233765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
234765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // figure out the register offset (*_ON_L)
235765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  uint8_t regoff;
236765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
237765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (led == PCA9685_ALL_LED)
238765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    regoff = REG_ALL_LED_ON_L;
239765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  else
240765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    regoff = REG_LED0_ON_L + (led * 4);
241765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
242765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // we need to preserve the full ON bit in *_ON_H
243765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  uint8_t onbit = (readByte(regoff + 1) & 0x10);
244765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
245765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  time = (time & 0x0fff) | (onbit << 8);
246765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
247765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return writeWord(regoff, time);
248765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
249765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
250765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::ledOffTime(uint8_t led, uint16_t time)
251765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{
252765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (led > 15 && (led != PCA9685_ALL_LED))
253765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    {
254765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      throw std::out_of_range(std::string(__FUNCTION__) +
255765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                              ": led value must be between 0-15 or " +
256765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                              "PCA9685_ALL_LED (255)");
257765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return false;
258765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
259765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
260765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (time > 4095)
261765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    {
262765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      throw std::out_of_range(std::string(__FUNCTION__) +
263765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang                              ": time value must be between 0-4095");
264765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang      return false;
265765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    }
266765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
267765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // figure out the register offset (*_OFF_L)
268765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  uint8_t regoff;
269765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
270765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  if (led == PCA9685_ALL_LED)
271765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    regoff = REG_ALL_LED_OFF_L;
272765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  else
273765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang    regoff = REG_LED0_ON_L + (led * 4) + 2;
274765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
275765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // we need to preserve the full OFF bit in *_OFF_H
276765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  uint8_t offbit = (readByte(regoff + 1) & 0x10);
277765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
278765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  time = (time & 0x0fff) | (offbit << 8);
279765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
280765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return writeWord(regoff, time);
281765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
282765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
283765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::setPrescale(uint8_t prescale)
284765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{
285765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  // This will be ignored if the device isn't in SLEEP mode
286765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return writeByte(REG_PRESCALE, prescale);
287765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
288765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
289765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::setPrescaleFromHz(float hz, float oscFreq)
290765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{
291765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  float prescale = round( oscFreq / (4096.0 * hz) ) - 1;
292765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang
293765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang  return setPrescale(uint8_t(prescale));
294765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang}
295