blob: 8065d377000d0eae7936e5709fa2d841642a78de [file] [log] [blame]
Brian Silvermanf7f267a2017-02-04 16:16:08 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
3/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#include "HAL/I2C.h"
9
10#include "DigitalInternal.h"
11#include "HAL/DIO.h"
12#include "HAL/HAL.h"
13#include "i2clib/i2c-lib.h"
14
15using namespace hal;
16
17static priority_recursive_mutex digitalI2COnBoardMutex;
18static priority_recursive_mutex digitalI2CMXPMutex;
19
20static uint8_t i2COnboardObjCount = 0;
21static uint8_t i2CMXPObjCount = 0;
22static uint8_t i2COnBoardHandle = 0;
23static uint8_t i2CMXPHandle = 0;
24
25static HAL_DigitalHandle i2CMXPDigitalHandle1 = HAL_kInvalidHandle;
26static HAL_DigitalHandle i2CMXPDigitalHandle2 = HAL_kInvalidHandle;
27
28extern "C" {
29/*
30 * Initialize the I2C port. Opens the port if necessary and saves the handle.
31 * If opening the MXP port, also sets up the channel functions appropriately
32 * @param port The port to open, 0 for the on-board, 1 for the MXP.
33 */
34void HAL_InitializeI2C(int32_t port, int32_t* status) {
35 initializeDigital(status);
36 if (*status != 0) return;
37
38 if (port > 1) {
39 // Set port out of range error here
40 return;
41 }
42
43 priority_recursive_mutex& lock =
44 port == 0 ? digitalI2COnBoardMutex : digitalI2CMXPMutex;
45 {
46 std::lock_guard<priority_recursive_mutex> sync(lock);
47 if (port == 0) {
48 i2COnboardObjCount++;
49 if (i2COnBoardHandle > 0) return;
50 i2COnBoardHandle = i2clib_open("/dev/i2c-2");
51 } else if (port == 1) {
52 i2CMXPObjCount++;
53 if (i2CMXPHandle > 0) return;
54 if ((i2CMXPDigitalHandle1 = HAL_InitializeDIOPort(
55 HAL_GetPort(24), false, status)) == HAL_kInvalidHandle) {
56 return;
57 }
58 if ((i2CMXPDigitalHandle2 = HAL_InitializeDIOPort(
59 HAL_GetPort(25), false, status)) == HAL_kInvalidHandle) {
60 HAL_FreeDIOPort(i2CMXPDigitalHandle1); // free the first port allocated
61 return;
62 }
63 digitalSystem->writeEnableMXPSpecialFunction(
64 digitalSystem->readEnableMXPSpecialFunction(status) | 0xC000, status);
65 i2CMXPHandle = i2clib_open("/dev/i2c-1");
66 }
67 return;
68 }
69}
70
71/**
72 * Generic transaction.
73 *
74 * This is a lower-level interface to the I2C hardware giving you more control
75 * over each transaction.
76 *
77 * @param dataToSend Buffer of data to send as part of the transaction.
78 * @param sendSize Number of bytes to send as part of the transaction.
79 * @param dataReceived Buffer to read data into.
80 * @param receiveSize Number of bytes to read from the device.
81 * @return The number of bytes read (>= 0) or -1 on transfer abort.
82 */
83int32_t HAL_TransactionI2C(int32_t port, int32_t deviceAddress,
84 uint8_t* dataToSend, int32_t sendSize,
85 uint8_t* dataReceived, int32_t receiveSize) {
86 if (port > 1) {
87 // Set port out of range error here
88 return -1;
89 }
90
91 int32_t handle = port == 0 ? i2COnBoardHandle : i2CMXPHandle;
92 priority_recursive_mutex& lock =
93 port == 0 ? digitalI2COnBoardMutex : digitalI2CMXPMutex;
94
95 {
96 std::lock_guard<priority_recursive_mutex> sync(lock);
97 return i2clib_writeread(
98 handle, deviceAddress, reinterpret_cast<const char*>(dataToSend),
99 static_cast<int32_t>(sendSize), reinterpret_cast<char*>(dataReceived),
100 static_cast<int32_t>(receiveSize));
101 }
102}
103
104/**
105 * Execute a write transaction with the device.
106 *
107 * Write a single byte to a register on a device and wait until the
108 * transaction is complete.
109 *
110 * @param registerAddress The address of the register on the device to be
111 * written.
112 * @param data The byte to write to the register on the device.
113 * @return The number of bytes written (>= 0) or -1 on transfer abort.
114 */
115int32_t HAL_WriteI2C(int32_t port, int32_t deviceAddress, uint8_t* dataToSend,
116 int32_t sendSize) {
117 if (port > 1) {
118 // Set port out of range error here
119 return -1;
120 }
121
122 int32_t handle = port == 0 ? i2COnBoardHandle : i2CMXPHandle;
123 priority_recursive_mutex& lock =
124 port == 0 ? digitalI2COnBoardMutex : digitalI2CMXPMutex;
125 {
126 std::lock_guard<priority_recursive_mutex> sync(lock);
127 return i2clib_write(handle, deviceAddress,
128 reinterpret_cast<const char*>(dataToSend), sendSize);
129 }
130}
131
132/**
133 * Execute a read transaction with the device.
134 *
135 * Read bytes from a device.
136 * Most I2C devices will auto-increment the register pointer internally allowing
137 * you to read consecutive registers on a device in a single transaction.
138 *
139 * @param registerAddress The register to read first in the transaction.
140 * @param count The number of bytes to read in the transaction.
141 * @param buffer A pointer to the array of bytes to store the data read from the
142 * device.
143 * @return The number of bytes read (>= 0) or -1 on transfer abort.
144 */
145int32_t HAL_ReadI2C(int32_t port, int32_t deviceAddress, uint8_t* buffer,
146 int32_t count) {
147 if (port > 1) {
148 // Set port out of range error here
149 return -1;
150 }
151
152 int32_t handle = port == 0 ? i2COnBoardHandle : i2CMXPHandle;
153 priority_recursive_mutex& lock =
154 port == 0 ? digitalI2COnBoardMutex : digitalI2CMXPMutex;
155 {
156 std::lock_guard<priority_recursive_mutex> sync(lock);
157 return i2clib_read(handle, deviceAddress, reinterpret_cast<char*>(buffer),
158 static_cast<int32_t>(count));
159 }
160}
161
162void HAL_CloseI2C(int32_t port) {
163 if (port > 1) {
164 // Set port out of range error here
165 return;
166 }
167 priority_recursive_mutex& lock =
168 port == 0 ? digitalI2COnBoardMutex : digitalI2CMXPMutex;
169 {
170 std::lock_guard<priority_recursive_mutex> sync(lock);
171 if ((port == 0 ? i2COnboardObjCount-- : i2CMXPObjCount--) == 0) {
172 int32_t handle = port == 0 ? i2COnBoardHandle : i2CMXPHandle;
173 i2clib_close(handle);
174 }
175 }
176
177 if (port == 1) {
178 HAL_FreeDIOPort(i2CMXPDigitalHandle1);
179 HAL_FreeDIOPort(i2CMXPDigitalHandle2);
180 }
181 return;
182}
183}