WPILibC++  trunk
I2C.cpp
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) FIRST 2008. 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 $(WIND_BASE)/WPILib. */
5 /*----------------------------------------------------------------------------*/
6 
7 #include "I2C.h"
8 #include "DigitalModule.h"
9 #include "NetworkCommunication/UsageReporting.h"
10 #include "Synchronized.h"
11 #include "WPIErrors.h"
12 #include <taskLib.h>
13 
14 SEM_ID I2C::m_semaphore = NULL;
15 uint32_t I2C::m_objCount = 0;
16 
23 I2C::I2C(DigitalModule *module, uint8_t deviceAddress)
24  : m_module (module)
25  , m_deviceAddress (deviceAddress)
26  , m_compatibilityMode (true)
27 {
28  if (m_semaphore == NULL)
29  {
30  m_semaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE);
31  }
32  m_objCount++;
33 
34  nUsageReporting::report(nUsageReporting::kResourceType_I2C, deviceAddress, module->GetNumber() - 1);
35 }
36 
41 {
42  m_objCount--;
43  if (m_objCount <= 0)
44  {
45  semDelete(m_semaphore);
46  m_semaphore = NULL;
47  }
48 }
49 
61 bool I2C::Transaction(uint8_t *dataToSend, uint8_t sendSize, uint8_t *dataReceived, uint8_t receiveSize)
62 {
63  if (sendSize > 6)
64  {
65  wpi_setWPIErrorWithContext(ParameterOutOfRange, "sendSize");
66  return true;
67  }
68  if (receiveSize > 7)
69  {
70  wpi_setWPIErrorWithContext(ParameterOutOfRange, "receiveSize");
71  return true;
72  }
73 
74  uint32_t data=0;
75  uint32_t dataHigh=0;
76  uint32_t i;
77  for(i=0; i<sendSize && i<sizeof(data); i++)
78  {
79  data |= (uint32_t)dataToSend[i] << (8*i);
80  }
81  for(; i<sendSize; i++)
82  {
83  dataHigh |= (uint32_t)dataToSend[i] << (8*(i-sizeof(data)));
84  }
85 
86  bool aborted = true;
87  tRioStatusCode localStatus = NiFpga_Status_Success;
88  {
89  Synchronized sync(m_semaphore);
90  m_module->m_fpgaDIO->writeI2CConfig_Address(m_deviceAddress, &localStatus);
91  m_module->m_fpgaDIO->writeI2CConfig_BytesToWrite(sendSize, &localStatus);
92  m_module->m_fpgaDIO->writeI2CConfig_BytesToRead(receiveSize, &localStatus);
93  if (sendSize > 0) m_module->m_fpgaDIO->writeI2CDataToSend(data, &localStatus);
94  if (sendSize > sizeof(data)) m_module->m_fpgaDIO->writeI2CConfig_DataToSendHigh(dataHigh, &localStatus);
95  m_module->m_fpgaDIO->writeI2CConfig_BitwiseHandshake(m_compatibilityMode, &localStatus);
96  uint8_t transaction = m_module->m_fpgaDIO->readI2CStatus_Transaction(&localStatus);
97  m_module->m_fpgaDIO->strobeI2CStart(&localStatus);
98  while(transaction == m_module->m_fpgaDIO->readI2CStatus_Transaction(&localStatus)) taskDelay(1);
99  while(!m_module->m_fpgaDIO->readI2CStatus_Done(&localStatus)) taskDelay(1);
100  aborted = m_module->m_fpgaDIO->readI2CStatus_Aborted(&localStatus);
101  if (receiveSize > 0) data = m_module->m_fpgaDIO->readI2CDataReceived(&localStatus);
102  if (receiveSize > sizeof(data)) dataHigh = m_module->m_fpgaDIO->readI2CStatus_DataReceivedHigh(&localStatus);
103  }
104  wpi_setError(localStatus);
105 
106  for(i=0; i<receiveSize && i<sizeof(data); i++)
107  {
108  dataReceived[i] = (data >> (8*i)) & 0xFF;
109  }
110  for(; i<receiveSize; i++)
111  {
112  dataReceived[i] = (dataHigh >> (8*(i-sizeof(data)))) & 0xFF;
113  }
114  return aborted;
115 }
116 
126 {
127  return Transaction(NULL, 0, NULL, 0);
128 }
129 
140 bool I2C::Write(uint8_t registerAddress, uint8_t data)
141 {
142  uint8_t buffer[2];
143  buffer[0] = registerAddress;
144  buffer[1] = data;
145  return Transaction(buffer, sizeof(buffer), NULL, 0);
146 }
147 
161 bool I2C::Read(uint8_t registerAddress, uint8_t count, uint8_t *buffer)
162 {
163  if (count < 1 || count > 7)
164  {
165  wpi_setWPIErrorWithContext(ParameterOutOfRange, "count");
166  return true;
167  }
168  if (buffer == NULL)
169  {
170  wpi_setWPIErrorWithContext(NullParameter, "buffer");
171  return true;
172  }
173 
174  return Transaction(&registerAddress, sizeof(registerAddress), buffer, count);
175 }
176 
185 void I2C::Broadcast(uint8_t registerAddress, uint8_t data)
186 {
187 }
188 
197 void I2C::SetCompatibilityMode(bool enable)
198 {
199  m_compatibilityMode = enable;
200 
201  const char *cm = NULL;
202  if (m_compatibilityMode) cm = "C";
203  nUsageReporting::report(nUsageReporting::kResourceType_I2C, m_deviceAddress, m_module->GetNumber() - 1, cm);
204 }
205 
219 bool I2C::VerifySensor(uint8_t registerAddress, uint8_t count, const uint8_t *expected)
220 {
221  // TODO: Make use of all 7 read bytes
222  uint8_t deviceData[4];
223  for (uint8_t i=0, curRegisterAddress = registerAddress; i < count; i+=4, curRegisterAddress+=4)
224  {
225  uint8_t toRead = count - i < 4 ? count - i : 4;
226  // Read the chunk of data. Return false if the sensor does not respond.
227  if (Read(curRegisterAddress, toRead, deviceData)) return false;
228 
229  for (uint8_t j=0; j<toRead; j++)
230  {
231  if(deviceData[j] != expected[i + j]) return false;
232  }
233  }
234  return true;
235 }
236 
bool AddressOnly()
Definition: I2C.cpp:125
void Broadcast(uint8_t registerAddress, uint8_t data)
Definition: I2C.cpp:185
bool Transaction(uint8_t *dataToSend, uint8_t sendSize, uint8_t *dataReceived, uint8_t receiveSize)
Definition: I2C.cpp:61
void SetCompatibilityMode(bool enable)
Definition: I2C.cpp:197
virtual ~I2C()
Definition: I2C.cpp:40
bool Read(uint8_t registerAddress, uint8_t count, uint8_t *data)
Definition: I2C.cpp:161
bool VerifySensor(uint8_t registerAddress, uint8_t count, const uint8_t *expected)
Definition: I2C.cpp:219
bool Write(uint8_t registerAddress, uint8_t data)
Definition: I2C.cpp:140