From 08297430b57fccf8367cfcb594bf99cbcfba4b9e Mon Sep 17 00:00:00 2001 From: Thad House Date: Mon, 28 Apr 2025 08:29:01 -0700 Subject: [PATCH] [hal,wpilib] Add support for second I2C port (#7878) --- hal/src/main/native/include/hal/I2CTypes.h | 4 +- hal/src/main/native/systemcore/I2C.cpp | 68 +++++++++++-------- .../main/native/systemcore/PortsInternal.h | 1 + .../test/native/cpp/mockdata/I2CDataTest.cpp | 2 +- wpilibc/src/main/native/include/frc/I2C.h | 8 +-- .../examples/I2CCommunication/include/Robot.h | 2 +- .../main/java/edu/wpi/first/wpilibj/I2C.java | 8 +-- .../wpilibj/simulation/ADXL345SimTest.java | 2 +- .../examples/i2ccommunication/Robot.java | 2 +- 9 files changed, 54 insertions(+), 43 deletions(-) diff --git a/hal/src/main/native/include/hal/I2CTypes.h b/hal/src/main/native/include/hal/I2CTypes.h index 075820f31f..a0e64407aa 100644 --- a/hal/src/main/native/include/hal/I2CTypes.h +++ b/hal/src/main/native/include/hal/I2CTypes.h @@ -16,7 +16,7 @@ HAL_ENUM(HAL_I2CPort) { HAL_I2C_kInvalid = -1, - HAL_I2C_kOnboard, - HAL_I2C_kMXP + HAL_I2C_kPort0, + HAL_I2C_kPort1 }; /** @} */ diff --git a/hal/src/main/native/systemcore/I2C.cpp b/hal/src/main/native/systemcore/I2C.cpp index 3e87f607c6..aba2ec0d39 100644 --- a/hal/src/main/native/systemcore/I2C.cpp +++ b/hal/src/main/native/systemcore/I2C.cpp @@ -18,37 +18,46 @@ #include "HALInitializer.h" #include "HALInternal.h" +#include "PortsInternal.h" #include "hal/DIO.h" #include "hal/HAL.h" using namespace hal; -static wpi::mutex digitalI2COnBoardMutex; -static uint8_t i2COnboardObjCount{0}; -static int i2COnBoardHandle{-1}; +namespace { +constexpr const char* physicalPorts[kNumI2cBuses] = {"/dev/i2c-1", + "/dev/i2c-10"}; + +struct I2C { + wpi::mutex initMutex; + int objCount = 0; + int fd = -1; +}; + +static I2C i2cObjs[kNumI2cBuses]; +} // namespace namespace hal::init { void InitializeI2C() {} } // namespace hal::init extern "C" { - void HAL_InitializeI2C(HAL_I2CPort port, int32_t* status) { hal::init::CheckInit(); - if (port != 0) { + if (port < 0 || port > 2) { *status = RESOURCE_OUT_OF_RANGE; - hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for I2C", 0, 0, + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for I2C", 0, 1, port); return; } - std::scoped_lock lock(digitalI2COnBoardMutex); - i2COnboardObjCount++; - if (i2COnboardObjCount > 1) { + std::scoped_lock lock(i2cObjs[port].initMutex); + i2cObjs[port].objCount++; + if (i2cObjs[port].objCount > 1) { return; } - int handle = open("/dev/i2c-1", O_RDWR); + int handle = open(physicalPorts[port], O_RDWR); if (handle < 0) { int err = errno; *status = NO_AVAILABLE_RESOURCES; @@ -56,18 +65,18 @@ void HAL_InitializeI2C(HAL_I2CPort port, int32_t* status) { std::strerror(err))); wpi::print("Failed to open onboard i2c bus: {}\n", std::strerror(err)); handle = -1; - i2COnboardObjCount--; + i2cObjs[port].objCount--; return; } - i2COnBoardHandle = handle; + i2cObjs[port].fd = handle; } int32_t HAL_TransactionI2C(HAL_I2CPort port, int32_t deviceAddress, const uint8_t* dataToSend, int32_t sendSize, uint8_t* dataReceived, int32_t receiveSize) { - if (port != 0) { + if (port < 0 || port > 2) { int32_t status = 0; - hal::SetLastErrorIndexOutOfRange(&status, "Invalid Index for I2C", 0, 0, + hal::SetLastErrorIndexOutOfRange(&status, "Invalid Index for I2C", 0, 1, port); return -1; } @@ -86,15 +95,15 @@ int32_t HAL_TransactionI2C(HAL_I2CPort port, int32_t deviceAddress, rdwr.msgs = msgs; rdwr.nmsgs = 2; - std::scoped_lock lock(digitalI2COnBoardMutex); - return ioctl(i2COnBoardHandle, I2C_RDWR, &rdwr); + std::scoped_lock lock(i2cObjs[port].initMutex); + return ioctl(i2cObjs[port].fd, I2C_RDWR, &rdwr); } int32_t HAL_WriteI2C(HAL_I2CPort port, int32_t deviceAddress, const uint8_t* dataToSend, int32_t sendSize) { - if (port != 0) { + if (port < 0 || port > 2) { int32_t status = 0; - hal::SetLastErrorIndexOutOfRange(&status, "Invalid Index for I2C", 0, 0, + hal::SetLastErrorIndexOutOfRange(&status, "Invalid Index for I2C", 0, 2, port); return -1; } @@ -109,15 +118,15 @@ int32_t HAL_WriteI2C(HAL_I2CPort port, int32_t deviceAddress, rdwr.msgs = &msg; rdwr.nmsgs = 1; - std::scoped_lock lock(digitalI2COnBoardMutex); - return ioctl(i2COnBoardHandle, I2C_RDWR, &rdwr); + std::scoped_lock lock(i2cObjs[port].initMutex); + return ioctl(i2cObjs[port].fd, I2C_RDWR, &rdwr); } int32_t HAL_ReadI2C(HAL_I2CPort port, int32_t deviceAddress, uint8_t* buffer, int32_t count) { - if (port != 0) { + if (port < 0 || port > 2) { int32_t status = 0; - hal::SetLastErrorIndexOutOfRange(&status, "Invalid Index for I2C", 0, 0, + hal::SetLastErrorIndexOutOfRange(&status, "Invalid Index for I2C", 0, 1, port); return -1; } @@ -132,21 +141,22 @@ int32_t HAL_ReadI2C(HAL_I2CPort port, int32_t deviceAddress, uint8_t* buffer, rdwr.msgs = &msg; rdwr.nmsgs = 1; - std::scoped_lock lock(digitalI2COnBoardMutex); - return ioctl(i2COnBoardHandle, I2C_RDWR, &rdwr); + std::scoped_lock lock(i2cObjs[port].initMutex); + return ioctl(i2cObjs[port].fd, I2C_RDWR, &rdwr); } void HAL_CloseI2C(HAL_I2CPort port) { - if (port != 0) { + if (port < 0 || port > 2) { int32_t status = 0; - hal::SetLastErrorIndexOutOfRange(&status, "Invalid Index for I2C", 0, 0, + hal::SetLastErrorIndexOutOfRange(&status, "Invalid Index for I2C", 0, 1, port); return; } - std::scoped_lock lock(digitalI2COnBoardMutex); - if (i2COnboardObjCount-- == 0) { - close(i2COnBoardHandle); + std::scoped_lock lock(i2cObjs[port].initMutex); + if (i2cObjs[port].objCount-- == 0) { + close(i2cObjs[port].objCount); + i2cObjs[port].fd = -1; } } diff --git a/hal/src/main/native/systemcore/PortsInternal.h b/hal/src/main/native/systemcore/PortsInternal.h index cbc3c3c088..6656cbcf85 100644 --- a/hal/src/main/native/systemcore/PortsInternal.h +++ b/hal/src/main/native/systemcore/PortsInternal.h @@ -10,6 +10,7 @@ namespace hal { constexpr int32_t kNumCanBuses = 5; constexpr int32_t kNumSmartIo = 6; +constexpr int32_t kNumI2cBuses = 2; constexpr int32_t kNumAccumulators = 0; constexpr int32_t kNumAnalogInputs = 8; constexpr int32_t kNumAnalogOutputs = 0; diff --git a/hal/src/test/native/cpp/mockdata/I2CDataTest.cpp b/hal/src/test/native/cpp/mockdata/I2CDataTest.cpp index ef6cc04296..8ba7806868 100644 --- a/hal/src/test/native/cpp/mockdata/I2CDataTest.cpp +++ b/hal/src/test/native/cpp/mockdata/I2CDataTest.cpp @@ -31,7 +31,7 @@ TEST(I2CSimTest, I2CInitialization) { INDEX_TO_TEST, &TestI2CInitializationCallback, &callbackParam, false); ASSERT_TRUE(0 != callbackId); - port = HAL_I2C_kMXP; + port = HAL_I2C_kPort1; gTestI2CCallbackName = "Unset"; HAL_InitializeI2C(port, &status); EXPECT_STREQ("Initialized", gTestI2CCallbackName.c_str()); diff --git a/wpilibc/src/main/native/include/frc/I2C.h b/wpilibc/src/main/native/include/frc/I2C.h index 41314fbf56..6b8decedb9 100644 --- a/wpilibc/src/main/native/include/frc/I2C.h +++ b/wpilibc/src/main/native/include/frc/I2C.h @@ -23,10 +23,10 @@ class I2C { * I2C connection ports. */ enum Port { - /// Onboard I2C port. - kOnboard = 0, - /// MXP (roboRIO MXP) I2C port. - kMXP + /// I2C Port 0. + kPort0 = 0, + /// I2C Port 1. + kPort1 }; /** diff --git a/wpilibcExamples/src/main/cpp/examples/I2CCommunication/include/Robot.h b/wpilibcExamples/src/main/cpp/examples/I2CCommunication/include/Robot.h index ede2624cd8..48bbe4a189 100644 --- a/wpilibcExamples/src/main/cpp/examples/I2CCommunication/include/Robot.h +++ b/wpilibcExamples/src/main/cpp/examples/I2CCommunication/include/Robot.h @@ -17,7 +17,7 @@ class Robot : public frc::TimedRobot { public: void RobotPeriodic() override; - static constexpr frc::I2C::Port kPort = frc::I2C::Port::kOnboard; + static constexpr frc::I2C::Port kPort = frc::I2C::Port::kPort0; private: static constexpr int deviceAddress = 4; diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/I2C.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/I2C.java index 209e4e7446..0403207733 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/I2C.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/I2C.java @@ -20,10 +20,10 @@ import java.nio.ByteBuffer; public class I2C implements AutoCloseable { /** I2C connection ports. */ public enum Port { - /** Onboard I2C port. */ - kOnboard(0), - /** MXP (roboRIO MXP) I2C port. */ - kMXP(1); + /** I2C Port 0. */ + kPort0(0), + /** I2C Port 1. */ + kPort1(1); /** Port value. */ public final int value; diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ADXL345SimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ADXL345SimTest.java index ad1f2420c6..cda2650717 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ADXL345SimTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ADXL345SimTest.java @@ -18,7 +18,7 @@ class ADXL345SimTest { void testInitI2C(ADXL345_I2C.Range range) { HAL.initialize(500, 0); - try (ADXL345_I2C accel = new ADXL345_I2C(I2C.Port.kMXP, range)) { + try (ADXL345_I2C accel = new ADXL345_I2C(I2C.Port.kPort0, range)) { ADXL345Sim sim = new ADXL345Sim(accel); sim.setX(1.91); diff --git a/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/i2ccommunication/Robot.java b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/i2ccommunication/Robot.java index bfbfc39de9..1a99d9937e 100644 --- a/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/i2ccommunication/Robot.java +++ b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/i2ccommunication/Robot.java @@ -15,7 +15,7 @@ import java.util.Optional; * code using the roboRIO's I2C port. */ public class Robot extends TimedRobot { - static final Port kPort = Port.kOnboard; + static final Port kPort = Port.kPort0; private static final int kDeviceAddress = 4; private final I2C m_arduino = new I2C(kPort, kDeviceAddress);