blob: 232a47f0f1263d93550a05ed21551429a8d921fa [file] [log] [blame]
Austin Schuh812d0d12021-11-04 20:16:48 -07001// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
Brian Silverman8fce7482020-01-05 13:18:21 -08004
5#include "frc/I2C.h"
6
Maxwell Henderson80bec322024-01-09 15:48:44 -08007#include <algorithm>
Brian Silverman8fce7482020-01-05 13:18:21 -08008#include <utility>
9
10#include <hal/FRCUsageReporting.h>
11#include <hal/I2C.h>
12
Austin Schuh812d0d12021-11-04 20:16:48 -070013#include "frc/Errors.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080014
15using namespace frc;
16
17I2C::I2C(Port port, int deviceAddress)
18 : m_port(static_cast<HAL_I2CPort>(port)), m_deviceAddress(deviceAddress) {
19 int32_t status = 0;
Austin Schuh75263e32022-02-22 18:05:32 -080020
21 if (port == I2C::Port::kOnboard) {
James Kuszmaulcf324122023-01-14 14:07:17 -080022 FRC_ReportError(warn::Warning,
Austin Schuh75263e32022-02-22 18:05:32 -080023 "Onboard I2C port is subject to system lockups. See Known "
24 "Issues page for "
25 "details");
26 }
27
Brian Silverman8fce7482020-01-05 13:18:21 -080028 HAL_InitializeI2C(m_port, &status);
James Kuszmaulcf324122023-01-14 14:07:17 -080029 FRC_CheckErrorStatus(status, "Port {}", static_cast<int>(port));
Brian Silverman8fce7482020-01-05 13:18:21 -080030
31 HAL_Report(HALUsageReporting::kResourceType_I2C, deviceAddress);
32}
33
Austin Schuh812d0d12021-11-04 20:16:48 -070034I2C::~I2C() {
35 HAL_CloseI2C(m_port);
36}
37
38I2C::Port I2C::GetPort() const {
39 return static_cast<Port>(static_cast<int>(m_port));
40}
41
42int I2C::GetDeviceAddress() const {
43 return m_deviceAddress;
44}
Brian Silverman8fce7482020-01-05 13:18:21 -080045
46bool I2C::Transaction(uint8_t* dataToSend, int sendSize, uint8_t* dataReceived,
47 int receiveSize) {
48 int32_t status = 0;
49 status = HAL_TransactionI2C(m_port, m_deviceAddress, dataToSend, sendSize,
50 dataReceived, receiveSize);
Brian Silverman8fce7482020-01-05 13:18:21 -080051 return status < 0;
52}
53
Austin Schuh812d0d12021-11-04 20:16:48 -070054bool I2C::AddressOnly() {
55 return Transaction(nullptr, 0, nullptr, 0);
56}
Brian Silverman8fce7482020-01-05 13:18:21 -080057
58bool I2C::Write(int registerAddress, uint8_t data) {
59 uint8_t buffer[2];
60 buffer[0] = registerAddress;
61 buffer[1] = data;
62 int32_t status = 0;
63 status = HAL_WriteI2C(m_port, m_deviceAddress, buffer, sizeof(buffer));
64 return status < 0;
65}
66
67bool I2C::WriteBulk(uint8_t* data, int count) {
68 int32_t status = 0;
69 status = HAL_WriteI2C(m_port, m_deviceAddress, data, count);
70 return status < 0;
71}
72
73bool I2C::Read(int registerAddress, int count, uint8_t* buffer) {
74 if (count < 1) {
Austin Schuh812d0d12021-11-04 20:16:48 -070075 throw FRC_MakeError(err::ParameterOutOfRange, "count {}", count);
Brian Silverman8fce7482020-01-05 13:18:21 -080076 }
Austin Schuh812d0d12021-11-04 20:16:48 -070077 if (!buffer) {
James Kuszmaulcf324122023-01-14 14:07:17 -080078 throw FRC_MakeError(err::NullParameter, "buffer");
Brian Silverman8fce7482020-01-05 13:18:21 -080079 }
80 uint8_t regAddr = registerAddress;
81 return Transaction(&regAddr, sizeof(regAddr), buffer, count);
82}
83
84bool I2C::ReadOnly(int count, uint8_t* buffer) {
85 if (count < 1) {
Austin Schuh812d0d12021-11-04 20:16:48 -070086 throw FRC_MakeError(err::ParameterOutOfRange, "count {}", count);
Brian Silverman8fce7482020-01-05 13:18:21 -080087 }
Austin Schuh812d0d12021-11-04 20:16:48 -070088 if (!buffer) {
James Kuszmaulcf324122023-01-14 14:07:17 -080089 throw FRC_MakeError(err::NullParameter, "buffer");
Brian Silverman8fce7482020-01-05 13:18:21 -080090 }
91 return HAL_ReadI2C(m_port, m_deviceAddress, buffer, count) < 0;
92}
93
94bool I2C::VerifySensor(int registerAddress, int count,
95 const uint8_t* expected) {
96 // TODO: Make use of all 7 read bytes
97 uint8_t deviceData[4];
98 for (int i = 0, curRegisterAddress = registerAddress; i < count;
99 i += 4, curRegisterAddress += 4) {
Maxwell Henderson80bec322024-01-09 15:48:44 -0800100 int toRead = std::min(count - i, 4);
Brian Silverman8fce7482020-01-05 13:18:21 -0800101 // Read the chunk of data. Return false if the sensor does not respond.
Austin Schuh812d0d12021-11-04 20:16:48 -0700102 if (Read(curRegisterAddress, toRead, deviceData)) {
103 return false;
104 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800105
106 for (int j = 0; j < toRead; j++) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700107 if (deviceData[j] != expected[i + j]) {
108 return false;
109 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800110 }
111 }
112 return true;
113}