Merge branch 'crio-compiling-switch' into network-robot-new
diff --git a/aos/atom_code/input/FRCComm.h b/aos/atom_code/input/FRCComm.h
index 14c4602..98619de 100644
--- a/aos/atom_code/input/FRCComm.h
+++ b/aos/atom_code/input/FRCComm.h
@@ -124,7 +124,6 @@
UINT32 FPGAChecksum3;
char versionData[8];
-};
-
+} __attribute__((packed));
#endif
diff --git a/aos/build/aos.gypi b/aos/build/aos.gypi
index 662a419..115ae06 100644
--- a/aos/build/aos.gypi
+++ b/aos/build/aos.gypi
@@ -44,6 +44,8 @@
'defines': [
'__STDC_FORMAT_MACROS',
'_FORTIFY_SOURCE=2',
+ '__STDC_CONSTANT_MACROS',
+ '__STDC_LIMIT_MACROS',
],
'ldflags': [
'-pipe',
diff --git a/aos/build/download_externals.sh b/aos/build/download_externals.sh
index 5e07d02..4f999b2 100755
--- a/aos/build/download_externals.sh
+++ b/aos/build/download_externals.sh
@@ -89,3 +89,10 @@
CFLAGS='-m32' CXXFLAGS='-m32' LDFLAGS='-m32' \
bash -c "cd ${LIBUSB_DIR} && ./configure \
--prefix=`readlink -f ${LIBUSB_PREFIX}` && make && make install"
+
+# get the LLVM Compiler-RT source
+COMPILER_RT_TAG=RELEASE_32/final
+COMPILER_RT_VERSION=`echo ${COMPILER_RT_TAG} | sed s:/:_:`
+COMPILER_RT_DIR=${EXTERNALS}/compiler-rt-${COMPILER_RT_VERSION}
+COMPILER_RT_URL=http://llvm.org/svn/llvm-project/compiler-rt/tags/${COMPILER_RT_TAG}
+[ -d ${COMPILER_RT_DIR} ] || svn checkout ${COMPILER_RT_URL} ${COMPILER_RT_DIR}
diff --git a/aos/build/externals.gyp b/aos/build/externals.gyp
index 0fa5fed..0daa229 100644
--- a/aos/build/externals.gyp
+++ b/aos/build/externals.gyp
@@ -13,6 +13,7 @@
'gflags_version': '2.0',
'libusb_version': '1.0.9',
'libusb_apiversion': '1.0',
+ 'compiler_rt_version': 'RELEASE_32_final',
},
'targets': [
{
@@ -187,4 +188,7 @@
},
},
],
+ 'includes': [
+ 'libgcc-additions/libgcc-additions.gypi',
+ ],
}
diff --git a/aos/build/libgcc-additions/README b/aos/build/libgcc-additions/README
new file mode 100644
index 0000000..6a9a665
--- /dev/null
+++ b/aos/build/libgcc-additions/README
@@ -0,0 +1,26 @@
+This directory contains the stuff necessary to deal with the fact that the
+ libgcc.a from the old GCC that the cRIO has doesn't have all of the functions
+ that newer GCCs expect from it.
+
+[extra functions necessary for 4.5.2]
+I generated this diff with `powerpc-wrs-vxworks-nm \
+ gccdist/WindRiver/gnu/3.4.4-vxworks-6.3/x86-win32/lib/gcc/powerpc-wrs-vxworks/3.4.4/libgcc.a \
+ | fgrep '000 T' | awk ' { print $NF }'` (and using the same command with the
+ gccdist.a from the 4.5.2 GCC.
+ I then gave the outputs from both of those to diff and edited out by hand the
+ functions that just moved.
+__powisf2
+__powidf2
+__mulsc3
+__muldc3
+__divsc3
+__divdc3
+__bswapsi2
+__bswapdi2
+__floatundisf
+__floatundidf
+__eprintf
+
+eprintf looks like it's not needed.
+Compiler-RT thinks that bswapsi2 and bswapdi2 are only needed on arm, so it
+ only has arm assembly for them.
diff --git a/aos/build/libgcc-additions/_bswapdi2.o b/aos/build/libgcc-additions/_bswapdi2.o
new file mode 100644
index 0000000..8bc6f56
--- /dev/null
+++ b/aos/build/libgcc-additions/_bswapdi2.o
Binary files differ
diff --git a/aos/build/libgcc-additions/_bswapsi2.o b/aos/build/libgcc-additions/_bswapsi2.o
new file mode 100644
index 0000000..4700ad8
--- /dev/null
+++ b/aos/build/libgcc-additions/_bswapsi2.o
Binary files differ
diff --git a/aos/build/libgcc-additions/libgcc-additions.gypi b/aos/build/libgcc-additions/libgcc-additions.gypi
new file mode 100644
index 0000000..8090f7c
--- /dev/null
+++ b/aos/build/libgcc-additions/libgcc-additions.gypi
@@ -0,0 +1,33 @@
+{
+ 'targets': [
+ {
+ 'target_name': 'libgcc-4.5.2',
+ 'type': 'static_library',
+ 'variables': {
+ 'compiler-rt': '<(externals)/compiler-rt-<(compiler_rt_version)',
+ },
+ 'include_dirs': [
+ '<(compiler-rt)/lib',
+ ],
+ 'defines': [
+ '_YUGA_BIG_ENDIAN=1',
+ '_YUGA_LITTLE_ENDIAN=0',
+ 'UINT64_C(c)=c##ULL',
+ ],
+ 'sources': [
+ '<(compiler-rt)/lib/powisf2.c',
+ '<(compiler-rt)/lib/powidf2.c',
+ '<(compiler-rt)/lib/mulsc3.c',
+ '<(compiler-rt)/lib/muldc3.c',
+ '<(compiler-rt)/lib/divsc3.c',
+ '<(compiler-rt)/lib/divdc3.c',
+ #'<(compiler-rt)/lib/bswapsi2.c',
+ '_bswapsi2.o',
+ #'<(compiler-rt)/lib/bswapdi2.c',
+ '_bswapdi2.o',
+ '<(compiler-rt)/lib/floatundisf.c',
+ '<(compiler-rt)/lib/floatundidf.c',
+ ],
+ },
+ ],
+}
diff --git a/aos/externals/.gitignore b/aos/externals/.gitignore
index 7f6c98d..64c3acf 100644
--- a/aos/externals/.gitignore
+++ b/aos/externals/.gitignore
@@ -21,3 +21,4 @@
/libusb-1.0.9-prefix/
/libusb-1.0.9.tar.bz2
/libusb-1.0.9/
+/compiler-rt-RELEASE_32_final/
diff --git a/aos/externals/WPILib/WPILib/ADXL345_I2C.cpp b/aos/externals/WPILib/WPILib/ADXL345_I2C.cpp
index 9880e0e..2a4040e 100644
--- a/aos/externals/WPILib/WPILib/ADXL345_I2C.cpp
+++ b/aos/externals/WPILib/WPILib/ADXL345_I2C.cpp
@@ -73,7 +73,7 @@
*/
ADXL345_I2C::AllAxes ADXL345_I2C::GetAccelerations()
{
- AllAxes data = {0.0};
+ AllAxes data = {0.0, 0.0, 0.0};
INT16 rawData[3];
if (m_i2c)
{
diff --git a/aos/externals/WPILib/WPILib/ADXL345_SPI.cpp b/aos/externals/WPILib/WPILib/ADXL345_SPI.cpp
index 789448d..42d8dea 100644
--- a/aos/externals/WPILib/WPILib/ADXL345_SPI.cpp
+++ b/aos/externals/WPILib/WPILib/ADXL345_SPI.cpp
@@ -157,7 +157,7 @@
*/
ADXL345_SPI::AllAxes ADXL345_SPI::GetAccelerations()
{
- AllAxes data = {0.0};
+ AllAxes data = {0.0, 0.0, 0.0};
INT16 rawData[3];
if (m_spi)
{
diff --git a/aos/externals/WPILib/WPILib/AnalogChannel.cpp b/aos/externals/WPILib/WPILib/AnalogChannel.cpp
index 834837f..26708c1 100644
--- a/aos/externals/WPILib/WPILib/AnalogChannel.cpp
+++ b/aos/externals/WPILib/WPILib/AnalogChannel.cpp
@@ -38,9 +38,9 @@
}
snprintf(buf, 64, "Analog Input %d (Module: %d)", channel, moduleNumber);
- if (channels->Allocate((moduleNumber - 1) * kAnalogChannels + channel - 1, buf) == ~0ul)
+ if (channels->Allocate((moduleNumber - 1) * kAnalogChannels +
+ channel - 1, buf, this) == ~0ul)
{
- CloneError(channels);
return;
}
m_channel = channel;
@@ -86,7 +86,8 @@
*/
AnalogChannel::~AnalogChannel()
{
- channels->Free((m_module->GetNumber() - 1) * kAnalogChannels + m_channel - 1);
+ channels->Free((m_module->GetNumber() - 1) * kAnalogChannels + m_channel - 1,
+ this);
}
/**
diff --git a/aos/externals/WPILib/WPILib/AnalogModule.cpp b/aos/externals/WPILib/WPILib/AnalogModule.cpp
index d685c13..68e7940 100644
--- a/aos/externals/WPILib/WPILib/AnalogModule.cpp
+++ b/aos/externals/WPILib/WPILib/AnalogModule.cpp
@@ -14,7 +14,8 @@
const long AnalogModule::kDefaultOversampleBits;
const long AnalogModule::kDefaultAverageBits;
const float AnalogModule::kDefaultSampleRate;
-SEM_ID AnalogModule::m_registerWindowSemaphore = NULL;
+// Needs to be global since the protected resource spans both module singletons.
+ReentrantSemaphore AnalogModule::m_registerWindowSemaphore;
/**
* Get an instance of an Analog Module.
@@ -71,12 +72,6 @@
SetAverageBits(i + 1, kDefaultAverageBits);
SetOversampleBits(i + 1, kDefaultOversampleBits);
}
-
- if (m_registerWindowSemaphore == NULL)
- {
- // Needs to be global since the protected resource spans both module singletons.
- m_registerWindowSemaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE);
- }
}
/**
diff --git a/aos/externals/WPILib/WPILib/AnalogModule.h b/aos/externals/WPILib/WPILib/AnalogModule.h
index 3f69685..3ed44ca 100644
--- a/aos/externals/WPILib/WPILib/AnalogModule.h
+++ b/aos/externals/WPILib/WPILib/AnalogModule.h
@@ -48,7 +48,7 @@
virtual ~AnalogModule();
private:
- static SEM_ID m_registerWindowSemaphore;
+ static ReentrantSemaphore m_registerWindowSemaphore;
UINT32 GetNumActiveChannels();
UINT32 GetNumChannelsToActivate();
diff --git a/aos/externals/WPILib/WPILib/AnalogTrigger.cpp b/aos/externals/WPILib/WPILib/AnalogTrigger.cpp
index ffe45c1..2deeb54 100644
--- a/aos/externals/WPILib/WPILib/AnalogTrigger.cpp
+++ b/aos/externals/WPILib/WPILib/AnalogTrigger.cpp
@@ -21,10 +21,9 @@
void AnalogTrigger::InitTrigger(UINT8 moduleNumber, UINT32 channel)
{
Resource::CreateResourceObject(&triggers, tAnalogTrigger::kNumSystems);
- UINT32 index = triggers->Allocate("Analog Trigger");
+ UINT32 index = triggers->Allocate("Analog Trigger", this);
if (index == ~0ul)
{
- CloneError(triggers);
return;
}
m_index = (UINT8)index;
@@ -74,7 +73,7 @@
AnalogTrigger::~AnalogTrigger()
{
- triggers->Free(m_index);
+ triggers->Free(m_index, this);
delete m_trigger;
}
diff --git a/aos/externals/WPILib/WPILib/CAN/JaguarCANDriver.h b/aos/externals/WPILib/WPILib/CAN/JaguarCANDriver.h
index 35c82a5..0f8afe4 100644
--- a/aos/externals/WPILib/WPILib/CAN/JaguarCANDriver.h
+++ b/aos/externals/WPILib/WPILib/CAN/JaguarCANDriver.h
@@ -14,8 +14,6 @@
#ifndef __JaguarCANDriver_h__
#define __JaguarCANDriver_h__
-#include <VxWorks.h>
-
#ifdef __cplusplus
extern "C"
{
diff --git a/aos/externals/WPILib/WPILib/CANJaguar.cpp b/aos/externals/WPILib/WPILib/CANJaguar.cpp
index cf03370..ec55460 100644
--- a/aos/externals/WPILib/WPILib/CANJaguar.cpp
+++ b/aos/externals/WPILib/WPILib/CANJaguar.cpp
@@ -1223,7 +1223,7 @@
void CANJaguar::GetDescription(char *desc)
{
- sprintf(desc, "CANJaguar ID %d", m_deviceNumber);
+ snprintf(desc, 64, "CANJaguar ID %d", m_deviceNumber);
}
/**
diff --git a/aos/externals/WPILib/WPILib/ChipObject/tSystemInterface.h b/aos/externals/WPILib/WPILib/ChipObject/tSystemInterface.h
index 46786e8..d5008e1 100644
--- a/aos/externals/WPILib/WPILib/ChipObject/tSystemInterface.h
+++ b/aos/externals/WPILib/WPILib/ChipObject/tSystemInterface.h
@@ -12,9 +12,9 @@
tSystemInterface(){}
virtual ~tSystemInterface(){}
- virtual const uint16_t getExpectedFPGAVersion()=0;
- virtual const uint32_t getExpectedFPGARevision()=0;
- virtual const uint32_t * const getExpectedFPGASignature()=0;
+ virtual uint16_t getExpectedFPGAVersion()=0;
+ virtual uint32_t getExpectedFPGARevision()=0;
+ virtual uint32_t * getExpectedFPGASignature()=0;
virtual void getHardwareFpgaSignature(uint32_t *guid_ptr, tRioStatusCode *status)=0;
virtual uint32_t getLVHandle(tRioStatusCode *status)=0;
virtual uint32_t getHandle()=0;
diff --git a/aos/externals/WPILib/WPILib/Counter.cpp b/aos/externals/WPILib/WPILib/Counter.cpp
index a11c268..e7c17ad 100644
--- a/aos/externals/WPILib/WPILib/Counter.cpp
+++ b/aos/externals/WPILib/WPILib/Counter.cpp
@@ -20,10 +20,9 @@
void Counter::InitCounter(Mode mode)
{
Resource::CreateResourceObject(&counters, tCounter::kNumSystems);
- UINT32 index = counters->Allocate("Counter");
+ UINT32 index = counters->Allocate("Counter", this);
if (index == ~0ul)
{
- CloneError(counters);
return;
}
m_index = index;
@@ -183,7 +182,7 @@
}
delete m_counter;
m_counter = NULL;
- counters->Free(m_index);
+ counters->Free(m_index, this);
}
/**
diff --git a/aos/externals/WPILib/WPILib/Dashboard.cpp b/aos/externals/WPILib/WPILib/Dashboard.cpp
index c513baf..2235b99 100644
--- a/aos/externals/WPILib/WPILib/Dashboard.cpp
+++ b/aos/externals/WPILib/WPILib/Dashboard.cpp
@@ -29,7 +29,7 @@
{
m_userStatusData = new char[kMaxDashboardDataSize];
m_localBuffer = new char[kMaxDashboardDataSize];
- m_localPrintBuffer = new char[kMaxDashboardDataSize * 2];
+ m_localPrintBuffer = new char[kLocalPrintBufferSize];
m_localPrintBuffer[0] = 0;
m_packPtr = m_localBuffer;
m_printSemaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE);
@@ -275,7 +275,7 @@
va_start (args, writeFmt);
{
Synchronized sync(m_printSemaphore);
- vsprintf(m_localPrintBuffer + strlen(m_localPrintBuffer), writeFmt, args);
+ vsnprintf(m_localPrintBuffer + strlen(m_localPrintBuffer), kLocalPrintBufferSize - strlen(m_localPrintBuffer), writeFmt, args);
size = strlen(m_localPrintBuffer);
}
if (size > kMaxDashboardDataSize)
diff --git a/aos/externals/WPILib/WPILib/Dashboard.h b/aos/externals/WPILib/WPILib/Dashboard.h
index dfcf989..1856660 100644
--- a/aos/externals/WPILib/WPILib/Dashboard.h
+++ b/aos/externals/WPILib/WPILib/Dashboard.h
@@ -50,6 +50,7 @@
void Flush() {}
private:
static const INT32 kMaxDashboardDataSize = USER_STATUS_DATA_SIZE - sizeof(UINT32) * 3 - sizeof(UINT8); // 13 bytes needed for 3 size parameters and the sequence number
+ static const size_t kLocalPrintBufferSize = kMaxDashboardDataSize * 2;
// Usage Guidelines...
DISALLOW_COPY_AND_ASSIGN(Dashboard);
diff --git a/aos/externals/WPILib/WPILib/DigitalModule.cpp b/aos/externals/WPILib/WPILib/DigitalModule.cpp
index 3e7f728..d715c65 100644
--- a/aos/externals/WPILib/WPILib/DigitalModule.cpp
+++ b/aos/externals/WPILib/WPILib/DigitalModule.cpp
@@ -63,7 +63,7 @@
if (m_fpgaDIO->readLoopTiming(&localStatus) != kExpectedLoopTiming)
{
char err[128];
- sprintf(err, "DIO LoopTiming: %d, expecting: %d\n", m_fpgaDIO->readLoopTiming(&localStatus), kExpectedLoopTiming);
+ snprintf(err, sizeof(err), "DIO LoopTiming: %d, expecting: %d\n", m_fpgaDIO->readLoopTiming(&localStatus), kExpectedLoopTiming);
wpi_setWPIErrorWithContext(LoopTimingError, err);
}
m_fpgaDIO->writePWMConfig_Period(PWM::kDefaultPwmPeriod, &localStatus);
@@ -154,18 +154,7 @@
*/
void DigitalModule::SetRelayForward(UINT32 channel, bool on)
{
- tRioStatusCode localStatus = NiFpga_Status_Success;
- CheckRelayChannel(channel);
- {
- Synchronized sync(m_relaySemaphore);
- UINT8 forwardRelays = m_fpgaDIO->readSlowValue_RelayFwd(&localStatus);
- if (on)
- forwardRelays |= 1 << (channel - 1);
- else
- forwardRelays &= ~(1 << (channel - 1));
- m_fpgaDIO->writeSlowValue_RelayFwd(forwardRelays, &localStatus);
- }
- wpi_setError(localStatus);
+ SetRelaysForward(1 << (channel - 1), on ? 0xFF : 0x00);
}
/**
@@ -175,18 +164,47 @@
*/
void DigitalModule::SetRelayReverse(UINT32 channel, bool on)
{
- tRioStatusCode localStatus = NiFpga_Status_Success;
- CheckRelayChannel(channel);
- {
- Synchronized sync(m_relaySemaphore);
- UINT8 reverseRelays = m_fpgaDIO->readSlowValue_RelayRev(&localStatus);
- if (on)
- reverseRelays |= 1 << (channel - 1);
- else
- reverseRelays &= ~(1 << (channel - 1));
- m_fpgaDIO->writeSlowValue_RelayRev(reverseRelays, &localStatus);
- }
- wpi_setError(localStatus);
+ SetRelaysReverse(1 << (channel - 1), on ? 0xFF : 0x00);
+}
+
+/**
+ * Set the state of multiple relays at the same time.
+ * For both parameters, 0b100000000 is channel 1 and 0b00000001 is channel 8.
+ * @param mask which relays to set
+ * @param values what to set the relays to
+ */
+void DigitalModule::SetRelaysForward(UINT8 mask, UINT8 values) {
+ tRioStatusCode localStatus = NiFpga_Status_Success;
+ {
+ Synchronized sync(m_relaySemaphore);
+ UINT8 current = m_fpgaDIO->readSlowValue_RelayFwd(&localStatus);
+ // Clearr all of the bits that we're messing with first.
+ current &= ~mask;
+ // Then set only the ones that are supposed to be set.
+ current |= (mask & values);
+ m_fpgaDIO->writeSlowValue_RelayFwd(current, &localStatus);
+ }
+ wpi_setError(localStatus);
+}
+
+/**
+ * Set the state of multiple relays at the same time.
+ * For both parameters, 0b100000000 is channel 1 and 0b00000001 is channel 8.
+ * @param mask which relays to set
+ * @param values what to set the relays to
+ */
+void DigitalModule::SetRelaysReverse(UINT8 mask, UINT8 values) {
+ tRioStatusCode localStatus = NiFpga_Status_Success;
+ {
+ Synchronized sync(m_relaySemaphore);
+ UINT8 current = m_fpgaDIO->readSlowValue_RelayRev(&localStatus);
+ // Clearr all of the bits that we're messing with first.
+ current &= ~mask;
+ // Then set only the ones that are supposed to be set.
+ current |= (mask & values);
+ m_fpgaDIO->writeSlowValue_RelayRev(current, &localStatus);
+ }
+ wpi_setError(localStatus);
}
/**
@@ -248,7 +266,8 @@
{
char buf[64];
snprintf(buf, 64, "DIO %d (Module %d)", channel, m_moduleNumber);
- if (DIOChannels->Allocate(kDigitalChannels * (m_moduleNumber - 1) + channel - 1, buf) == ~0ul) return false;
+ if (DIOChannels->Allocate(kDigitalChannels * (m_moduleNumber - 1) +
+ channel - 1, buf, this) == ~0ul) return false;
tRioStatusCode localStatus = NiFpga_Status_Success;
{
Synchronized sync(m_digitalSemaphore);
@@ -276,7 +295,29 @@
*/
void DigitalModule::FreeDIO(UINT32 channel)
{
- DIOChannels->Free(kDigitalChannels * (m_moduleNumber - 1) + channel - 1);
+ DIOChannels->Free(kDigitalChannels * (m_moduleNumber - 1) + channel - 1,
+ this);
+}
+
+/**
+ * Write multiple digital I/O bits to the FPGA at the same time.
+ * For both parameters, 0x0001 is channel 16 and 0x8000 is channel 1.
+ *
+ * @param mask Which bits to modify.
+ * @param values What to set all of the bits in mask to.
+ */
+void DigitalModule::SetDIOs(UINT16 mask, UINT16 values) {
+ tRioStatusCode localStatus = NiFpga_Status_Success;
+ {
+ Synchronized sync(m_digitalSemaphore);
+ UINT16 current = m_fpgaDIO->readDO(&localStatus);
+ // Clear all of the bits that we're messing with first.
+ current &= ~mask;
+ // Then set only the ones that are supposed to be set.
+ current |= (mask & values);
+ m_fpgaDIO->writeDO(current, &localStatus);
+ }
+ wpi_setError(localStatus);
}
/**
@@ -286,29 +327,9 @@
* @param channel The Digital I/O channel
* @param value The state to set the digital channel (if it is configured as an output)
*/
-void DigitalModule::SetDIO(UINT32 channel, short value)
+void DigitalModule::SetDIO(UINT32 channel, bool value)
{
- if (value != 0 && value != 1)
- {
- wpi_setWPIError(NonBinaryDigitalValue);
- if (value != 0)
- value = 1;
- }
- tRioStatusCode localStatus = NiFpga_Status_Success;
- {
- Synchronized sync(m_digitalSemaphore);
- UINT16 currentDIO = m_fpgaDIO->readDO(&localStatus);
- if(value == 0)
- {
- currentDIO = currentDIO & ~(1 << RemapDigitalChannel(channel - 1));
- }
- else if (value == 1)
- {
- currentDIO = currentDIO | (1 << RemapDigitalChannel(channel - 1));
- }
- m_fpgaDIO->writeDO(currentDIO, &localStatus);
- }
- wpi_setError(localStatus);
+ SetDIOs(1 << RemapDigitalChannel(channel - 1), value ? 0xFFFF : 0x0000);
}
/**
@@ -421,7 +442,7 @@
/**
* Allocate a DO PWM Generator.
- * Allocate PWM generators so that they are not accidently reused.
+ * Allocate PWM generators so that they are not accidentally reused.
*
* @return PWM Generator refnum
*/
@@ -429,7 +450,7 @@
{
char buf[64];
snprintf(buf, 64, "DO_PWM (Module: %d)", m_moduleNumber);
- return DO_PWMGenerators[(m_moduleNumber - 1)]->Allocate(buf);
+ return DO_PWMGenerators[(m_moduleNumber - 1)]->Allocate(buf, this);
}
/**
@@ -440,7 +461,7 @@
void DigitalModule::FreeDO_PWM(UINT32 pwmGenerator)
{
if (pwmGenerator == ~0ul) return;
- DO_PWMGenerators[(m_moduleNumber - 1)]->Free(pwmGenerator);
+ DO_PWMGenerators[(m_moduleNumber - 1)]->Free(pwmGenerator, this);
}
/**
@@ -461,7 +482,7 @@
}
/**
- * Configure which DO channel the PWM siganl is output on
+ * Configure which DO channel the PWM signal is output on
*
* @param pwmGenerator The generator index reserved by AllocateDO_PWM()
* @param channel The Digital Output channel to output on
diff --git a/aos/externals/WPILib/WPILib/DigitalModule.h b/aos/externals/WPILib/WPILib/DigitalModule.h
index e80beb6..44f617f 100644
--- a/aos/externals/WPILib/WPILib/DigitalModule.h
+++ b/aos/externals/WPILib/WPILib/DigitalModule.h
@@ -29,13 +29,16 @@
void SetPWMPeriodScale(UINT32 channel, UINT32 squelchMask);
void SetRelayForward(UINT32 channel, bool on);
void SetRelayReverse(UINT32 channel, bool on);
+ void SetRelaysForward(UINT8 mask, UINT8 values);
+ void SetRelaysReverse(UINT8 mask, UINT8 values);
bool GetRelayForward(UINT32 channel);
UINT8 GetRelayForward();
bool GetRelayReverse(UINT32 channel);
UINT8 GetRelayReverse();
bool AllocateDIO(UINT32 channel, bool input);
void FreeDIO(UINT32 channel);
- void SetDIO(UINT32 channel, short value);
+ void SetDIOs(UINT16 mask, UINT16 values);
+ void SetDIO(UINT32 channel, bool value);
bool GetDIO(UINT32 channel);
UINT16 GetDIO();
bool GetDIODirection(UINT32 channel);
diff --git a/aos/externals/WPILib/WPILib/DigitalOutput.cpp b/aos/externals/WPILib/WPILib/DigitalOutput.cpp
index a571066..4f45ee7 100644
--- a/aos/externals/WPILib/WPILib/DigitalOutput.cpp
+++ b/aos/externals/WPILib/WPILib/DigitalOutput.cpp
@@ -214,10 +214,9 @@
void DigitalOutput::RequestInterrupts(tInterruptHandler handler, void *param)
{
if (StatusIsFatal()) return;
- UINT32 index = interruptsResource->Allocate("Sync Interrupt");
+ UINT32 index = interruptsResource->Allocate("Sync Interrupt", this);
if (index == ~0ul)
{
- CloneError(interruptsResource);
return;
}
m_interruptIndex = index;
@@ -245,10 +244,9 @@
void DigitalOutput::RequestInterrupts()
{
if (StatusIsFatal()) return;
- UINT32 index = interruptsResource->Allocate("Sync Interrupt");
+ UINT32 index = interruptsResource->Allocate("Sync Interrupt", this);
if (index == ~0ul)
{
- CloneError(interruptsResource);
return;
}
m_interruptIndex = index;
diff --git a/aos/externals/WPILib/WPILib/DigitalSource.cpp b/aos/externals/WPILib/WPILib/DigitalSource.cpp
index 3c1e3a8..862b439 100644
--- a/aos/externals/WPILib/WPILib/DigitalSource.cpp
+++ b/aos/externals/WPILib/WPILib/DigitalSource.cpp
@@ -24,7 +24,7 @@
{
delete m_manager;
delete m_interrupt;
- interruptsResource->Free(m_interruptIndex);
+ interruptsResource->Free(m_interruptIndex, this);
}
}
@@ -39,10 +39,9 @@
void DigitalSource::RequestInterrupts(tInterruptHandler handler, void *param)
{
if (StatusIsFatal()) return;
- UINT32 index = interruptsResource->Allocate("Async Interrupt");
+ UINT32 index = interruptsResource->Allocate("Async Interrupt", this);
if (index == ~0ul)
{
- CloneError(interruptsResource);
return;
}
m_interruptIndex = index;
@@ -70,10 +69,9 @@
void DigitalSource::RequestInterrupts()
{
if (StatusIsFatal()) return;
- UINT32 index = interruptsResource->Allocate("Sync Interrupt");
+ UINT32 index = interruptsResource->Allocate("Sync Interrupt", this);
if (index == ~0ul)
{
- CloneError(interruptsResource);
return;
}
m_interruptIndex = index;
diff --git a/aos/externals/WPILib/WPILib/DoubleSolenoid.cpp b/aos/externals/WPILib/WPILib/DoubleSolenoid.cpp
index d05c7ff..4b3e473 100644
--- a/aos/externals/WPILib/WPILib/DoubleSolenoid.cpp
+++ b/aos/externals/WPILib/WPILib/DoubleSolenoid.cpp
@@ -37,15 +37,15 @@
Resource::CreateResourceObject(&m_allocated, tSolenoid::kNumDO7_0Elements * kSolenoidChannels);
snprintf(buf, 64, "Solenoid %d (Module %d)", m_forwardChannel, m_moduleNumber);
- if (m_allocated->Allocate((m_moduleNumber - 1) * kSolenoidChannels + m_forwardChannel - 1, buf) == ~0ul)
+ if (m_allocated->Allocate((m_moduleNumber - 1) * kSolenoidChannels +
+ m_forwardChannel - 1, buf, this) == ~0ul)
{
- CloneError(m_allocated);
return;
}
snprintf(buf, 64, "Solenoid %d (Module %d)", m_reverseChannel, m_moduleNumber);
- if (m_allocated->Allocate((m_moduleNumber - 1) * kSolenoidChannels + m_reverseChannel - 1, buf) == ~0ul)
+ if (m_allocated->Allocate((m_moduleNumber - 1) * kSolenoidChannels +
+ m_reverseChannel - 1, buf, this) == ~0ul)
{
- CloneError(m_allocated);
return;
}
m_forwardMask = 1 << (m_forwardChannel - 1);
@@ -90,11 +90,10 @@
*/
DoubleSolenoid::~DoubleSolenoid()
{
- if (CheckSolenoidModule(m_moduleNumber))
- {
- m_allocated->Free((m_moduleNumber - 1) * kSolenoidChannels + m_forwardChannel - 1);
- m_allocated->Free((m_moduleNumber - 1) * kSolenoidChannels + m_reverseChannel - 1);
- }
+ m_allocated->Free((m_moduleNumber - 1) * kSolenoidChannels +
+ m_forwardChannel - 1, this);
+ m_allocated->Free((m_moduleNumber - 1) * kSolenoidChannels +
+ m_reverseChannel - 1, this);
}
/**
diff --git a/aos/externals/WPILib/WPILib/DoubleSolenoid.h b/aos/externals/WPILib/WPILib/DoubleSolenoid.h
index f9920a1..a4cd03a 100644
--- a/aos/externals/WPILib/WPILib/DoubleSolenoid.h
+++ b/aos/externals/WPILib/WPILib/DoubleSolenoid.h
@@ -38,7 +38,7 @@
ITable * GetTable();
private:
- virtual void InitSolenoid();
+ void InitSolenoid();
UINT32 m_forwardChannel; ///< The forward channel on the module to control.
UINT32 m_reverseChannel; ///< The reverse channel on the module to control.
diff --git a/aos/externals/WPILib/WPILib/DriverStation.cpp b/aos/externals/WPILib/WPILib/DriverStation.cpp
index ffe0e66..e71ab90 100644
--- a/aos/externals/WPILib/WPILib/DriverStation.cpp
+++ b/aos/externals/WPILib/WPILib/DriverStation.cpp
@@ -159,7 +159,8 @@
void DriverStation::GetData()
{
static bool lastEnabled = false;
- getCommonControlData(m_controlData, WAIT_FOREVER);
+ // Have to const_cast away the volatile.
+ getCommonControlData(const_cast<FRCCommonControlData *>(m_controlData), WAIT_FOREVER);
if (!lastEnabled && IsEnabled())
{
// If starting teleop, assume that autonomous just took up 15 seconds
@@ -364,6 +365,7 @@
if (channel < 1 || channel > 8)
wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel must be between 1 and 8");
+ // TODO: fix the lack of thread safety here
static UINT8 reported_mask = 0;
if (!(reported_mask & (1 >> channel)))
{
@@ -388,32 +390,79 @@
return ((m_digitalOut >> (channel-1)) & 0x1) ? true : false;;
}
+/**
+ * @return Whether or not the robot is currently enabled by the field controls.
+ */
bool DriverStation::IsEnabled()
{
return m_controlData->enabled;
}
+/**
+ * @return Whether or not the robot is currently disabled by the field controls.
+ */
bool DriverStation::IsDisabled()
{
return !m_controlData->enabled;
}
+/**
+ * Determines if the robot is currently in autonomous mode. Does not check
+ * whether the robot is enabled.
+ * @return Whether or not the robot is currently in autonomous mode.
+ */
bool DriverStation::IsAutonomous()
{
return m_controlData->autonomous;
}
+/**
+ * Determines if the robot is currently in teleoperated mode. Does not check
+ * whether the robot is enabled.
+ * @return Whether or not the robot is currently in teleoperated mode.
+ */
bool DriverStation::IsOperatorControl()
{
return !(m_controlData->autonomous || m_controlData->test);
}
+/**
+ * Determines if the robot is currently in test mode. Does not check
+ * whether the robot is enabled.
+ * @return Whether or not the robot is currently in test mode.
+ */
bool DriverStation::IsTest()
{
return m_controlData->test;
}
/**
+ * @return What state the robot is currently in.
+ */
+DriverStation::FMSState DriverStation::GetCurrentState() {
+ UINT8 control_at_start = m_controlData->control;
+ if (IsDisabled()) {
+ return FMSState::kDisabled;
+ // Or else it must be enabled (for all of the other ones).
+ } else if (IsAutonomous()) {
+ return FMSState::kAutonomous;
+ } else if (IsTest()) {
+ return FMSState::kTestMode;
+ } else if (IsOperatorControl()) {
+ return FMSState::kTeleop;
+ } else {
+ // If we didn't get another packet in the mean time.
+ if (m_controlData->control == control_at_start) {
+ wpi_setWPIErrorWithContext(IncompatibleState, "Unknown FMS State");
+ return FMSState::kDisabled;
+ } else {
+ // The data changed out from under us. Try again.
+ return GetCurrentState();
+ }
+ }
+}
+
+/**
* Has a new control packet from the driver station arrived since the last time this function was called?
* Warning: If you call this function from more than one place at the same time,
* you will not get the get the intended behavior
diff --git a/aos/externals/WPILib/WPILib/DriverStation.h b/aos/externals/WPILib/WPILib/DriverStation.h
index acd9b16..fffa675 100644
--- a/aos/externals/WPILib/WPILib/DriverStation.h
+++ b/aos/externals/WPILib/WPILib/DriverStation.h
@@ -23,7 +23,15 @@
public:
enum Alliance {kRed, kBlue, kInvalid};
- virtual ~DriverStation();
+ // Represents all of the states that FMS thinks of a robot as being in.
+ // NOTE: All of the ones except kDisabled mean that the robot is enabled too.
+ enum FMSState {
+ kDisabled,
+ kAutonomous,
+ kTeleop,
+ kTestMode,
+ };
+
static DriverStation *GetInstance();
static const UINT32 kBatteryModuleNumber = 1;
@@ -41,9 +49,10 @@
bool IsEnabled();
bool IsDisabled();
- bool IsAutonomous();
+ bool IsAutonomous();
bool IsOperatorControl();
- bool IsTest();
+ bool IsTest();
+ FMSState GetCurrentState();
bool IsNewControlData();
bool IsFMSAttached();
@@ -96,6 +105,7 @@
protected:
DriverStation();
+ virtual ~DriverStation();
void GetData();
void SetData();
@@ -109,7 +119,10 @@
void Run();
- struct FRCCommonControlData *m_controlData;
+ // Volatile because it gets modified by GetData() in a separate task. Be
+ // careful using values out of here (2-byte accesses are safe as long as
+ // they're aligned, which all of the ones in here should be).
+ volatile struct FRCCommonControlData *m_controlData;
UINT8 m_digitalOut;
AnalogChannel *m_batteryChannel;
SEM_ID m_statusDataSemaphore;
diff --git a/aos/externals/WPILib/WPILib/DriverStationLCD.h b/aos/externals/WPILib/WPILib/DriverStationLCD.h
index 3ea90a5..1a3731f 100644
--- a/aos/externals/WPILib/WPILib/DriverStationLCD.h
+++ b/aos/externals/WPILib/WPILib/DriverStationLCD.h
@@ -25,7 +25,6 @@
static const INT32 kNumLines = 6;
enum Line {kMain_Line6=0, kUser_Line1=0, kUser_Line2=1, kUser_Line3=2, kUser_Line4=3, kUser_Line5=4, kUser_Line6=5};
- virtual ~DriverStationLCD();
static DriverStationLCD *GetInstance();
void UpdateLCD();
@@ -38,6 +37,7 @@
protected:
DriverStationLCD();
+ virtual ~DriverStationLCD();
private:
static void InitTask(DriverStationLCD *ds);
diff --git a/aos/externals/WPILib/WPILib/Encoder.cpp b/aos/externals/WPILib/WPILib/Encoder.cpp
index cdf1dba..cfb96c9 100644
--- a/aos/externals/WPILib/WPILib/Encoder.cpp
+++ b/aos/externals/WPILib/WPILib/Encoder.cpp
@@ -27,14 +27,11 @@
{
m_encodingType = encodingType;
tRioStatusCode localStatus = NiFpga_Status_Success;
- switch (encodingType)
- {
- case k4X:
+ if (encodingType == k4X) {
Resource::CreateResourceObject(&quadEncoders, tEncoder::kNumSystems);
- UINT32 index = quadEncoders->Allocate("4X Encoder");
+ UINT32 index = quadEncoders->Allocate("4X Encoder", this);
if (index == ~0ul)
{
- CloneError(quadEncoders);
return;
}
if (m_aSource->StatusIsFatal())
@@ -59,12 +56,9 @@
m_encoder->writeConfig_Reverse(reverseDirection, &localStatus);
m_encoder->writeTimerConfig_AverageSize(4, &localStatus);
m_counter = NULL;
- break;
- case k1X:
- case k2X:
+ } else {
m_counter = new Counter(m_encodingType, m_aSource, m_bSource, reverseDirection);
m_index = m_counter->GetIndex();
- break;
}
m_distancePerPulse = 1.0;
m_pidSource = kDistance;
@@ -195,7 +189,7 @@
}
else
{
- quadEncoders->Free(m_index);
+ quadEncoders->Free(m_index, this);
delete m_encoder;
}
}
diff --git a/aos/externals/WPILib/WPILib/Error.cpp b/aos/externals/WPILib/WPILib/Error.cpp
index 30f0cbc..9e83de7 100644
--- a/aos/externals/WPILib/WPILib/Error.cpp
+++ b/aos/externals/WPILib/WPILib/Error.cpp
@@ -25,8 +25,32 @@
Error::~Error()
{}
-void Error::Clone(Error &error)
+/**
+ * Clones another error into this if this is currently clear. If not, does
+ * nothing.
+ * This is necessary because just using "if (!IsClear()) Clone(error)" has a
+ * race condition which this method does not.
+ * Cloning 2 errors into each other at the same time can lead to deadlocks!
+ */
+void Error::CloneIfClear(const Error &error) {
+ Synchronized sync(m_semaphore);
+ if (IsClear()) {
+ DoClone(error);
+ }
+}
+
+/**
+ * Clones another error into this object.
+ * Cloning 2 errors into each other at the same time can lead to deadlocks!
+ */
+void Error::Clone(const Error &error) {
+ Synchronized sync(m_semaphore);
+ DoClone(error);
+}
+
+void Error::DoClone(const Error &error)
{
+ Synchronized sync(error.m_semaphore);
m_code = error.m_code;
m_message = error.m_message;
m_filename = error.m_filename;
@@ -36,17 +60,19 @@
m_timestamp = error.m_timestamp;
}
+bool Error::IsClear() const { return GetCode() == 0; }
+
Error::Code Error::GetCode() const
{ return m_code; }
-const char * Error::GetMessage() const
-{ return m_message.c_str(); }
+std::string Error::GetMessage() const
+{ return m_message; }
-const char * Error::GetFilename() const
-{ return m_filename.c_str(); }
+std::string Error::GetFilename() const
+{ return m_filename; }
-const char * Error::GetFunction() const
-{ return m_function.c_str(); }
+std::string Error::GetFunction() const
+{ return m_function; }
UINT32 Error::GetLineNumber() const
{ return m_lineNumber; }
@@ -57,8 +83,10 @@
double Error::GetTime() const
{ return m_timestamp; }
-void Error::Set(Code code, const char* contextMessage, const char* filename, const char* function, UINT32 lineNumber, const ErrorBase* originatingObject)
-{
+void Error::Set(Code code, const char* contextMessage, const char* filename,
+ const char* function, UINT32 lineNumber,
+ const ErrorBase* originatingObject) {
+ Synchronized sync(m_semaphore);
m_code = code;
m_message = contextMessage;
m_filename = filename;
@@ -69,39 +97,40 @@
Report();
- if (m_suspendOnErrorEnabled) taskSuspend(0);
+ if (m_suspendOnErrorEnabled) taskSuspend(0 /*self*/);
}
-void Error::Report()
+void Error::Report() const
{
// Error string buffers
- char *error = new char[256];
- char *error_with_code = new char[256];
+ char error[256];
+ char error_with_code[256];
// Build error strings
- if (m_code != -1)
+ if (m_code != -1 && m_code != 1)
{
- snprintf(error, 256, "%s: status = %d (0x%08X) %s ...in %s() in %s at line %d\n",
- m_code < 0 ? "ERROR" : "WARNING", (INT32)m_code, (UINT32)m_code, m_message.c_str(),
- m_function.c_str(), m_filename.c_str(), m_lineNumber);
- sprintf(error_with_code,"<Code>%d %s", (INT32)m_code, error);
+ snprintf(error, sizeof(error),
+ "%s: status = %d (0x%08X) %s ...in %s() in %s at line %d\n",
+ m_code < 0 ? "ERROR" : "WARNING", (INT32)m_code,
+ (UINT32)m_code, m_message.c_str(),
+ m_function.c_str(), m_filename.c_str(), m_lineNumber);
+ snprintf(error_with_code, sizeof(error_with_code),
+ "<Code>%d %s", (INT32)m_code, error);
} else {
- snprintf(error, 256, "ERROR: %s ...in %s() in %s at line %d\n", m_message.c_str(),
- m_function.c_str(), m_filename.c_str(), m_lineNumber);
- strcpy(error_with_code, error);
+ snprintf(error, sizeof(error),
+ "%s: %s ...in %s() in %s at line %d\n",
+ m_code < 0 ? "ERROR" : "WARNING", m_message.c_str(),
+ m_function.c_str(), m_filename.c_str(), m_lineNumber);
+ strncpy(error_with_code, error, sizeof(error_with_code));
}
// TODO: Add logging to disk
// Send to the DriverStation
setErrorData(error_with_code, strlen(error_with_code), 100);
- delete [] error_with_code;
-
// Print to console
printf("\n\n>>>>%s", error);
- delete [] error;
-
if (m_stackTraceEnabled)
{
printf("-----------<Stack Trace>----------------\n");
@@ -111,6 +140,7 @@
void Error::Clear()
{
+ Synchronized sync(m_semaphore);
m_code = 0;
m_message = "";
m_filename = "";
diff --git a/aos/externals/WPILib/WPILib/Error.h b/aos/externals/WPILib/WPILib/Error.h
index a80fe06..9636262 100644
--- a/aos/externals/WPILib/WPILib/Error.h
+++ b/aos/externals/WPILib/WPILib/Error.h
@@ -10,37 +10,55 @@
#include "Base.h"
#include "ChipObject/NiRio.h"
#include <string>
-#include <vxWorks.h>
+#include "Synchronized.h"
// Forward declarations
class ErrorBase;
/**
- * Error object represents a library error.
+ * Represents an error or warning.
+ *
+ * All methods that can change instance data are protected by a lock so
+ * that it is safe to call any methods from multiple tasks at the same time.
*/
class Error
{
public:
+ // -1 is other error, 1 is other warning.
typedef tRioStatusCode Code;
Error();
~Error();
- void Clone(Error &error);
- Code GetCode() const;
- const char *GetMessage() const;
- const char *GetFilename() const;
- const char *GetFunction() const;
- UINT32 GetLineNumber() const;
- const ErrorBase* GetOriginatingObject() const;
- double GetTime() const;
+
+ void CloneIfClear(const Error &error);
+ void Clone(const Error &error);
void Clear();
void Set(Code code, const char* contextMessage, const char* filename,
const char *function, UINT32 lineNumber, const ErrorBase* originatingObject);
+
+ bool IsClear() const;
+ Code GetCode() const;
+ // Have to return by value to avoid race conditions using the result for all
+ // of these methods.
+ std::string GetMessage() const;
+ std::string GetFilename() const;
+ std::string GetFunction() const;
+ UINT32 GetLineNumber() const;
+ const ErrorBase* GetOriginatingObject() const;
+ double GetTime() const;
+
+ // Enable or disable printing out a stack trace on the console whenever there
+ // is an error.
static void EnableStackTrace(bool enable) { m_stackTraceEnabled=enable; }
+ // Enable or disable having any task that gets an error suspend itself.
static void EnableSuspendOnError(bool enable) { m_suspendOnErrorEnabled=enable; }
private:
- void Report();
+ // Deals with notifying other code of this error.
+ void Report() const;
+ // Actually implements cloning.
+ // Does not lock m_semaphore, so callers must.
+ void DoClone(const Error &error);
Code m_code;
std::string m_message;
@@ -49,6 +67,10 @@
UINT32 m_lineNumber;
const ErrorBase* m_originatingObject;
double m_timestamp;
+ // Used for protecting all modifications to instance data.
+ // This means that all non-const methods should lock this for (at least most)
+ // of their implementations!
+ ReentrantSemaphore m_semaphore;
static bool m_stackTraceEnabled;
static bool m_suspendOnErrorEnabled;
diff --git a/aos/externals/WPILib/WPILib/ErrorBase.cpp b/aos/externals/WPILib/WPILib/ErrorBase.cpp
index 2722963..5f766c7 100644
--- a/aos/externals/WPILib/WPILib/ErrorBase.cpp
+++ b/aos/externals/WPILib/WPILib/ErrorBase.cpp
@@ -14,8 +14,8 @@
#include <symLib.h>
#include <sysSymTbl.h>
-SEM_ID ErrorBase::_globalErrorMutex = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE);
Error ErrorBase::_globalError;
+
/**
* @brief Initialize the instance status to 0 for now.
*/
@@ -26,15 +26,10 @@
{}
/**
- * @brief Retrieve the current error.
- * Get the current error information associated with this sensor.
+ * @brief Retrieve the error associated this object.
+ * Get the error information associated with this sensor.
*/
-Error& ErrorBase::GetError()
-{
- return m_error;
-}
-
-const Error& ErrorBase::GetError() const
+Error& ErrorBase::GetError() const
{
return m_error;
}
@@ -48,7 +43,10 @@
}
/**
- * @brief Set error information associated with a C library call that set an error to the "errno" global variable.
+ * @brief Set error information associated with a C library call that set an
+ * error to the "errno" "global variable" (it's really a macro that calls a
+ * function under VxWorks so that it's thread safe).
+ * Will still set an error even if errno is 0.
*
* @param contextMessage A custom message from the code that set the error.
* @param filename Filename of the error source
@@ -62,7 +60,7 @@
int errNo = errnoGet();
if (errNo == 0)
{
- sprintf(err, "OK: %s", contextMessage);
+ snprintf(err, sizeof(err), "OK: %s", contextMessage);
}
else
{
@@ -71,24 +69,21 @@
SYM_TYPE ptype;
symFindByValue(statSymTbl, errNo, statName, &pval, &ptype);
if (pval != errNo)
- snprintf(err, 256, "Unknown errno 0x%08X: %s", errNo, contextMessage);
+ snprintf(err, sizeof(err), "Unknown errno 0x%08X: %s", errNo, contextMessage);
else
- snprintf(err, 256, "%s (0x%08X): %s", statName, errNo, contextMessage);
+ snprintf(err, sizeof(err), "%s (0x%08X): %s", statName, errNo, contextMessage);
delete [] statName;
}
// Set the current error information for this object.
m_error.Set(-1, err, filename, function, lineNumber, this);
- // Update the global error if there is not one already set.
- Synchronized mutex(_globalErrorMutex);
- if (_globalError.GetCode() == 0) {
- _globalError.Clone(m_error);
- }
+ _globalError.CloneIfClear(m_error);
}
/**
* @brief Set the current error information associated from the nivision Imaq API.
+ * Does nothing of success is > 0.
*
* @param success The return from the function
* @param contextMessage A custom message from the code that set the error.
@@ -101,21 +96,18 @@
// If there was an error
if (success <= 0) {
char err[256];
- sprintf(err, "%s: %s", contextMessage, imaqGetErrorText(imaqGetLastError()));
+ snprintf(err, sizeof(err), "%s: %s", contextMessage, imaqGetErrorText(imaqGetLastError()));
// Set the current error information for this object.
m_error.Set(imaqGetLastError(), err, filename, function, lineNumber, this);
- // Update the global error if there is not one already set.
- Synchronized mutex(_globalErrorMutex);
- if (_globalError.GetCode() == 0) {
- _globalError.Clone(m_error);
- }
+ _globalError.CloneIfClear(m_error);
}
}
/**
- * @brief Set the current error information associated with this sensor.
+ * @brief Set the current error information associated with this object.
+ * Does nothing if code is 0.
*
* @param code The error code
* @param contextMessage A custom message from the code that set the error.
@@ -131,16 +123,12 @@
// Set the current error information for this object.
m_error.Set(code, contextMessage, filename, function, lineNumber, this);
- // Update the global error if there is not one already set.
- Synchronized mutex(_globalErrorMutex);
- if (_globalError.GetCode() == 0) {
- _globalError.Clone(m_error);
- }
+ _globalError.CloneIfClear(m_error);
}
}
/**
- * @brief Set the current error information associated with this sensor.
+ * @brief Set the current error information associated with this object.
*
* @param errorMessage The error message from WPIErrors.h
* @param contextMessage A custom message from the code that set the error.
@@ -152,19 +140,15 @@
const char* filename, const char* function, UINT32 lineNumber) const
{
char err[256];
- sprintf(err, "%s: %s", errorMessage, contextMessage);
+ snprintf(err, sizeof(err), "%s: %s", errorMessage, contextMessage);
// Set the current error information for this object.
m_error.Set(-1, err, filename, function, lineNumber, this);
- // Update the global error if there is not one already set.
- Synchronized mutex(_globalErrorMutex);
- if (_globalError.GetCode() == 0) {
- _globalError.Clone(m_error);
- }
+ _globalError.CloneIfClear(m_error);
}
-void ErrorBase::CloneError(ErrorBase *rhs) const
+void ErrorBase::CloneError(const ErrorBase *rhs) const
{
m_error.Clone(rhs->GetError());
}
@@ -179,37 +163,49 @@
return m_error.GetCode() < 0;
}
+/**
+ * @brief Set the current global error information.
+ * Does nothing if code is 0.
+ * TODO: think about getting rid of this because nothing uses it any more
+ *
+ * @param code The error code
+ * @param contextMessage A custom message from the code that set the error.
+ * @param filename Filename of the error source
+ * @param function Function of the error source
+ * @param lineNumber Line number of the error source
+ */
void ErrorBase::SetGlobalError(Error::Code code, const char *contextMessage,
const char* filename, const char* function, UINT32 lineNumber)
{
- // If there was an error
- if (code != 0) {
- Synchronized mutex(_globalErrorMutex);
-
- // Set the current error information for this object.
- _globalError.Set(code, contextMessage, filename, function, lineNumber, NULL);
- }
+ if (code != 0) {
+ // Set the current error information for this object.
+ _globalError.Set(code, contextMessage, filename, function, lineNumber, NULL);
+ }
}
+/**
+ * @brief Set the current global error information.
+ *
+ * @param errorMessage The error message from WPIErrors.h
+ * @param contextMessage A custom message from the code that set the error.
+ * @param filename Filename of the error source
+ * @param function Function of the error source
+ * @param lineNumber Line number of the error source
+ */
void ErrorBase::SetGlobalWPIError(const char *errorMessage, const char *contextMessage,
const char* filename, const char* function, UINT32 lineNumber)
{
char err[256];
- sprintf(err, "%s: %s", errorMessage, contextMessage);
+ snprintf(err, sizeof(err), "%s: %s", errorMessage, contextMessage);
- Synchronized mutex(_globalErrorMutex);
- if (_globalError.GetCode() != 0) {
- _globalError.Clear();
- }
_globalError.Set(-1, err, filename, function, lineNumber, NULL);
}
/**
- * Retrieve the current global error.
+ * Retrieve the global error.
*/
-Error& ErrorBase::GetGlobalError()
+const Error& ErrorBase::GetGlobalError()
{
- Synchronized mutex(_globalErrorMutex);
return _globalError;
}
diff --git a/aos/externals/WPILib/WPILib/ErrorBase.h b/aos/externals/WPILib/WPILib/ErrorBase.h
index f967562..9d032cb 100644
--- a/aos/externals/WPILib/WPILib/ErrorBase.h
+++ b/aos/externals/WPILib/WPILib/ErrorBase.h
@@ -10,59 +10,86 @@
#include "Base.h"
#include "ChipObject/NiRio.h"
#include "Error.h"
-#include <semLib.h>
-#include <vxWorks.h>
-#define wpi_setErrnoErrorWithContext(context) (this->SetErrnoError((context), __FILE__, __FUNCTION__, __LINE__))
-#define wpi_setErrnoError() (wpi_setErrnoErrorWithContext(""))
-#define wpi_setImaqErrorWithContext(code, context) (this->SetImaqError((code), (context), __FILE__, __FUNCTION__, __LINE__))
-#define wpi_setErrorWithContext(code, context) (this->SetError((code), (context), __FILE__, __FUNCTION__, __LINE__))
+// Helper macros to fill in the context information for you. See the
+// documentation for the methods that they call for details.
+#define wpi_setErrnoErrorWithContext(context) \
+ (this->SetErrnoError((context), __FILE__, __FUNCTION__, __LINE__))
+#define wpi_setErrnoError() \
+ (wpi_setErrnoErrorWithContext(""))
+#define wpi_setImaqErrorWithContext(code, context) \
+ (this->SetImaqError((code), (context), __FILE__, __FUNCTION__, __LINE__))
+#define wpi_setErrorWithContext(code, context) \
+ (this->SetError((code), (context), __FILE__, __FUNCTION__, __LINE__))
#define wpi_setError(code) (wpi_setErrorWithContext(code, ""))
-#define wpi_setStaticErrorWithContext(object, code, context) (object->SetError((code), (context), __FILE__, __FUNCTION__, __LINE__))
-#define wpi_setStaticError(object, code) (wpi_setStaticErrorWithContext(object, code, ""))
-#define wpi_setGlobalErrorWithContext(code, context) (ErrorBase::SetGlobalError((code), (context), __FILE__, __FUNCTION__, __LINE__))
+#define wpi_setStaticErrorWithContext(object, code, context) \
+ (object->SetError((code), (context), __FILE__, __FUNCTION__, __LINE__))
+#define wpi_setStaticError(object, code) \
+ (wpi_setStaticErrorWithContext(object, code, ""))
+#define wpi_setGlobalErrorWithContext(code, context) \
+ (ErrorBase::SetGlobalError((code), (context), \
+ __FILE__, __FUNCTION__, __LINE__))
#define wpi_setGlobalError(code) (wpi_setGlobalErrorWithContext(code, ""))
-#define wpi_setWPIErrorWithContext(error, context) (this->SetWPIError((wpi_error_s_##error), (context), __FILE__, __FUNCTION__, __LINE__))
+#define wpi_setWPIErrorWithContext(error, context) \
+ (this->SetWPIError((wpi_error_s_##error), (context), \
+ __FILE__, __FUNCTION__, __LINE__))
#define wpi_setWPIError(error) (wpi_setWPIErrorWithContext(error, ""))
-#define wpi_setStaticWPIErrorWithContext(object, error, context) (object->SetWPIError((wpi_error_s_##error), (context), __FILE__, __FUNCTION__, __LINE__))
-#define wpi_setStaticWPIError(object, error) (wpi_setStaticWPIErrorWithContext(object, error, ""))
-#define wpi_setGlobalWPIErrorWithContext(error, context) (ErrorBase::SetGlobalWPIError((wpi_error_s_##error), (context), __FILE__, __FUNCTION__, __LINE__))
-#define wpi_setGlobalWPIError(error) (wpi_setGlobalWPIErrorWithContext(error, ""))
+#define wpi_setStaticWPIErrorWithContext(object, error, context) \
+ (object->SetWPIError((wpi_error_s_##error), (context), \
+ __FILE__, __FUNCTION__, __LINE__))
+#define wpi_setStaticWPIError(object, error) \
+ (wpi_setStaticWPIErrorWithContext(object, error, ""))
+#define wpi_setGlobalWPIErrorWithContext(error, context) \
+ (ErrorBase::SetGlobalWPIError((wpi_error_s_##error), (context), \
+ __FILE__, __FUNCTION__, __LINE__))
+#define wpi_setGlobalWPIError(error) \
+ (wpi_setGlobalWPIErrorWithContext(error, ""))
/**
* Base class for most objects.
* ErrorBase is the base class for most objects since it holds the generated error
* for that object. In addition, there is a single instance of a global error object
+ *
+ * BE AWARE: This does include a mutable instance variable! This means that even
+ * if you make an object const it's not really. However, all modification to
+ * that instance variable is protected by a semaphore, so it does not create any
+ * thread safety issues.
+ *
+ * All of the Set*Error methods will update the global error if there is nothing
+ * there already.
*/
class ErrorBase
{
-//TODO: Consider initializing instance variables and cleanup in destructor
public:
+ ErrorBase();
virtual ~ErrorBase();
- virtual Error& GetError();
- virtual const Error& GetError() const;
- virtual void SetErrnoError(const char *contextMessage,
+
+ Error& GetError() const;
+ void SetErrnoError(const char *contextMessage,
const char* filename, const char* function, UINT32 lineNumber) const;
- virtual void SetImaqError(int success, const char *contextMessage,
+ void SetImaqError(int success, const char *contextMessage,
const char* filename, const char* function, UINT32 lineNumber) const;
- virtual void SetError(Error::Code code, const char *contextMessage,
+ void SetError(Error::Code code, const char *contextMessage,
const char* filename, const char* function, UINT32 lineNumber) const;
- virtual void SetWPIError(const char *errorMessage, const char *contextMessage,
+ void SetWPIError(const char *errorMessage, const char *contextMessage,
const char* filename, const char* function, UINT32 lineNumber) const;
- virtual void CloneError(ErrorBase *rhs) const;
- virtual void ClearError() const;
- virtual bool StatusIsFatal() const;
+ void CloneError(const ErrorBase *rhs) const;
+ void ClearError() const;
+ bool StatusIsFatal() const;
static void SetGlobalError(Error::Code code, const char *contextMessage,
const char* filename, const char* function, UINT32 lineNumber);
static void SetGlobalWPIError(const char *errorMessage, const char *contextMessage,
const char* filename, const char* function, UINT32 lineNumber);
- static Error& GetGlobalError();
+ static const Error& GetGlobalError();
+
protected:
+ // This mutable is safe because Error guarantees that all modifications are
+ // protected with an internal lock.
mutable Error m_error;
- // TODO: Replace globalError with a global list of all errors.
- static SEM_ID _globalErrorMutex;
+ // TODO: Replace globalError with a global list of all errors, but make sure
+ // that it's thread safe.
static Error _globalError;
- ErrorBase();
+
private:
DISALLOW_COPY_AND_ASSIGN(ErrorBase);
};
diff --git a/aos/externals/WPILib/WPILib/Global.cpp b/aos/externals/WPILib/WPILib/Global.cpp
new file mode 100644
index 0000000..0d48129
--- /dev/null
+++ b/aos/externals/WPILib/WPILib/Global.cpp
@@ -0,0 +1,155 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2008. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
+/*----------------------------------------------------------------------------*/
+
+#include "Global.h"
+#include "Utility.h"
+
+Global *Global::instance;
+ReentrantSemaphore Global::instance_lock;
+
+Global *Global::GetInstance() {
+ Synchronized sync(instance_lock);
+ if (instance == NULL) {
+ instance = new Global();
+ }
+ return instance;
+}
+
+Global::Global() {
+ tRioStatusCode status = NiFpga_Status_Success;
+ global_.reset(tGlobal::create(&status));
+ wpi_setError(status);
+
+ AddToSingletonList();
+}
+
+Global::~Global() {
+ Synchronized sync(instance_lock);
+ instance = NULL;
+}
+
+/**
+ * Return the FPGA Version number.
+ * For now, expect this to be competition year.
+ * @return FPGA Version number.
+ */
+UINT16 Global::GetFPGAVersion()
+{
+ tRioStatusCode status = NiFpga_Status_Success;
+ UINT16 version = global_->readVersion(&status);
+ wpi_setError(status);
+ return version;
+}
+
+/**
+ * Return the FPGA Revision number.
+ * The format of the revision is 3 numbers.
+ * The 12 most significant bits are the Major Revision.
+ * the next 8 bits are the Minor Revision.
+ * The 12 least significant bits are the Build Number.
+ * @return FPGA Revision number.
+ */
+UINT32 Global::GetFPGARevision()
+{
+ tRioStatusCode status = NiFpga_Status_Success;
+ UINT32 revision = global_->readRevision(&status);
+ wpi_setError(status);
+ return revision;
+}
+
+/**
+ * Read the microsecond-resolution timer on the FPGA.
+ *
+ * @return The current time in microseconds according to the FPGA (since FPGA reset).
+ */
+UINT32 Global::GetFPGATime()
+{
+ tRioStatusCode status = NiFpga_Status_Success;
+ UINT32 time = global_->readLocalTime(&status);
+ wpi_setError(status);
+ return time;
+}
+
+// RT hardware access functions exported from ni_emb.out
+extern "C"
+{
+ INT32 UserSwitchInput(INT32 nSwitch);
+ INT32 LedInput(INT32 led);
+ INT32 LedOutput(INT32 led, INT32 value);
+}
+
+/**
+ * Read the value of the USER1 DIP switch on the cRIO.
+ */
+INT32 Global::GetRIOUserSwitch()
+{
+ INT32 switchValue = UserSwitchInput(0);
+ wpi_assert(switchValue >= 0);
+ return switchValue > 0;
+}
+
+/**
+ * Set the state of the USER1 status LED on the cRIO.
+ */
+void Global::SetRIOUserLED(UINT32 state)
+{
+ LedOutput(0, state > 0);
+}
+
+/**
+ * Get the current state of the USER1 status LED on the cRIO.
+ * @return The curent state of the USER1 LED.
+ */
+INT32 Global::GetRIOUserLED()
+{
+ return LedInput(0);
+}
+
+/**
+ * Toggle the state of the USER1 status LED on the cRIO.
+ * @return The new state of the USER1 LED.
+ */
+INT32 Global::ToggleRIOUserLED()
+{
+ Synchronized sync(led_toggle_lock_);
+ INT32 ledState = !GetRIOUserLED();
+ SetRIOUserLED(ledState);
+ return ledState;
+}
+
+/**
+ * Set the state of the FPGA status LED on the cRIO.
+ */
+void Global::SetRIO_FPGA_LED(UINT32 state)
+{
+ tRioStatusCode status = NiFpga_Status_Success;
+ global_->writeFPGA_LED(state, &status);
+ wpi_setError(status);
+}
+
+/**
+ * Get the current state of the FPGA status LED on the cRIO.
+ * @return The curent state of the FPGA LED.
+ */
+INT32 Global::GetRIO_FPGA_LED()
+{
+ tRioStatusCode status = NiFpga_Status_Success;
+ bool ledValue = global_->readFPGA_LED(&status);
+ wpi_setError(status);
+ return ledValue;
+}
+
+/**
+ * Toggle the state of the FPGA status LED on the cRIO.
+ * @return The new state of the FPGA LED.
+ */
+INT32 Global::ToggleRIO_FPGA_LED()
+{
+ Synchronized sync(led_toggle_lock_);
+ INT32 ledState = !GetRIO_FPGA_LED();
+ SetRIO_FPGA_LED(ledState);
+ return ledState;
+}
diff --git a/aos/externals/WPILib/WPILib/Global.h b/aos/externals/WPILib/WPILib/Global.h
new file mode 100644
index 0000000..4857e09
--- /dev/null
+++ b/aos/externals/WPILib/WPILib/Global.h
@@ -0,0 +1,42 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2008. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
+/*----------------------------------------------------------------------------*/
+
+#include <memory>
+
+#include "SensorBase.h"
+#include "Synchronized.h"
+#include "ChipObject.h"
+
+#ifndef WPILIB_GLOBAL_H_
+#define WPILIB_GLOBAL_H_
+
+class Global : public SensorBase {
+ public:
+ static Global *GetInstance();
+
+ UINT16 GetFPGAVersion();
+ UINT32 GetFPGARevision();
+ UINT32 GetFPGATime();
+ INT32 GetRIOUserSwitch();
+ void SetRIOUserLED(UINT32 state);
+ INT32 GetRIOUserLED();
+ INT32 ToggleRIOUserLED();
+ void SetRIO_FPGA_LED(UINT32 state);
+ INT32 GetRIO_FPGA_LED();
+ INT32 ToggleRIO_FPGA_LED();
+
+ private:
+ Global();
+ ~Global();
+
+ static Global *instance;
+ static ReentrantSemaphore instance_lock;
+
+ ::std::auto_ptr<tGlobal> global_;
+ ReentrantSemaphore led_toggle_lock_;
+};
+
+#endif // WPILIB_GLOBAL_H_
diff --git a/aos/externals/WPILib/WPILib/IterativeRobot.cpp b/aos/externals/WPILib/WPILib/IterativeRobot.cpp
index 96e9b71..579ea2b 100644
--- a/aos/externals/WPILib/WPILib/IterativeRobot.cpp
+++ b/aos/externals/WPILib/WPILib/IterativeRobot.cpp
@@ -61,7 +61,7 @@
/**
* Get the period for the periodic functions.
- * Returns 0.0 if configured to syncronize with DS control data packets.
+ * Returns 0.0 if configured to synchronize with DS control data packets.
* @return Period of the periodic function calls
*/
double IterativeRobot::GetPeriod()
@@ -87,8 +87,7 @@
*
* This specific StartCompetition() implements "main loop" behavior like that of the FRC
* control system in 2008 and earlier, with a primary (slow) loop that is
- * called periodically, and a "fast loop" (a.k.a. "spin loop") that is
- * called as fast as possible with no delay between calls.
+ * called periodically.
*/
void IterativeRobot::StartCompetition()
{
diff --git a/aos/externals/WPILib/WPILib/LiveWindow/LiveWindow.h b/aos/externals/WPILib/WPILib/LiveWindow/LiveWindow.h
index 7237afa..b3e620e 100644
--- a/aos/externals/WPILib/WPILib/LiveWindow/LiveWindow.h
+++ b/aos/externals/WPILib/WPILib/LiveWindow/LiveWindow.h
@@ -24,6 +24,10 @@
this->subsystem = subsystem;
this->name = name;
this->isSensor = isSensor;
+#else
+ (void)subsystem;
+ (void)name;
+ (void)isSensor;
#endif
}
};
diff --git a/aos/externals/WPILib/WPILib/Module.cpp b/aos/externals/WPILib/WPILib/Module.cpp
index 99e26ea..2d01ea5 100644
--- a/aos/externals/WPILib/WPILib/Module.cpp
+++ b/aos/externals/WPILib/WPILib/Module.cpp
@@ -8,6 +8,9 @@
#include "AnalogModule.h"
#include "DigitalModule.h"
//#include "SolenoidModule.h"
+#include "Utility.h"
+
+ReentrantSemaphore Module::m_semaphore;
Module* Module::m_modules[kMaxModules] = {NULL};
@@ -21,6 +24,7 @@
: m_moduleType (type)
, m_moduleNumber (number)
{
+ Synchronized sync(m_semaphore);
m_modules[ToIndex(type, number)] = this;
}
@@ -29,6 +33,7 @@
*/
Module::~Module()
{
+ m_modules[ToIndex(m_moduleType, m_moduleNumber)] = NULL;
}
/**
@@ -39,6 +44,7 @@
*/
Module* Module::GetModule(nLoadOut::tModuleType type, UINT8 number)
{
+ Synchronized sync(m_semaphore);
if (m_modules[ToIndex(type, number)] == NULL)
{
switch(type)
@@ -70,7 +76,20 @@
*/
UINT8 Module::ToIndex(nLoadOut::tModuleType type, UINT8 number)
{
- if (number == 0 || number > kMaxModuleNumber) return 0;
- if (type < nLoadOut::kModuleType_Analog || type > nLoadOut::kModuleType_Solenoid) return 0;
+ if (number == 0 || number > kMaxModuleNumber) {
+ char buf[64];
+ snprintf(buf, sizeof(buf), "Trying to get index for invalid module %d",
+ static_cast<int>(number));
+ wpi_assertWithMessage(false, buf);
+ return 0;
+ }
+ if (type < nLoadOut::kModuleType_Analog ||
+ type > nLoadOut::kModuleType_Solenoid) {
+ char buf[64];
+ snprintf(buf, sizeof(buf), "Trying to get index for invalid module type %d",
+ static_cast<int>(type));
+ wpi_assertWithMessage(false, buf);
+ return 0;
+ }
return (type * kMaxModuleNumber) + (number - 1);
}
diff --git a/aos/externals/WPILib/WPILib/Module.h b/aos/externals/WPILib/WPILib/Module.h
index 1c9f976..45b10ff 100644
--- a/aos/externals/WPILib/WPILib/Module.h
+++ b/aos/externals/WPILib/WPILib/Module.h
@@ -9,6 +9,7 @@
#include "SensorBase.h"
#include "NetworkCommunication/LoadOut.h"
+#include "Synchronized.h"
#define kMaxModules (nLoadOut::kModuleType_Solenoid * kMaxModuleNumber + (kMaxModuleNumber - 1))
@@ -20,7 +21,7 @@
static Module *GetModule(nLoadOut::tModuleType type, UINT8 number);
protected:
- explicit Module(nLoadOut::tModuleType type, UINT8 number);
+ Module(nLoadOut::tModuleType type, UINT8 number);
virtual ~Module();
nLoadOut::tModuleType m_moduleType; ///< The type of module represented.
@@ -29,6 +30,7 @@
private:
static UINT8 ToIndex(nLoadOut::tModuleType type, UINT8 number);
static Module* m_modules[kMaxModules];
+ static ReentrantSemaphore m_semaphore;
};
#endif
diff --git a/aos/externals/WPILib/WPILib/MotorSafety.h b/aos/externals/WPILib/WPILib/MotorSafety.h
index 15481d8..a13ac38 100644
--- a/aos/externals/WPILib/WPILib/MotorSafety.h
+++ b/aos/externals/WPILib/WPILib/MotorSafety.h
@@ -16,6 +16,7 @@
virtual void StopMotor() = 0;
virtual void SetSafetyEnabled(bool enabled) = 0;
virtual bool IsSafetyEnabled() = 0;
+ // May write to the first 64 bytes of desc.
virtual void GetDescription(char *desc) = 0;
};
diff --git a/aos/externals/WPILib/WPILib/PWM.cpp b/aos/externals/WPILib/WPILib/PWM.cpp
index 05bf16d..7ae5370 100644
--- a/aos/externals/WPILib/WPILib/PWM.cpp
+++ b/aos/externals/WPILib/WPILib/PWM.cpp
@@ -42,9 +42,9 @@
}
snprintf(buf, 64, "PWM %d (Module: %d)", channel, moduleNumber);
- if (allocated->Allocate((moduleNumber - 1) * kPwmChannels + channel - 1, buf) == ~0ul)
+ if (allocated->Allocate((moduleNumber - 1) * kPwmChannels + channel - 1,
+ buf, this) == ~0ul)
{
- CloneError(allocated);
return;
}
m_channel = channel;
@@ -92,7 +92,8 @@
if (m_module)
{
m_module->SetPWM(m_channel, kPwmDisabled);
- allocated->Free((m_module->GetNumber() - 1) * kPwmChannels + m_channel - 1);
+ allocated->Free((m_module->GetNumber() - 1) * kPwmChannels + m_channel - 1,
+ this);
}
}
diff --git a/aos/externals/WPILib/WPILib/RWLock.cpp b/aos/externals/WPILib/WPILib/RWLock.cpp
new file mode 100644
index 0000000..9918af0
--- /dev/null
+++ b/aos/externals/WPILib/WPILib/RWLock.cpp
@@ -0,0 +1,202 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2008. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
+/*----------------------------------------------------------------------------*/
+
+#include <taskLib.h>
+#include <intLib.h>
+#include <assert.h>
+
+#include "RWLock.h"
+
+// A wrapper for assert that allows it to be easily turned off just in this
+// file. That configuration is recommended for normal use because it means less
+// code that gets executed with the scheduler locked.
+#if 1
+#define rwlock_assert(expression) assert(expression)
+// A macro to easily assert that some expression (possibly with side effects)
+// is 0.
+#define rwlock_assert_success(expression) do { \
+ int ret = (expression); \
+ assert(ret == 0); \
+} while (false)
+#else
+#define rwlock_assert(expression) ((void)0)
+#define rwlock_assert_success(expression) ((void)(expression))
+#endif
+
+/**
+ * Class that locks the scheduler and then unlocks it in the destructor.
+ */
+class TaskSchedulerLocker {
+ public:
+ TaskSchedulerLocker() {
+ rwlock_assert_success(taskLock());
+ }
+ ~TaskSchedulerLocker() {
+ rwlock_assert_success(taskUnlock());
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TaskSchedulerLocker);
+};
+
+RWLock::Locker::Locker(RWLock *lock, bool write)
+ : lock_(lock), num_(lock_->Lock(write)) {
+}
+
+RWLock::Locker::Locker(const Locker &other)
+ : lock_(other.lock_), num_(lock_->AddLock()) {
+}
+
+RWLock::Locker::~Locker() {
+ lock_->Unlock(num_);
+}
+
+// RWLock is implemented by just locking the scheduler while doing anything
+// because that is the only way under vxworks to do much of anything atomically.
+
+RWLock::RWLock()
+ : number_of_write_locks_(0),
+ number_of_writers_pending_(0),
+ number_of_readers_(0),
+ reader_tasks_(),
+ read_ready_(semBCreate(SEM_Q_PRIORITY, SEM_EMPTY)),
+ write_ready_(semBCreate(SEM_Q_PRIORITY, SEM_EMPTY)) {
+ rwlock_assert(read_ready_ != NULL);
+ rwlock_assert(write_ready_ != NULL);
+}
+
+RWLock::~RWLock() {
+ // Make sure that nobody else currently has a lock or will ever be able to.
+ Lock(true);
+
+ rwlock_assert_success(semDelete(read_ready_));
+ rwlock_assert_success(semDelete(write_ready_));
+}
+
+int RWLock::Lock(bool write) {
+ assert(!intContext());
+
+ int current_task = taskIdSelf();
+ // It's safe to do this check up here (outside of locking the scheduler)
+ // because we only care whether the current task is in there or not and that
+ // can't be changed because it's the task doing the checking.
+ bool current_task_holds_already = TaskOwns(current_task);
+
+ TaskSchedulerLocker scheduler_locker;
+
+ // We can't be reading and writing at the same time.
+ rwlock_assert(!((number_of_write_locks_ > 0) && (number_of_readers_ > 0)));
+
+ if (write) {
+ assert(!current_task_holds_already);
+ // If somebody else already has it locked.
+ // Don't have to worry about another task getting scheduled after
+ // write_ready_ gets given because nobody else (except another writer, which
+ // would just block on it) will do anything while there are pending
+ // writer(s).
+ if ((number_of_readers_ > 0) || (number_of_write_locks_ > 0)) {
+ ++number_of_writers_pending_;
+ // Wait for it to be our turn.
+ rwlock_assert_success(semTake(write_ready_, WAIT_FOREVER));
+ --number_of_writers_pending_;
+ } else {
+ rwlock_assert(number_of_writers_pending_ == 0);
+ }
+ rwlock_assert((number_of_write_locks_ == 0) && (number_of_readers_ == 0));
+ number_of_write_locks_ = 1;
+ return 0;
+ } else { // read
+ // While there are one or more writers active or waiting.
+ // Has to be a loop in case a writer gets scheduled between the time
+ // read_ready_ gets flushed and we run.
+ while ((number_of_write_locks_ > 0) || (number_of_writers_pending_ > 0)) {
+ // Wait for the writer(s) to finish.
+ rwlock_assert_success(semTake(read_ready_, WAIT_FOREVER));
+ }
+
+ int num = number_of_readers_;
+ number_of_readers_ = num + 1;
+ assert(num < kMaxReaders);
+ rwlock_assert(reader_tasks_[num] == 0);
+ reader_tasks_[num] = current_task;
+ rwlock_assert((number_of_write_locks_ == 0) && (number_of_readers_ > 0));
+ return num;
+ }
+}
+
+void RWLock::Unlock(int num) {
+ assert(!intContext());
+ TaskSchedulerLocker scheduler_locker;
+
+ // We have to be reading or writing right now, but not both.
+ rwlock_assert((number_of_write_locks_ > 0) != (number_of_readers_ > 0));
+
+ if (number_of_write_locks_ > 0) { // we're currently writing
+ rwlock_assert(num == 0);
+ --number_of_write_locks_;
+ rwlock_assert((number_of_write_locks_ >= 0) &&
+ (number_of_writers_pending_ >= 0));
+ // If we were the last one.
+ if (number_of_write_locks_ == 0) {
+ // If there are no other tasks waiting to write (because otherwise they
+ // need to get priority over any readers).
+ if (number_of_writers_pending_ == 0) {
+ // Wake up any waiting readers.
+ rwlock_assert_success(semFlush(read_ready_));
+ } else {
+ // Wake up a waiting writer.
+ // Not a problem if somebody else already did this before the waiting
+ // writer got a chance to take it because it'll do nothing and return
+ // success.
+ rwlock_assert_success(semGive(write_ready_));
+ }
+ }
+ } else { // we're curently reading
+ rwlock_assert(reader_tasks_[num] == taskIdSelf());
+ reader_tasks_[num] = 0;
+ --number_of_readers_;
+ rwlock_assert(number_of_readers_ >= 0 &&
+ (number_of_writers_pending_ >= 0));
+ // If we were the last one.
+ if (number_of_readers_ == 0) {
+ // If there are any writers waiting for a chance to go.
+ if (number_of_writers_pending_ > 0) {
+ // Wake a waiting writer.
+ // Not a problem if somebody else already did this before the waiting
+ // writer got a chance to take it because it'll still return success.
+ rwlock_assert_success(semGive(write_ready_));
+ }
+ }
+ }
+}
+
+int RWLock::AddLock() {
+ assert(!intContext());
+ // TODO: Replace this with just atomically incrementing the right number once
+ // we start using a GCC new enough to have the nice atomic builtins.
+ // That will be safe because whether we're currently reading or writing can't
+ // change in the middle of this.
+ TaskSchedulerLocker scheduler_locker;
+
+ // We have to be reading or writing right now, but not both.
+ rwlock_assert((number_of_write_locks_ > 0) != (number_of_readers_ > 0));
+
+ if (number_of_write_locks_ > 0) { // we're currently writing
+ ++number_of_write_locks_;
+ return 0;
+ } else { // we're currently reading
+ return number_of_readers_++;
+ }
+}
+
+bool RWLock::TaskOwns(int task_id) {
+ for (size_t i = 0;
+ i < sizeof(reader_tasks_) / sizeof(reader_tasks_[0]);
+ ++i) {
+ if (reader_tasks_[i] == task_id) return true;
+ }
+ return false;
+}
diff --git a/aos/externals/WPILib/WPILib/RWLock.h b/aos/externals/WPILib/WPILib/RWLock.h
new file mode 100644
index 0000000..13d7b50
--- /dev/null
+++ b/aos/externals/WPILib/WPILib/RWLock.h
@@ -0,0 +1,125 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2008. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
+/*----------------------------------------------------------------------------*/
+
+#ifndef WPILIB_DATA_LOCK_H_
+#define WPILIB_DATA_LOCK_H_
+
+#include <semLib.h>
+
+#include "Base.h"
+
+/**
+ * Represents a read/write lock on using some shared data so that it will not
+ * be modified by any other tasks while code is using it.
+ *
+ * See <http://en.wikipedia.org/wiki/Readers-writer_lock> for an overview of how
+ * this can be used.
+ *
+ * In this implementation, if there are any writers pending, then any new
+ * attempts to acquire read locks will wait until all writers are done unless a
+ * read lock is already held by that same task.
+ */
+class RWLock {
+ public:
+ /**
+ * Represents an actual lock on the shared data. The destructor will free it.
+ *
+ * Intended to be used as an automatic (or local) variable so that the
+ * compiler will ensure that the destructor gets called no matter how the
+ * scope is exited.
+ *
+ * While it is possible to use new/delete to dynamically allocate an instance,
+ * the constructor and destructor still MUST still be called from the same
+ * task.
+ *
+ * Has a copy constructor which allows "copying" the lock that is held. Does
+ * not have an assignment operator because assigning a lock doesn't make much
+ * sense.
+ */
+ class Locker {
+ public:
+ /**
+ * @param write Whether to create a writer lock (creates a reader lock
+ * otherwise).
+ */
+ Locker(RWLock *lock, bool write);
+
+ /**
+ * Creates another lock of the same type. They can both be released
+ * (destructed) independently.
+ * NOTE: This does allow creating multiple write locks that are held at the
+ * same time.
+ */
+ Locker(const Locker &other);
+
+ /**
+ * Unlocks the lock.
+ */
+ ~Locker();
+
+ private:
+ RWLock *const lock_;
+ const int num_;
+
+ void operator=(const Locker &);
+ };
+
+ /**
+ * The maximum number of read locks that can be held at the same time.
+ */
+ static const int kMaxReaders = 64;
+
+ RWLock();
+ /**
+ * Waits until there are no more read or write locks held.
+ */
+ ~RWLock();
+
+ private:
+ // The number of write locks that are currently held.
+ int number_of_write_locks_;
+ // How many tasks are currently waiting to get a write lock.
+ // Each count in here corresponds to a task that is blocked on write_ready_.
+ int number_of_writers_pending_;
+
+ // How many read locks are currently held.
+ int number_of_readers_;
+
+ // The task ID of the task holding each read lock.
+ int reader_tasks_[kMaxReaders];
+
+ // Always locked. Gets semFlushed when readers are allowed to take the lock
+ // (after all writers are done).
+ SEM_ID read_ready_;
+ // Locked almost all of the time. Pending writers (who have to update
+ // number_of_writers_pending_) block locking this and it gets unlocked when it
+ // is time for one of them to go.
+ SEM_ID write_ready_;
+
+ // Acquires the appropriate kind of lock.
+ // Returns a value that must be passed to the corresponding Unlock call.
+ int Lock(bool write);
+ // Unlocks 1 lock.
+ // Does not need to know whether it is read or write because only one type of
+ // lock can be held at a time.
+ // num must be the return value from the corresponding Lock/AddLock call.
+ void Unlock(int num);
+ // Increments the lock count by 1.
+ // There must be at least 1 lock held during the execution of this method.
+ // Use the regular Unlock() to unlock a lock acquired this way.
+ // This is not the same as Lock(current_type) because this is the only way to
+ // acquire multiple write locks at the same time.
+ // Returns a value that must be passed to the corresponding Unlock call.
+ int AddLock();
+ // Checks whether task_id is in reader_tasks_.
+ bool TaskOwns(int task_id);
+
+ friend class Locker;
+
+ DISALLOW_COPY_AND_ASSIGN(RWLock);
+};
+
+#endif // WPILIB_DATA_LOCK_H_
diff --git a/aos/externals/WPILib/WPILib/Relay.cpp b/aos/externals/WPILib/WPILib/Relay.cpp
index dd59d52..9fb3a2d 100644
--- a/aos/externals/WPILib/WPILib/Relay.cpp
+++ b/aos/externals/WPILib/WPILib/Relay.cpp
@@ -43,9 +43,9 @@
if (m_direction == kBothDirections || m_direction == kForwardOnly)
{
snprintf(buf, 64, "Forward Relay %d (Module: %d)", m_channel, moduleNumber);
- if (relayChannels->Allocate(((moduleNumber - 1) * kRelayChannels + m_channel - 1) * 2, buf) == ~0ul)
+ if (relayChannels->Allocate(((moduleNumber - 1) * kRelayChannels +
+ m_channel - 1) * 2, buf, this) == ~0ul)
{
- CloneError(relayChannels);
return;
}
@@ -54,9 +54,9 @@
if (m_direction == kBothDirections || m_direction == kReverseOnly)
{
snprintf(buf, 64, "Reverse Relay %d (Module: %d)", m_channel, moduleNumber);
- if (relayChannels->Allocate(((moduleNumber - 1) * kRelayChannels + m_channel - 1) * 2 + 1, buf) == ~0ul)
+ if (relayChannels->Allocate(((moduleNumber - 1) * kRelayChannels
+ + m_channel - 1) * 2 + 1, buf, this) == ~0ul)
{
- CloneError(relayChannels);
return;
}
@@ -105,11 +105,13 @@
if (m_direction == kBothDirections || m_direction == kForwardOnly)
{
- relayChannels->Free(((m_module->GetNumber() - 1) * kRelayChannels + m_channel - 1) * 2);
+ relayChannels->Free(((m_module->GetNumber() - 1) *
+ kRelayChannels + m_channel - 1) * 2, this);
}
if (m_direction == kBothDirections || m_direction == kReverseOnly)
{
- relayChannels->Free(((m_module->GetNumber() - 1) * kRelayChannels + m_channel - 1) * 2 + 1);
+ relayChannels->Free(((m_module->GetNumber() - 1) *
+ kRelayChannels + m_channel - 1) * 2 + 1, this);
}
}
diff --git a/aos/externals/WPILib/WPILib/Resource.cpp b/aos/externals/WPILib/WPILib/Resource.cpp
index ec35eb3..ef7d15d 100644
--- a/aos/externals/WPILib/WPILib/Resource.cpp
+++ b/aos/externals/WPILib/WPILib/Resource.cpp
@@ -6,7 +6,6 @@
#include "Resource.h"
#include "WPIErrors.h"
-#include "ErrorBase.h"
ReentrantSemaphore Resource::m_createLock;
@@ -28,6 +27,7 @@
/**
* Factory method to create a Resource allocation-tracker *if* needed.
+ * Handles the necessary synchronization internally.
*
* @param r -- address of the caller's Resource pointer. If *r == NULL, this
* will construct a Resource and make *r point to it. If *r != NULL, i.e.
@@ -59,7 +59,7 @@
* When a resource is requested, mark it allocated. In this case, a free resource value
* within the range is located and returned after it is marked allocated.
*/
-UINT32 Resource::Allocate(const char *resourceDesc)
+UINT32 Resource::Allocate(const char *resourceDesc, const ErrorBase *error)
{
Synchronized sync(m_allocateLock);
for (UINT32 i=0; i < m_size; i++)
@@ -70,7 +70,7 @@
return i;
}
}
- wpi_setWPIErrorWithContext(NoAvailableResources, resourceDesc);
+ wpi_setStaticWPIErrorWithContext(error, NoAvailableResources, resourceDesc);
return ~0ul;
}
@@ -79,17 +79,18 @@
* The user requests a specific resource value, i.e. channel number and it is verified
* unallocated, then returned.
*/
-UINT32 Resource::Allocate(UINT32 index, const char *resourceDesc)
+UINT32 Resource::Allocate(UINT32 index, const char *resourceDesc,
+ const ErrorBase *error)
{
Synchronized sync(m_allocateLock);
if (index >= m_size)
{
- wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, resourceDesc);
+ wpi_setStaticWPIErrorWithContext(error, ChannelIndexOutOfRange, resourceDesc);
return ~0ul;
}
if ( m_isAllocated[index] )
{
- wpi_setWPIErrorWithContext(ResourceAlreadyAllocated, resourceDesc);
+ wpi_setStaticWPIErrorWithContext(error, ResourceAlreadyAllocated, resourceDesc);
return ~0ul;
}
m_isAllocated[index] = true;
@@ -102,18 +103,18 @@
* After a resource is no longer needed, for example a destructor is called for a channel assignment
* class, Free will release the resource value so it can be reused somewhere else in the program.
*/
-void Resource::Free(UINT32 index)
+void Resource::Free(UINT32 index, const ErrorBase *error)
{
Synchronized sync(m_allocateLock);
if (index == ~0ul) return;
if (index >= m_size)
{
- wpi_setWPIError(NotAllocated);
+ wpi_setStaticWPIError(error, NotAllocated);
return;
}
if (!m_isAllocated[index])
{
- wpi_setWPIError(NotAllocated);
+ wpi_setStaticWPIError(error, NotAllocated);
return;
}
m_isAllocated[index] = false;
diff --git a/aos/externals/WPILib/WPILib/Resource.h b/aos/externals/WPILib/WPILib/Resource.h
index dbe1936..11faaec 100644
--- a/aos/externals/WPILib/WPILib/Resource.h
+++ b/aos/externals/WPILib/WPILib/Resource.h
@@ -19,15 +19,18 @@
* The Resource class does not allocate the hardware channels or other
* resources; it just tracks which indices were marked in use by
* Allocate and not yet freed by Free.
+ *
+ * Several methods require an ErrorBase* so that they can report any errors.
*/
-class Resource : public ErrorBase
+class Resource
{
public:
virtual ~Resource();
static void CreateResourceObject(Resource **r, UINT32 elements);
- UINT32 Allocate(const char *resourceDesc);
- UINT32 Allocate(UINT32 index, const char *resourceDesc);
- void Free(UINT32 index);
+ UINT32 Allocate(const char *resourceDesc, const ErrorBase *error);
+ UINT32 Allocate(UINT32 index, const char *resourceDesc,
+ const ErrorBase *error);
+ void Free(UINT32 index, const ErrorBase *error);
private:
explicit Resource(UINT32 size);
diff --git a/aos/externals/WPILib/WPILib/RobotBase.cpp b/aos/externals/WPILib/WPILib/RobotBase.cpp
index 0bebf09..17c7682 100644
--- a/aos/externals/WPILib/WPILib/RobotBase.cpp
+++ b/aos/externals/WPILib/WPILib/RobotBase.cpp
@@ -19,6 +19,8 @@
void RobotBase::setInstance(RobotBase* robot)
{
+ // No point in synchronization here because it's private and it only gets
+ // called from robotTask.
wpi_assert(m_instance == NULL);
m_instance = robot;
}
@@ -30,8 +32,9 @@
/**
* Constructor for a generic robot program.
- * User code should be placed in the constuctor that runs before the Autonomous or Operator
- * Control period starts. The constructor will run to completion before Autonomous is entered.
+ * User code that should run before the Autonomous or Operator Control period
+ * starts should be placed in the subclass constructor.
+ * The constructor must finish before Autonomous can be entered.
*
* This must be used to ensure that the communications code starts. In the future it would be
* nice to put this code into it's own task that loads on boot so ensure that it runs.
@@ -45,7 +48,7 @@
/**
* Free the resources for a RobotBase class.
- * This includes deleting all classes that might have been allocated as Singletons to they
+ * This includes deleting all classes that might have been allocated as Singletons so they
* would never be deleted except here.
*/
RobotBase::~RobotBase()
@@ -95,7 +98,7 @@
}
/**
- * Determine if the robot is currently in Autnomous mode.
+ * Determine if the robot is currently in Autonomous mode.
* @return True if the robot is currently operating Autonomously as determined by the field controls.
*/
bool RobotBase::IsAutonomous()
@@ -135,18 +138,21 @@
*/
void RobotBase::robotTask(FUNCPTR factory, Task *task)
{
- RobotBase::setInstance((RobotBase*)factory());
- RobotBase::getInstance().m_task = task;
- RobotBase::getInstance().StartCompetition();
+ RobotBase *instance = (RobotBase*)factory();
+ instance->m_task = task;
+ RobotBase::setInstance(instance);
+ instance->StartCompetition();
}
/**
*
* Start the robot code.
- * This function starts the robot code running by spawning a task. Currently tasks seemed to be
- * started by LVRT without setting the VX_FP_TASK flag so floating point context is not saved on
- * interrupts. Therefore the program experiences hard to debug and unpredictable results. So the
- * LVRT code starts this function, and it, in turn, starts the actual user program.
+ * This function starts the robot code running by spawning a task. Currently
+ * tasks seem to be started by LVRT without setting the VX_FP_TASK flag which
+ * means that the floating point registers are not saved on interrupts and task
+ * switches. That causes the program to experience hard to debug and
+ * unpredictable results, so the LVRT code starts this function, so that it, in
+ * turn, can start the actual user program.
*/
void RobotBase::startRobotTask(FUNCPTR factory)
{
@@ -199,8 +205,7 @@
/**
* This class exists for the sole purpose of getting its destructor called when the module unloads.
* Before the module is done unloading, we need to delete the RobotBase derived singleton. This should delete
- * the other remaining singletons that were registered. This should also stop all tasks that are using
- * the Task class.
+ * the other remaining singletons that were registered.
*/
class RobotDeleter
{
diff --git a/aos/externals/WPILib/WPILib/RobotBase.h b/aos/externals/WPILib/WPILib/RobotBase.h
index ac15250..45c24dd 100644
--- a/aos/externals/WPILib/WPILib/RobotBase.h
+++ b/aos/externals/WPILib/WPILib/RobotBase.h
@@ -13,6 +13,11 @@
class DriverStation;
+/**
+ * This macro will set up the given class (which must be a (direct or indirect)
+ * RobotBase subclass) so that when the user code is loaded, it will be
+ * instantiated and StartCompetition() will be called on the instance.
+ */
#define START_ROBOT_CLASS(_ClassName_) \
RobotBase *FRC_userClassFactory() \
{ \
@@ -28,17 +33,14 @@
/**
* Implement a Robot Program framework.
- * The RobotBase class is intended to be subclassed by a user creating a robot program.
- * Overridden Autonomous() and OperatorControl() methods are called at the appropriate time
- * as the match proceeds. In the current implementation, the Autonomous code will run to
- * completion before the OperatorControl code could start. In the future the Autonomous code
- * might be spawned as a task, then killed at the end of the Autonomous period.
+ * The RobotBase class is intended to be subclassed by a user creating a robot
+ * program, possibly indirectly through one of the subclasses included in this
+ * library.
*/
class RobotBase {
friend class RobotDeleter;
public:
static RobotBase &getInstance();
- static void setInstance(RobotBase* robot);
bool IsEnabled();
bool IsDisabled();
@@ -49,13 +51,15 @@
bool IsNewDataAvailable();
Watchdog &GetWatchdog();
static void startRobotTask(FUNCPTR factory);
- static void robotTask(FUNCPTR factory, Task *task);
protected:
virtual ~RobotBase();
virtual void StartCompetition() = 0;
RobotBase();
+ static void setInstance(RobotBase* robot);
+ static void robotTask(FUNCPTR factory, Task *task);
+
Task *m_task;
Watchdog m_watchdog;
DriverStation *m_ds;
diff --git a/aos/externals/WPILib/WPILib/RobotDrive.cpp b/aos/externals/WPILib/WPILib/RobotDrive.cpp
index 14e28f5..1d538c5 100644
--- a/aos/externals/WPILib/WPILib/RobotDrive.cpp
+++ b/aos/externals/WPILib/WPILib/RobotDrive.cpp
@@ -725,7 +725,7 @@
void RobotDrive::GetDescription(char *desc)
{
- sprintf(desc, "RobotDrive");
+ snprintf(desc, 64, "RobotDrive");
}
void RobotDrive::StopMotor()
diff --git a/aos/externals/WPILib/WPILib/SafePWM.cpp b/aos/externals/WPILib/WPILib/SafePWM.cpp
index 484fbe6..989d782 100644
--- a/aos/externals/WPILib/WPILib/SafePWM.cpp
+++ b/aos/externals/WPILib/WPILib/SafePWM.cpp
@@ -100,7 +100,7 @@
void SafePWM::GetDescription(char *desc)
{
- sprintf(desc, "PWM %d on module %d", GetChannel(), GetModuleNumber());
+ snprintf(desc, 64, "PWM %d on module %d", GetChannel(), GetModuleNumber());
}
/**
diff --git a/aos/externals/WPILib/WPILib/SensorBase.cpp b/aos/externals/WPILib/WPILib/SensorBase.cpp
index a68d260..5574a35 100644
--- a/aos/externals/WPILib/WPILib/SensorBase.cpp
+++ b/aos/externals/WPILib/WPILib/SensorBase.cpp
@@ -7,7 +7,6 @@
#include "SensorBase.h"
#include "NetworkCommunication/LoadOut.h"
-#include "WPIErrors.h"
const UINT32 SensorBase::kSystemClockTicksPerMicrosecond;
const UINT32 SensorBase::kDigitalChannels;
@@ -18,11 +17,11 @@
const UINT32 SensorBase::kSolenoidModules;
const UINT32 SensorBase::kPwmChannels;
const UINT32 SensorBase::kRelayChannels;
-const UINT32 SensorBase::kChassisSlots;
SensorBase *SensorBase::m_singletonList = NULL;
+ReentrantSemaphore SensorBase::m_singletonListSemaphore;
/**
- * Creates an instance of the sensor base and gets an FPGA handle
+ * Creates an instance of SensorBase.
*/
SensorBase::SensorBase()
{
@@ -36,27 +35,31 @@
}
/**
- * Add sensor to the singleton list.
- * Add this sensor to the list of singletons that need to be deleted when
- * the robot program exits. Each of the sensors on this list are singletons,
- * that is they aren't allocated directly with new, but instead are allocated
- * by the static GetInstance method. As a result, they are never deleted when
- * the program exits. Consequently these sensors may still be holding onto
- * resources and need to have their destructors called at the end of the program.
+ * @brief Add sensor to the singleton list.
+ * Add this object to the list of singletons that need to be deleted when
+ * the robot program exits. Each of the objects on this list are singletons,
+ * that is they aren't allocated directly by user code, but instead are
+ * allocated by (for example) a static GetInstance method. Because of this, they
+ * need some way to be freed when the module is unloaded so that they can free
+ * any resources that they are holding on to.
+ * @see #DeleteSingletons()
*/
void SensorBase::AddToSingletonList()
{
+ Synchronized sync(m_singletonListSemaphore);
m_nextSingleton = m_singletonList;
m_singletonList = this;
}
/**
- * Delete all the singleton classes on the list.
- * All the classes that were allocated as singletons need to be deleted so
+ * @brief Delete all the singleton objects on the list.
+ * All the objects that were allocated as singletons need to be deleted so
* their resources can be freed.
+ * @see #AddToSingletonList()
*/
void SensorBase::DeleteSingletons()
{
+ Synchronized sync(m_singletonListSemaphore);
for (SensorBase *next = m_singletonList; next != NULL;)
{
SensorBase *tmp = next;
diff --git a/aos/externals/WPILib/WPILib/SensorBase.h b/aos/externals/WPILib/WPILib/SensorBase.h
index 1b149b1..3f12360 100644
--- a/aos/externals/WPILib/WPILib/SensorBase.h
+++ b/aos/externals/WPILib/WPILib/SensorBase.h
@@ -7,20 +7,19 @@
#ifndef SENSORBASE_H_
#define SENSORBASE_H_
-#include "ChipObject/NiRio.h"
#include "ErrorBase.h"
#include <stdio.h>
#include "Base.h"
+#include "Synchronized.h"
/**
* Base class for all sensors.
* Stores most recent status information as well as containing utility functions for checking
- * channels and error processing.
+ * channels.
*/
class SensorBase: public ErrorBase {
public:
SensorBase();
- virtual ~SensorBase();
static void DeleteSingletons();
static UINT32 GetDefaultAnalogModule() { return 1; }
static UINT32 GetDefaultDigitalModule() { return 1; }
@@ -36,6 +35,9 @@
static bool CheckAnalogChannel(UINT32 channel);
static bool CheckSolenoidChannel(UINT32 channel);
+ // NOT vxworks system clock ticks (returned by sysClkRateGet() from sysLib).
+ // TODO: Document what this actually is (has something to do with FPGA times).
+ // 40kHz clock?
static const UINT32 kSystemClockTicksPerMicrosecond = 40;
static const UINT32 kDigitalChannels = 14;
static const UINT32 kAnalogChannels = 8;
@@ -45,14 +47,19 @@
static const UINT32 kSolenoidModules = 2;
static const UINT32 kPwmChannels = 10;
static const UINT32 kRelayChannels = 8;
- static const UINT32 kChassisSlots = 8;
+
protected:
void AddToSingletonList();
+ // Subclasses that don't use the singleton list mechanism should make this
+ // public, but ones that do should keep it protected so that users can not
+ // delete the singleton instance(s).
+ virtual ~SensorBase();
private:
DISALLOW_COPY_AND_ASSIGN(SensorBase);
static SensorBase *m_singletonList;
SensorBase *m_nextSingleton;
+ static ReentrantSemaphore m_singletonListSemaphore;
};
diff --git a/aos/externals/WPILib/WPILib/SimpleRobot.h b/aos/externals/WPILib/WPILib/SimpleRobot.h
index d963805..88143a6 100644
--- a/aos/externals/WPILib/WPILib/SimpleRobot.h
+++ b/aos/externals/WPILib/WPILib/SimpleRobot.h
@@ -11,6 +11,10 @@
/**
* @todo If this is going to last until release, it needs a better name.
+ * Overridden Autonomous() and OperatorControl() methods are called at the appropriate time
+ * as the match proceeds. In the current implementation, the Autonomous code will run to
+ * completion before the OperatorControl code could start. In the future the Autonomous code
+ * might be spawned as a task, then killed at the end of the Autonomous period.
*/
class SimpleRobot: public RobotBase
{
diff --git a/aos/externals/WPILib/WPILib/Solenoid.cpp b/aos/externals/WPILib/WPILib/Solenoid.cpp
index 35813af..7a56a09 100644
--- a/aos/externals/WPILib/WPILib/Solenoid.cpp
+++ b/aos/externals/WPILib/WPILib/Solenoid.cpp
@@ -30,9 +30,10 @@
Resource::CreateResourceObject(&m_allocated, tSolenoid::kNumDO7_0Elements * kSolenoidChannels);
snprintf(buf, 64, "Solenoid %d (Module: %d)", m_channel, m_moduleNumber);
- if (m_allocated->Allocate((m_moduleNumber - 1) * kSolenoidChannels + m_channel - 1, buf) == ~0ul)
+ if (m_allocated->Allocate((m_moduleNumber - 1) * kSolenoidChannels
+ + m_channel - 1,
+ buf, this) == ~0ul)
{
- CloneError(m_allocated);
return;
}
@@ -72,7 +73,8 @@
{
if (CheckSolenoidModule(m_moduleNumber))
{
- m_allocated->Free((m_moduleNumber - 1) * kSolenoidChannels + m_channel - 1);
+ m_allocated->Free((m_moduleNumber - 1) * kSolenoidChannels + m_channel - 1,
+ this);
}
}
diff --git a/aos/externals/WPILib/WPILib/SolenoidBase.cpp b/aos/externals/WPILib/WPILib/SolenoidBase.cpp
index cc1a2c4..1f38869 100644
--- a/aos/externals/WPILib/WPILib/SolenoidBase.cpp
+++ b/aos/externals/WPILib/WPILib/SolenoidBase.cpp
@@ -50,7 +50,7 @@
}
/**
- * Set the value of a solenoid.
+ * Set the value of 1 or more solenoids at the same time.
*
* @param value The value you want to set on the module.
* @param mask The channels you want to be affected.
@@ -63,8 +63,9 @@
Synchronized sync(m_semaphore);
UINT8 currentValue = m_fpgaSolenoidModule->readDO7_0(m_moduleNumber - 1, &localStatus);
// Zero out the values to change
- currentValue = currentValue & ~mask;
- currentValue = currentValue | (value & mask);
+ currentValue &= ~mask;
+ // Actually set the values.
+ currentValue |= value & mask;
m_fpgaSolenoidModule->writeDO7_0(m_moduleNumber - 1, currentValue, &localStatus);
}
wpi_setError(localStatus);
diff --git a/aos/externals/WPILib/WPILib/SolenoidBase.h b/aos/externals/WPILib/WPILib/SolenoidBase.h
index a7a67a6..a9fdf61 100644
--- a/aos/externals/WPILib/WPILib/SolenoidBase.h
+++ b/aos/externals/WPILib/WPILib/SolenoidBase.h
@@ -15,17 +15,25 @@
/**
* SolenoidBase class is the common base class for the Solenoid and
* DoubleSolenoid classes.
+ * It also supports getting and setting the values of all solenoids on a given
+ * module at the same time directly.
*/
class SolenoidBase : public SensorBase {
public:
+ explicit SolenoidBase(UINT8 moduleNumber);
virtual ~SolenoidBase();
+
+ void Set(UINT8 value, UINT8 mask);
+
UINT8 GetAll();
+ /**
+ * Set the value of all of the solenoids at the same time.
+ *
+ * @param value The values you want to set all of the solenoids to.
+ */
+ void SetAll(UINT8 value) { Set(value, 0xFF); }
protected:
- explicit SolenoidBase(UINT8 moduleNumber);
- void Set(UINT8 value, UINT8 mask);
- virtual void InitSolenoid() = 0;
-
UINT32 m_moduleNumber; ///< Slot number where the module is plugged into the chassis.
static Resource *m_allocated;
diff --git a/aos/externals/WPILib/WPILib/Synchronized.cpp b/aos/externals/WPILib/WPILib/Synchronized.cpp
index eb17318..fd133b5 100644
--- a/aos/externals/WPILib/WPILib/Synchronized.cpp
+++ b/aos/externals/WPILib/WPILib/Synchronized.cpp
@@ -20,7 +20,7 @@
semTake(m_semaphore, WAIT_FOREVER);
}
-Synchronized::Synchronized(ReentrantSemaphore& semaphore)
+Synchronized::Synchronized(const ReentrantSemaphore& semaphore)
{
m_semaphore = semaphore.m_semaphore;
semTake(m_semaphore, WAIT_FOREVER);
diff --git a/aos/externals/WPILib/WPILib/Synchronized.h b/aos/externals/WPILib/WPILib/Synchronized.h
index 28cfbc3..4e44b0e 100644
--- a/aos/externals/WPILib/WPILib/Synchronized.h
+++ b/aos/externals/WPILib/WPILib/Synchronized.h
@@ -27,11 +27,15 @@
*
* This class is safe to use in static variables because it does not depend on
* any other C++ static constructors or destructors.
+ *
+ * The instance methods are marked const because using this class from multiple
+ * threads at once is safe and they don't actually modify the value of any of
+ * the instance variables.
*/
class ReentrantSemaphore
{
public:
- explicit ReentrantSemaphore() {
+ ReentrantSemaphore() {
m_semaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE);
}
~ReentrantSemaphore() {
@@ -42,7 +46,7 @@
* Lock the semaphore, blocking until it's available.
* @return 0 for success, -1 for error. If -1, the error will be in errno.
*/
- int take() {
+ int take() const {
return semTake(m_semaphore, WAIT_FOREVER);
}
@@ -50,7 +54,7 @@
* Unlock the semaphore.
* @return 0 for success, -1 for error. If -1, the error will be in errno.
*/
- int give() {
+ int give() const {
return semGive(m_semaphore);
}
@@ -83,8 +87,8 @@
{
public:
explicit Synchronized(SEM_ID);
- explicit Synchronized(ReentrantSemaphore&);
- virtual ~Synchronized();
+ explicit Synchronized(const ReentrantSemaphore&);
+ ~Synchronized();
private:
SEM_ID m_semaphore;
diff --git a/aos/externals/WPILib/WPILib/Task.cpp b/aos/externals/WPILib/WPILib/Task.cpp
index 4568246..5310d41 100644
--- a/aos/externals/WPILib/WPILib/Task.cpp
+++ b/aos/externals/WPILib/WPILib/Task.cpp
@@ -18,6 +18,7 @@
/**
* Create but don't launch a task.
+ * Does not use any floating point registers.
* @param name The name of the task. "FRC_" will be prepended to the task name.
* @param function The address of the function to run as the new task.
* @param priority The VxWorks priority for the task.
@@ -38,6 +39,9 @@
nUsageReporting::report(nUsageReporting::kResourceType_Task, instances, 0, m_taskName);
}
+/**
+ * Does not use any floating point registers.
+ */
Task::~Task()
{
if (m_taskID != kInvalidTaskID) Stop();
@@ -47,18 +51,20 @@
/**
* Starts this task.
- * If it is already running or unable to start, it fails and returns false.
+ * Does not use any floating point registers.
+ * @return true on success
*/
bool Task::Start(UINT32 arg0, UINT32 arg1, UINT32 arg2, UINT32 arg3, UINT32 arg4,
UINT32 arg5, UINT32 arg6, UINT32 arg7, UINT32 arg8, UINT32 arg9)
{
+ // Don't have to lock m_prioritySemaphore because this code isn't changing it.
m_taskID = taskSpawn(m_taskName,
m_priority,
VX_FP_TASK, // options
m_stackSize, // stack size
m_function, // function to start
- arg0, arg1, arg2, arg3, arg4, // parameter 1 - pointer to this class
- arg5, arg6, arg7, arg8, arg9);// additional unused parameters
+ arg0, arg1, arg2, arg3, arg4, // parameters to pass to m_function
+ arg5, arg6, arg7, arg8, arg9);// additional parameters
bool ok = HandleError(m_taskID);
if (!ok) m_taskID = kInvalidTaskID;
return ok;
@@ -66,8 +72,7 @@
/**
* Restarts a running task.
- * If the task isn't started, it starts it.
- * @return false if the task is running and we are unable to kill the previous instance
+ * @return true on success
*/
bool Task::Restart()
{
@@ -75,8 +80,8 @@
}
/**
- * Kills the running task.
- * @returns true on success false if the task doesn't exist or we are unable to kill it.
+ * Makes sure that the task is not running.
+ * @returns true on success
*/
bool Task::Stop()
{
@@ -109,7 +114,7 @@
/**
* Pauses a running task.
- * Returns true on success, false if unable to pause or the task isn't running.
+ * Returns true on success
*/
bool Task::Suspend()
{
@@ -118,7 +123,7 @@
/**
* Resumes a paused task.
- * Returns true on success, false if unable to resume or if the task isn't running/paused.
+ * Returns true on success
*/
bool Task::Resume()
{
@@ -140,6 +145,7 @@
*/
INT32 Task::GetPriority()
{
+ Synchronized sync(m_prioritySemaphore);
if (HandleError(taskPriorityGet(m_taskID, &m_priority)))
return m_priority;
else
@@ -155,6 +161,7 @@
*/
bool Task::SetPriority(INT32 priority)
{
+ Synchronized sync(m_prioritySemaphore);
m_priority = priority;
return HandleError(taskPrioritySet(m_taskID, m_priority));
}
diff --git a/aos/externals/WPILib/WPILib/Task.h b/aos/externals/WPILib/WPILib/Task.h
index 03c9555..d1ad259 100644
--- a/aos/externals/WPILib/WPILib/Task.h
+++ b/aos/externals/WPILib/WPILib/Task.h
@@ -9,10 +9,14 @@
#include "ErrorBase.h"
#include <vxWorks.h>
+#include "Synchronized.h"
/**
- * WPI task is a wrapper for the native Task object.
- * All WPILib tasks are managed by a static task manager for simplified cleanup.
+ * WPI task is a wrapper for a native VxWorks task.
+ *
+ * Some functions (documented) are guaranteed not to use any floating point so
+ * that it is safe to use them from tasks that do not have the VX_FP_TASK flag
+ * set (like during startup).
**/
class Task : public ErrorBase
{
@@ -47,6 +51,7 @@
INT32 m_taskID;
UINT32 m_stackSize;
INT32 m_priority;
+ ReentrantSemaphore m_prioritySemaphore;
bool HandleError(STATUS results);
DISALLOW_COPY_AND_ASSIGN(Task);
};
diff --git a/aos/externals/WPILib/WPILib/Timer.cpp b/aos/externals/WPILib/WPILib/Timer.cpp
index e9fcde7..7638b59 100644
--- a/aos/externals/WPILib/WPILib/Timer.cpp
+++ b/aos/externals/WPILib/WPILib/Timer.cpp
@@ -12,6 +12,7 @@
#include "Synchronized.h"
#include "Utility.h"
+#include "Global.h"
/**
* Pause the task for a specified time.
@@ -180,7 +181,7 @@
{
// FPGA returns the timestamp in microseconds
// Call the helper GetFPGATime() in Utility.cpp
- return GetFPGATime() * 1.0e-6;
+ return Global::GetInstance()->GetFPGATime() * 1.0e-6;
}
// Internal function that reads the PPC timestamp counter.
diff --git a/aos/externals/WPILib/WPILib/Utility.cpp b/aos/externals/WPILib/WPILib/Utility.cpp
index 5ce84f9..680da97 100644
--- a/aos/externals/WPILib/WPILib/Utility.cpp
+++ b/aos/externals/WPILib/WPILib/Utility.cpp
@@ -7,34 +7,34 @@
#include "Utility.h"
#include "NetworkCommunication/FRCComm.h"
-#include "ChipObject.h"
#include "Task.h"
#include <dbgLib.h>
#include <stdio.h>
+#include <taskLib.h>
#include <sysSymTbl.h>
#include "nivision.h"
-#define DBG_DEMANGLE_PRINT_LEN 256 /* Num chars of demangled names to print */
+#define DBG_DEMANGLE_PRINT_LEN MAX_SYS_SYM_LEN /* Num chars of demangled names to print */
extern "C"
{
extern char * cplusDemangle (char *source, char *dest, INT32 n);
}
-char *wpi_getLabel(UINT addr, INT32 *found)
+void wpi_getLabel(UINT addr, char *label, INT32 *found)
{
INT32 pVal;
SYM_TYPE pType;
char name[MAX_SYS_SYM_LEN + 1];
- static char label[DBG_DEMANGLE_PRINT_LEN + 1 + 11];
- bzero(label, DBG_DEMANGLE_PRINT_LEN + 1 + 11);
+ static const size_t kLabelSize = DBG_DEMANGLE_PRINT_LEN + 1 + 11;
+ bzero(label, kLabelSize);
if (symFindByValue(sysSymTbl, addr, name, &pVal, &pType) == OK)
{
- cplusDemangle(name, label, sizeof(label) - 11);
+ cplusDemangle(name, label, kLabelSize - 11);
if ((UINT)pVal != addr)
{
- sprintf(&label[strlen(label)], "+0x%04x", addr-pVal);
+ snprintf(label + strlen(label), kLabelSize - strlen(label), "+0x%04x", addr-pVal);
if (found) *found = 2;
}
else
@@ -44,11 +44,9 @@
}
else
{
- sprintf(label, "0x%04x", addr);
+ snprintf(label, kLabelSize, "0x%04x", addr);
if (found) *found = 0;
}
-
- return label;
}
/*
static void wpiTracePrint(INSTR *caller, INT32 func, INT32 nargs, INT32 *args, INT32 taskId, BOOL isKernelAdrs)
@@ -56,15 +54,16 @@
char buf [MAX_SYS_SYM_LEN * 2];
INT32 ix;
INT32 len = 0;
- len += sprintf (&buf [len], "%s <%#010x>: ", wpi_getLabel((UINT)caller), (INT32)caller);
- len += sprintf (&buf [len], "%s <%#010x> (", wpi_getLabel((UINT)func), func);
+ len += snprintf (&buf [len], sizeof(buf) - len, "%s <%#010x>: ", wpi_getLabel((UINT)caller), (INT32)caller);
+ len += snprintf (&buf [len], sizeof(buf) - len, "%s <%#010x> (", wpi_getLabel((UINT)func), func);
for (ix = 0; ix < nargs; ix++)
{
- if (ix != 0)
- len += sprintf (&buf [len], ", ");
- len += sprintf (&buf [len], "%#x", args [ix]);
+ if (ix != 0) {
+ len += snprintf (&buf [len], sizeof(buf) - len, ", ");
+ }
+ len += snprintf (&buf [len], sizeof(buf) - len, "%#x", args [ix]);
}
- len += sprintf (&buf [len], ")\n");
+ len += snprintf (&buf [len], sizeof(buf) - len, ")\n");
printf(buf);
}
@@ -77,7 +76,8 @@
INT32 nameFound = 0;
INT32 params = 0;
INT32 totalnargs = nargs;
- char *funcName = wpi_getLabel((UINT)func, &nameFound);
+ char funcName[DBG_DEMANGLE_PRINT_LEN + 1 + 11];
+ wpi_getLabel((UINT)func, funcName, &nameFound);
// Ignore names that are not exact symbol address matches.
if (nameFound != 1) return;
@@ -107,23 +107,24 @@
}
char *funcNameEnd = strchr(funcName, '(');
*funcNameEnd = 0;
- len += sprintf (&buf [len], funcName);
+ len += snprintf (buf + len, sizeof(buf) - len, funcName);
// If this is a member function, print out the this pointer value.
if (totalnargs - params == 1)
{
- len += sprintf (&buf [len], "<this=%#x>", args [0]);
+ len += snprintf (buf + len, sizeof(buf) - len, "<this=%#x>", args [0]);
}
// Print out the argument values.
- len += sprintf (&buf [len], "(");
+ len += snprintf (buf + len, sizeof(buf) - len, "(");
for (ix = totalnargs - params; ix < nargs; ix++)
{
- if (ix != totalnargs - params)
- len += sprintf (&buf [len], ", ");
- len += sprintf (&buf [len], "%#x", args [ix]);
+ if (ix != totalnargs - params) {
+ len += snprintf (buf + len, sizeof(buf) - len, ", ");
+ }
+ len += snprintf (buf + len, sizeof(buf) - len, "%#x", args [ix]);
}
- len += sprintf (&buf [len], ")\n");
+ len += snprintf (buf + len, sizeof(buf) - len, ")\n");
printf(buf);
}
@@ -135,7 +136,11 @@
static INT32 wpiStackTask(INT32 taskId)
{
- taskDelay(1);
+ // Make sure it's suspended in spite of any scheduler weirdness or whatever.
+ while (!taskIsSuspended(taskId)) {
+ taskDelay(1);
+ }
+
//tt(taskId);
REG_SET regs;
@@ -212,10 +217,10 @@
// If an error message was specified, include it
// Build error string
if(message != NULL) {
- sprintf(error, "Assertion failed: \"%s\", \"%s\" failed in %s() in %s at line %d\n",
+ snprintf(error, sizeof(error), "Assertion failed: \"%s\", \"%s\" failed in %s() in %s at line %d\n",
message, conditionText, funcName, fileName, lineNumber);
} else {
- sprintf(error, "Assertion failed: \"%s\" in %s() in %s at line %d\n",
+ snprintf(error, sizeof(error), "Assertion failed: \"%s\" in %s() in %s at line %d\n",
conditionText, funcName, fileName, lineNumber);
}
@@ -248,10 +253,10 @@
// If an error message was specified, include it
// Build error string
if(message != NULL) {
- sprintf(error, "Assertion failed: \"%s\", \"%d\" %s \"%d\" in %s() in %s at line %d\n",
+ snprintf(error, sizeof(error), "Assertion failed: \"%s\", \"%d\" %s \"%d\" in %s() in %s at line %d\n",
message, valueA, equalityType, valueB, funcName, fileName, lineNumber);
} else {
- sprintf(error, "Assertion failed: \"%d\" %s \"%d\" in %s() in %s at line %d\n",
+ snprintf(error, sizeof(error), "Assertion failed: \"%d\" %s \"%d\" in %s() in %s at line %d\n",
valueA, equalityType, valueB, funcName, fileName, lineNumber);
}
@@ -302,137 +307,3 @@
}
return valueA != valueB;
}
-
-
-/**
- * Return the FPGA Version number.
- * For now, expect this to be competition year.
- * @return FPGA Version number.
- */
-UINT16 GetFPGAVersion()
-{
- tRioStatusCode status = 0;
- tGlobal *global = tGlobal::create(&status);
- UINT16 version = global->readVersion(&status);
- delete global;
- wpi_setGlobalError(status);
- return version;
-}
-
-/**
- * Return the FPGA Revision number.
- * The format of the revision is 3 numbers.
- * The 12 most significant bits are the Major Revision.
- * the next 8 bits are the Minor Revision.
- * The 12 least significant bits are the Build Number.
- * @return FPGA Revision number.
- */
-UINT32 GetFPGARevision()
-{
- tRioStatusCode status = 0;
- tGlobal *global = tGlobal::create(&status);
- UINT32 revision = global->readRevision(&status);
- delete global;
- wpi_setGlobalError(status);
- return revision;
-}
-
-/**
- * Read the microsecond-resolution timer on the FPGA.
- *
- * @return The current time in microseconds according to the FPGA (since FPGA reset).
- */
-UINT32 GetFPGATime()
-{
- tRioStatusCode status = 0;
- tGlobal *global = tGlobal::create(&status);
- UINT32 time = global->readLocalTime(&status);
- delete global;
- wpi_setGlobalError(status);
- return time;
-}
-
-// RT hardware access functions exported from ni_emb.out
-extern "C"
-{
- INT32 UserSwitchInput(INT32 nSwitch);
- INT32 LedInput(INT32 led);
- INT32 LedOutput(INT32 led, INT32 value);
-}
-
-/**
- * Read the value of the USER1 DIP switch on the cRIO.
- */
-INT32 GetRIOUserSwitch()
-{
- INT32 switchValue = UserSwitchInput(0);
- wpi_assert(switchValue >= 0);
- return switchValue > 0;
-}
-
-/**
- * Set the state of the USER1 status LED on the cRIO.
- */
-void SetRIOUserLED(UINT32 state)
-{
- LedOutput(0, state > 0);
-}
-
-/**
- * Get the current state of the USER1 status LED on the cRIO.
- * @return The curent state of the USER1 LED.
- */
-INT32 GetRIOUserLED()
-{
- return LedInput(0);
-}
-
-/**
- * Toggle the state of the USER1 status LED on the cRIO.
- * @return The new state of the USER1 LED.
- */
-INT32 ToggleRIOUserLED()
-{
- INT32 ledState = !GetRIOUserLED();
- SetRIOUserLED(ledState);
- return ledState;
-}
-
-/**
- * Set the state of the FPGA status LED on the cRIO.
- */
-void SetRIO_FPGA_LED(UINT32 state)
-{
- tRioStatusCode status = 0;
- tGlobal *global = tGlobal::create(&status);
- global->writeFPGA_LED(state, &status);
- wpi_setGlobalError(status);
- delete global;
-}
-
-/**
- * Get the current state of the FPGA status LED on the cRIO.
- * @return The curent state of the FPGA LED.
- */
-INT32 GetRIO_FPGA_LED()
-{
- tRioStatusCode status = 0;
- tGlobal *global = tGlobal::create(&status);
- bool ledValue = global->readFPGA_LED(&status);
- wpi_setGlobalError(status);
- delete global;
- return ledValue;
-}
-
-/**
- * Toggle the state of the FPGA status LED on the cRIO.
- * @return The new state of the FPGA LED.
- */
-INT32 ToggleRIO_FPGA_LED()
-{
- INT32 ledState = !GetRIO_FPGA_LED();
- SetRIO_FPGA_LED(ledState);
- return ledState;
-}
-
-
diff --git a/aos/externals/WPILib/WPILib/Utility.h b/aos/externals/WPILib/WPILib/Utility.h
index 01bcbff..4462b7c 100644
--- a/aos/externals/WPILib/WPILib/Utility.h
+++ b/aos/externals/WPILib/WPILib/Utility.h
@@ -22,20 +22,10 @@
bool wpi_assertEqual_impl(int valueA, int valueB, const char *message, const char *fileName,UINT32 lineNumber, const char *funcName);
bool wpi_assertNotEqual_impl(int valueA, int valueB, const char *message, const char *fileName,UINT32 lineNumber, const char *funcName);
-char *wpi_getLabel(UINT addr, INT32 *found = NULL);
+// Will use up to (DBG_DEMANGLE_PRINT_LEN + 1 + 11) of label.
+void wpi_getLabel(UINT addr, char *label, INT32 *found = NULL);
void wpi_selfTrace();
void wpi_suspendOnAssertEnabled(bool enabled);
void wpi_stackTraceOnAssertEnable(bool enabled);
-UINT16 GetFPGAVersion();
-UINT32 GetFPGARevision();
-UINT32 GetFPGATime();
-INT32 GetRIOUserSwitch();
-void SetRIOUserLED(UINT32 state);
-INT32 GetRIOUserLED();
-INT32 ToggleRIOUserLED();
-void SetRIO_FPGA_LED(UINT32 state);
-INT32 GetRIO_FPGA_LED();
-INT32 ToggleRIO_FPGA_LED();
-
#endif // UTILITY_H_
diff --git a/aos/externals/WPILib/WPILib/networktables2/stream/FDIOStream.cpp b/aos/externals/WPILib/WPILib/networktables2/stream/FDIOStream.cpp
index 35d3c41..5f9fa3e 100644
--- a/aos/externals/WPILib/WPILib/networktables2/stream/FDIOStream.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/stream/FDIOStream.cpp
@@ -12,7 +12,7 @@
#include <errno.h>
#include <stdlib.h>
#ifdef _WRS_KERNEL
-#include <iolib.h>
+#include <ioLib.h>
#else
#include <unistd.h>
#endif
diff --git a/doc/wpilib-issues.txt b/doc/wpilib-issues.txt
new file mode 100644
index 0000000..1b46940
--- /dev/null
+++ b/doc/wpilib-issues.txt
@@ -0,0 +1,6 @@
+sprintf
+ErrorBase/Error not thread safe (aka CANJaguar)
+all of the sync issues last year
+Module not thread safe
+
+compressor turned on as soon as power was turned on (2 times in a row)
diff --git a/frc971/crio/crio.gyp b/frc971/crio/crio.gyp
index 9542e0b..62d88bc 100644
--- a/frc971/crio/crio.gyp
+++ b/frc971/crio/crio.gyp
@@ -6,6 +6,7 @@
'type': 'static_library',
'dependencies': [
'<(EXTERNALS):WPILib',
+ '<(EXTERNALS):libgcc-4.5.2',
],
},
{