merging in new and improved claw code
diff --git a/aos/build/queues/compiler.rb b/aos/build/queues/compiler.rb
index e4312fd..58b2bf1 100644
--- a/aos/build/queues/compiler.rb
+++ b/aos/build/queues/compiler.rb
@@ -88,6 +88,7 @@
cpp_tree.add_cc_include("aos/common/inttypes.h".inspect)
cpp_tree.add_cc_include("aos/common/queue_types.h".inspect)
cpp_tree.add_cc_include("aos/common/once.h".inspect)
+ cpp_tree.add_cc_include("aos/common/logging/logging_printf_formats.h".inspect)
cpp_tree.add_cc_using("::aos::to_network")
cpp_tree.add_cc_using("::aos::to_host")
diff --git a/aos/build/queues/objects/queue.rb b/aos/build/queues/objects/queue.rb
index 1199cc2..610bdf7 100644
--- a/aos/build/queues/objects/queue.rb
+++ b/aos/build/queues/objects/queue.rb
@@ -3,10 +3,11 @@
def initialize(type_name,name,length = nil) #lengths are for arrays
@type_name = type_name
@type = type_name.to_s
+ @type = '::aos::time::Time' if @type == 'Time'
@name = name
@length = length
end
- CommonMistakes = {"short" => "int16_t","int" => "int32_t","long" => "int64_t"}
+ CommonMistakes = {"short" => "int16_t","int" => "int32_t","long" => "int64_t","time" => "Time"}
def check_type_error(locals)
if(!(Sizes[@type] || (@length != nil && @type == "char")) )
if(correction = CommonMistakes[@type])
@@ -48,7 +49,8 @@
"int8_t" => "%\" PRId8 \"",
"int16_t" => "%\" PRId16 \"",
"int32_t" => "%\" PRId32 \"",
- "int64_t" => "%\" PRId64 \""}
+ "int64_t" => "%\" PRId64 \"",
+ "::aos::time::Time" => "\" AOS_TIME_FORMAT \""}
def toPrintFormat()
if(format = PrintFormat[@type])
return format;
@@ -60,12 +62,12 @@
ERROR_MSG
end
- Sizes = {"bool" => 1, "float" => 4,"double" => 8}
+ Sizes = {"bool" => 1, "float" => 4,"double" => 8,"::aos::time::Time" => 8}
[8,16,32,64].each do |len|
Sizes["int#{len}_t"] = len / 8
Sizes["uint#{len}_t"] = len / 8
end
- Zero = {"float" => "0.0f","double" => "0.0","bool" => "false"}
+ Zero = {"float" => "0.0f","double" => "0.0","bool" => "false","::aos::time::Time" => "::aos::time::Time(0, 0)"}
def size()
if(size = Sizes[@type]); return size; end
return 1 if(@type == "char")
diff --git a/aos/build/queues/output/message_dec.rb b/aos/build/queues/output/message_dec.rb
index 59e2f35..40a2570 100644
--- a/aos/build/queues/output/message_dec.rb
+++ b/aos/build/queues/output/message_dec.rb
@@ -301,6 +301,8 @@
def fetchPrintArgs(args, parent = "")
if (self.type == 'bool')
args.push("#{parent}#{self.name} ? 'T' : 'f'")
+ elsif (self.type == '::aos::time::Time')
+ args.push("AOS_TIME_ARGS(#{parent}#{self.name}.sec(), #{parent}#{self.name}.nsec())")
else
args.push("#{parent}#{self.name}")
end
diff --git a/aos/build/queues/print_field.rb b/aos/build/queues/print_field.rb
index a86140f..c7b8530 100644
--- a/aos/build/queues/print_field.rb
+++ b/aos/build/queues/print_field.rb
@@ -1,8 +1,8 @@
require File.dirname(__FILE__) + '/load.rb'
-TypeNames = [8, 16, 32, 64].collect do |size|
- ["uint#{size}_t", "int#{size}_t"]
-end.flatten + ['bool', 'float', 'char', 'double']
+# TODO(brians): Special-case Time too and float/double if we can find a good way to do it.
+GenericTypeNames = ['float', 'double', 'char', '::aos::time::Time']
+IntegerSizes = [8, 16, 32, 64]
WriteIffChanged.open(ARGV[0]) do |output|
output.puts <<END
@@ -15,13 +15,16 @@
#include <stdio.h>
#include "aos/common/byteorder.h"
+#include "aos/common/time.h"
+#include "aos/common/print_field_helpers.h"
+#include "aos/common/logging/logging_printf_formats.h"
namespace aos {
bool PrintField(char *output, size_t *output_bytes, const void *input,
size_t *input_bytes, uint32_t type) {
switch (type) {
-#{TypeNames.collect do |name|
+#{GenericTypeNames.collect do |name|
message_element = Target::MessageElement.new(name, 'value')
statement = MessageElementStmt.new(name, 'value')
message_element.size = statement.size
@@ -39,11 +42,45 @@
#{print_args[0]});
if (ret < 0) return false;
if (static_cast<unsigned int>(ret) >= *output_bytes) return false;
- *output_bytes -= ret + 1;
+ *output_bytes -= ret;
return true;
}
END2
end.join('')}
+#{IntegerSizes.collect do |size|
+ [true, false].collect do |signed|
+ size_bytes = size / 8
+ name = "#{signed ? '' : 'u'}int#{size}_t"
+ message_element = Target::MessageElement.new(name, 'value')
+ message_element.size = size_bytes
+ next <<END2
+ case #{message_element.getTypeID()}:
+ {
+ if (*input_bytes < #{size_bytes}) return false;
+ *input_bytes -= #{size_bytes};
+ #{name} value;
+ to_host(static_cast<const char *>(input), &value);
+ return PrintInteger<#{name}>(output, value, output_bytes);
+ }
+END2
+ end
+end.flatten.join('')}
+#{
+ message_element = Target::MessageElement.new('bool', 'value')
+ message_element.size = 1
+ r = <<END2
+ case #{message_element.getTypeID()}:
+ {
+ if (*input_bytes < 1) return false;
+ if (*output_bytes < 1) return false;
+ *input_bytes -= 1;
+ bool value = static_cast<const char *>(input)[0];
+ *output_bytes += 1;
+ *output = value ? 'T' : 'f';
+ return true;
+ }
+END2
+}
default:
return false;
}
diff --git a/aos/build/queues/queue_primitives.rb b/aos/build/queues/queue_primitives.rb
index 2c9594e..421c3b4 100644
--- a/aos/build/queues/queue_primitives.rb
+++ b/aos/build/queues/queue_primitives.rb
@@ -4,7 +4,7 @@
TypeNames = [8, 16, 32, 64].collect do |size|
["uint#{size}_t", "int#{size}_t"]
-end.flatten + ['bool', 'float', 'char', 'double']
+end.flatten + ['bool', 'float', 'char', 'double', '::aos::time::Time']
FileUtils.mkdir_p(File.dirname(ARGV[0]))
WriteIffChanged.open(ARGV[0]) do |output|
@@ -14,12 +14,15 @@
#include <stdint.h>
+#include "aos/common/time.h"
+
namespace aos {
namespace queue_primitive_types {
#{TypeNames.collect do |name|
message_element = Target::MessageElement.new(name, 'value')
statement = MessageElementStmt.new(name, 'value')
message_element.size = statement.size
+ name = 'Time' if name == '::aos::time::Time'
next <<END2
static const uint32_t #{name}_p = #{message_element.getTypeID()};
END2
@@ -40,7 +43,7 @@
message_element.size = statement.size
next <<END2
template<>
-class TypeID<#{name}> {
+class TypeID< #{name}> {
public:
static const uint32_t id = #{message_element.getTypeID()};
};
diff --git a/aos/common/common.gyp b/aos/common/common.gyp
index 8847d40..4b9d602 100644
--- a/aos/common/common.gyp
+++ b/aos/common/common.gyp
@@ -57,6 +57,10 @@
'<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:shared_mem',
'<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:core_lib',
'mutex',
+ 'time',
+ ],
+ 'export_dependent_settings': [
+ 'time',
],
'actions': [
{
@@ -231,6 +235,8 @@
'test_queue',
'<(AOS)/common/util/util.gyp:thread',
'die',
+ # We want to run it with the assertions etc to try and catch bugs there.
+ '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:queue_debug',
],
},
{
diff --git a/aos/common/logging/logging.h b/aos/common/logging/logging.h
index 673cc9a..114007b 100644
--- a/aos/common/logging/logging.h
+++ b/aos/common/logging/logging.h
@@ -8,6 +8,8 @@
#include <stdint.h>
#include <stdlib.h>
+#include "aos/common/macros.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -28,9 +30,6 @@
DECL_LEVELS;
#undef DECL_LEVEL
-#define STRINGIFY(x) TO_STRING(x)
-#define TO_STRING(x) #x
-
// Not static const size_t for C code.
#define LOG_MESSAGE_LEN 400
diff --git a/aos/common/logging/logging_impl.cc b/aos/common/logging/logging_impl.cc
index b74b69d..e7b0a5e 100644
--- a/aos/common/logging/logging_impl.cc
+++ b/aos/common/logging/logging_impl.cc
@@ -7,6 +7,7 @@
#include "aos/common/inttypes.h"
#include "aos/common/once.h"
#include "aos/common/queue_types.h"
+#include "aos/common/logging/logging_printf_formats.h"
namespace aos {
namespace logging {
@@ -138,17 +139,13 @@
}
void PrintMessage(FILE *output, const LogMessage &message) {
-#define NSECONDS_DIGITS 5
-#define BASE_FORMAT \
- "%.*s(%" PRId32 ")(%05" PRIu16 "): %-7s at %010" PRId32 \
- ".%0" STRINGIFY(NSECONDS_DIGITS) PRId32 "s: "
-#define BASE_ARGS \
- static_cast<int>(message.name_length), message.name, \
- static_cast<int32_t>(message.source), message.sequence, \
- log_str(message.level), message.seconds, (message.nseconds + 5000) / 10000
- switch (message.type) {
+#define BASE_ARGS \
+ AOS_LOGGING_BASE_ARGS( \
+ message.name_length, message.name, static_cast<int32_t>(message.source), \
+ message.sequence, message.level, message.seconds, message.nseconds)
+ switch (message.type) {
case LogMessage::Type::kString:
- fprintf(output, BASE_FORMAT "%.*s", BASE_ARGS,
+ fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s", BASE_ARGS,
static_cast<int>(message.message_length), message.message);
break;
case LogMessage::Type::kStruct: {
@@ -169,7 +166,7 @@
LOG(WARNING, "%zu extra bytes on message of type %s\n", input_length,
type_cache::Get(message.structure.type_id).name.c_str());
}
- fprintf(output, BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
+ fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
static_cast<int>(message.structure.string_length),
message.structure.serialized,
static_cast<int>(sizeof(buffer) - output_length), buffer);
@@ -192,14 +189,12 @@
LOG(FATAL, "printing %dx%d matrix of type %" PRIu32 " failed\n",
message.matrix.rows, message.matrix.cols, message.matrix.type);
}
- fprintf(output, BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
+ fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
static_cast<int>(message.matrix.string_length),
message.matrix.data,
static_cast<int>(sizeof(buffer) - output_length), buffer);
} break;
}
-#undef NSECONDS_DIGITS
-#undef BASE_FORMAT
#undef BASE_ARGS
}
diff --git a/aos/common/logging/logging_printf_formats.h b/aos/common/logging/logging_printf_formats.h
new file mode 100644
index 0000000..be186bc
--- /dev/null
+++ b/aos/common/logging/logging_printf_formats.h
@@ -0,0 +1,30 @@
+#ifndef AOS_COMMON_LOGGING_LOGGING_PRINTF_FORMATS_H_
+#define AOS_COMMON_LOGGING_LOGGING_PRINTF_FORMATS_H_
+
+#include "aos/common/macros.h"
+
+// This file has printf(3) formats and corresponding arguments for printing out
+// times and log messages.
+// They are all split out as macros because there are 2 things that want to
+// print using the same format: log_displayer and PrintMessage in
+// logging_impl.cc.
+
+#define AOS_TIME_FORMAT \
+ "%010" PRId32 ".%0" STRINGIFY(AOS_TIME_NSECONDS_DIGITS) PRId32 "s"
+#define AOS_TIME_ARGS(sec, nsec) \
+ sec, (nsec + (AOS_TIME_NSECONDS_DENOMINATOR / 2)) / \
+ AOS_TIME_NSECONDS_DENOMINATOR
+
+#define AOS_LOGGING_BASE_FORMAT \
+ "%.*s(%" PRId32 ")(%05" PRIu16 "): %-7s at " AOS_TIME_FORMAT ": "
+#define AOS_LOGGING_BASE_ARGS(name_length, name, source, sequence, level, sec, \
+ nsec) \
+ static_cast<int>(name_length), name, source, sequence, \
+ ::aos::logging::log_str(level), AOS_TIME_ARGS(sec, nsec)
+
+// These 2 define how many digits we use to print out the nseconds fields of
+// times. They have to stay matching.
+#define AOS_TIME_NSECONDS_DIGITS 5
+#define AOS_TIME_NSECONDS_DENOMINATOR 10000
+
+#endif // AOS_COMMON_LOGGING_LOGGING_PRINTF_FORMATS_H_
diff --git a/aos/common/macros.h b/aos/common/macros.h
index 2018b36..ba23fe4 100644
--- a/aos/common/macros.h
+++ b/aos/common/macros.h
@@ -22,4 +22,7 @@
#define UNUSED_VARIABLE
#endif
+#define STRINGIFY(x) TO_STRING(x)
+#define TO_STRING(x) #x
+
#endif // _AOS_COMMON_MACROS_H_
diff --git a/aos/common/print_field_helpers.h b/aos/common/print_field_helpers.h
new file mode 100644
index 0000000..48acdf6
--- /dev/null
+++ b/aos/common/print_field_helpers.h
@@ -0,0 +1,41 @@
+#ifndef AOS_COMMON_PRINT_FIELD_HELPERS_H_
+#define AOS_COMMON_PRINT_FIELD_HELPERS_H_
+
+#include <stdint.h>
+
+#include <type_traits>
+
+namespace aos {
+
+template<typename T>
+inline bool PrintInteger(char *buf, T val, size_t *output) {
+ static const bool is_signed = ::std::is_signed<T>::value;
+
+ size_t len = 0;
+ if (is_signed && val <= 0) {
+ while (*output > len && (val != 0 || len == 0)) {
+ buf[len++] = '0' - (val % 10);
+ val /= 10;
+ }
+ buf[len++] = '-';
+ } else {
+ while (*output > len && (val != 0 || len == 0)) {
+ buf[len++] = '0' + (val % 10);
+ val /= 10;
+ }
+ }
+ // If we have enough space.
+ if (*output >= len) {
+ for (size_t i = 0; i < (len >> 1); i++) {
+ std::swap(buf[len - 1 - i], buf[i]);
+ }
+ *output -= len;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+} // namespace aos
+
+#endif // AOS_COMMON_PRINT_FIELD_HELPERS_H_
diff --git a/aos/common/queue_types.cc b/aos/common/queue_types.cc
index 93cf135..8c22d90 100644
--- a/aos/common/queue_types.cc
+++ b/aos/common/queue_types.cc
@@ -148,12 +148,12 @@
type_cache::Get(type.fields[i]->type))) {
return false;
}
+ // Ignore the trailing '\0' that the subcall put on.
+ output -= 1;
}
- // Update the input and output pointers, ignoring the trailing '\0' that the
- // subcall put on.
- output += output_bytes_before - *output_bytes - 1;
- *output_bytes += 1;
+ // Update the input and output pointers.
+ output += output_bytes_before - *output_bytes;
input =
static_cast<const char *>(input) + input_bytes_before - *input_bytes;
}
@@ -208,10 +208,8 @@
return false;
}
CHECK_EQ(0u, input_bytes);
- // Update the output pointer, ignoring the trailing '\0' that
- // the subcall put on.
- output += output_bytes_before - *output_bytes - 1;
- *output_bytes += 1;
+ // Update the output pointer.
+ output += output_bytes_before - *output_bytes;
}
if (*output_bytes < 1) return false;
diff --git a/aos/common/queue_types.h b/aos/common/queue_types.h
index b95c946..eb0527e 100644
--- a/aos/common/queue_types.h
+++ b/aos/common/queue_types.h
@@ -102,6 +102,7 @@
//
// Prints the value from 1 primitive message field into output.
// The implementation of this is generated by the ruby code.
+// Does not include a trailing '\0' in what it subtracts from *output_bytes.
bool PrintField(char *output, size_t *output_bytes, const void *input,
size_t *input_bytes, uint32_t type)
__attribute__((warn_unused_result));
diff --git a/aos/common/time.h b/aos/common/time.h
index c646661..ca1d207 100644
--- a/aos/common/time.h
+++ b/aos/common/time.h
@@ -47,7 +47,7 @@
static const int32_t kNSecInUSec = 1000;
static const int32_t kMSecInSec = 1000;
static const int32_t kUSecInSec = 1000000;
- constexpr Time(int32_t sec, int32_t nsec)
+ constexpr Time(int32_t sec = 0, int32_t nsec = 0)
: sec_(sec), nsec_(CheckConstexpr(nsec)) {
}
#ifndef SWIG
diff --git a/aos/externals/WPILib/WPILib.a b/aos/externals/WPILib/WPILib.a
deleted file mode 100644
index 27cc22f..0000000
--- a/aos/externals/WPILib/WPILib.a
+++ /dev/null
Binary files differ
diff --git a/aos/externals/WPILib/WPILib/DriverStation.cpp b/aos/externals/WPILib/WPILib/DriverStation.cpp
index dfd92c0..e90beae 100644
--- a/aos/externals/WPILib/WPILib/DriverStation.cpp
+++ b/aos/externals/WPILib/WPILib/DriverStation.cpp
@@ -158,11 +158,11 @@
}
if (!lastEnabled && IsEnabled())
{
- // If starting teleop, assume that autonomous just took up 15 seconds
+ // If starting teleop, assume that autonomous just took up 10 seconds
if (IsAutonomous())
m_approxMatchTimeOffset = Timer::GetFPGATimestamp();
else
- m_approxMatchTimeOffset = Timer::GetFPGATimestamp() - 15.0;
+ m_approxMatchTimeOffset = Timer::GetFPGATimestamp() - 10.0;
}
else if (lastEnabled && !IsEnabled())
{
diff --git a/aos/externals/WPILib/WPILib/RobotBase.cpp b/aos/externals/WPILib/WPILib/RobotBase.cpp
index 393b397..a42938b 100644
--- a/aos/externals/WPILib/WPILib/RobotBase.cpp
+++ b/aos/externals/WPILib/WPILib/RobotBase.cpp
@@ -19,7 +19,7 @@
RobotBase* RobotBase::m_instance = NULL;
const char *FILE_NAME = "/c/FRC_Lib_Version.ini";
-const char *VERSION_STRING = "C++ 2014 Update 0";
+const char *VERSION_STRING = "C++ 2014 Update 1";
void RobotBase::setInstance(RobotBase* robot)
diff --git a/aos/externals/WPILib/WPILib/Scripts/CopyWPILibToUpdateDirectory.cmd b/aos/externals/WPILib/WPILib/Scripts/CopyWPILibToUpdateDirectory.cmd
index 2445cce..26ecc83 100644
--- a/aos/externals/WPILib/WPILib/Scripts/CopyWPILibToUpdateDirectory.cmd
+++ b/aos/externals/WPILib/WPILib/Scripts/CopyWPILibToUpdateDirectory.cmd
@@ -6,7 +6,7 @@
mkdir vxworks-6.3\target\h\WPILib\CAN
mkdir vxworks-6.3\target\h\WPILib\ChipObject
mkdir vxworks-6.3\target\h\WPILib\ChipObject\fpgainterfacecapi
-mkdir vxworks-6.3\target\h\WPILib\CInterfaces
+mkdir vxworks-6.3\target\h\WPILib\Interfaces
mkdir vxworks-6.3\target\h\WPILib\Commands
mkdir vxworks-6.3\target\h\WPILib\NetworkCommunication
mkdir vxworks-6.3\target\h\WPILib\SmartDashboard
@@ -32,7 +32,7 @@
del vxworks-6.3\target\h\WPIlib\Buttons\*.h
del vxworks-6.3\target\h\WPIlib\CAN\*.h
del vxworks-6.3\target\h\WPIlib\ChipObject\*.h
-del vxworks-6.3\target\h\WPIlib\CInterfaces\*.h
+del vxworks-6.3\target\h\WPIlib\Interfaces\*.h
del vxworks-6.3\target\h\WPIlib\Commands\*.h
del vxworks-6.3\target\h\WPIlib\NetworkCommunication\*.h
del vxworks-6.3\target\h\WPIlib\SmartDashboard\*.h
@@ -61,7 +61,7 @@
copy C:\WindRiver\workspace\WPILib\CAN\*.h vxworks-6.3\target\h\WPILib\CAN
copy C:\WindRiver\workspace\WPILib\ChipObject\*.h vxworks-6.3\target\h\WPILib\ChipObject
copy C:\WindRiver\workspace\WPILib\ChipObject\fpgainterfacecapi\*.h vxworks-6.3\target\h\WPILib\ChipObject\fpgainterfacecapi
-copy C:\WindRiver\workspace\WPILib\CInterfaces\*.h vxworks-6.3\target\h\WPILib\CInterfaces
+copy C:\WindRiver\workspace\WPILib\Interfaces\*.h vxworks-6.3\target\h\WPILib\Interfaces
copy C:\WindRiver\workspace\WPILib\Commands\*.h vxworks-6.3\target\h\WPILib\Commands
copy C:\WindRiver\workspace\WPILib\NetworkCommunication\*.h vxworks-6.3\target\h\WPILib\NetworkCommunication
copy C:\WindRiver\workspace\WPILib\SmartDashboard\*.h vxworks-6.3\target\h\WPILib\SmartDashboard
diff --git a/aos/externals/WPILib/WPILib/SerialPort.cpp b/aos/externals/WPILib/WPILib/SerialPort.cpp
index 7a1047e..f948f0a 100644
--- a/aos/externals/WPILib/WPILib/SerialPort.cpp
+++ b/aos/externals/WPILib/WPILib/SerialPort.cpp
@@ -183,13 +183,18 @@
uint32_t retCount = 0;
if (!m_consoleModeEnabled)
{
- ViStatus localStatus = viBufRead(m_portHandle, (ViPBuf)buffer, count, (ViPUInt32)&retCount);
+ ViStatus localStatus = viRead(m_portHandle, (ViPBuf)buffer, count, (ViPUInt32)&retCount);
switch (localStatus)
{
case VI_SUCCESS_TERM_CHAR:
case VI_SUCCESS_MAX_CNT:
case VI_ERROR_TMO: // Timeout
break;
+ case VI_ERROR_IO:
+ case VI_ERROR_ASRL_OVERRUN:
+ wpi_setError(localStatus);
+ Reset();
+ break;
default:
wpi_setError(localStatus);
}
@@ -209,7 +214,7 @@
uint32_t retCount = 0;
if (!m_consoleModeEnabled)
{
- ViStatus localStatus = viBufWrite(m_portHandle, (ViPBuf)buffer, count, (ViPUInt32)&retCount);
+ ViStatus localStatus = viWrite(m_portHandle, (ViPBuf)buffer, count, (ViPUInt32)&retCount);
wpi_setError(localStatus);
}
return retCount;
diff --git a/aos/externals/WPILib/WPILib/networktables2/AbstractNetworkTableEntryStore.cpp b/aos/externals/WPILib/WPILib/networktables2/AbstractNetworkTableEntryStore.cpp
index 00829a0..8d268b2 100644
--- a/aos/externals/WPILib/WPILib/networktables2/AbstractNetworkTableEntryStore.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/AbstractNetworkTableEntryStore.cpp
@@ -32,7 +32,7 @@
*/
NetworkTableEntry* AbstractNetworkTableEntryStore::GetEntry(std::string& name){
{
- NTSynchronized sync(LOCK);
+ NTSynchronized sync(block_namedEntries);
std::map<std::string, NetworkTableEntry*>::iterator value_itr = namedEntries.find(name);
if(value_itr != namedEntries.end()) {
return value_itr->second;
@@ -43,7 +43,7 @@
NetworkTableEntry* AbstractNetworkTableEntryStore::GetEntry(EntryId entryId){
{
- NTSynchronized sync(LOCK);
+ NTSynchronized sync(block_namedEntries);
std::map<EntryId, NetworkTableEntry*>::iterator value_itr = idEntries.find(entryId);
if(value_itr != idEntries.end()) {
@@ -55,7 +55,7 @@
std::vector<std::string>* AbstractNetworkTableEntryStore::keys(){
{
- NTSynchronized sync(LOCK);
+ NTSynchronized sync(block_namedEntries);
std::vector<std::string>* keys = new std::vector<std::string>();
std::map<std::string, NetworkTableEntry*>::iterator itr;
@@ -77,7 +77,7 @@
*/
void AbstractNetworkTableEntryStore::clearEntries(){
{
- NTSynchronized sync(LOCK);
+ NTSynchronized sync(block_namedEntries);
namedEntries.clear();
idEntries.clear();
}
@@ -88,7 +88,7 @@
*/
void AbstractNetworkTableEntryStore::clearIds(){
{
- NTSynchronized sync(LOCK);
+ NTSynchronized sync(block_namedEntries);
std::map<std::string, NetworkTableEntry*>::iterator itr;
idEntries.clear();
@@ -119,7 +119,7 @@
*/
void AbstractNetworkTableEntryStore::PutOutgoing(std::string& name, NetworkTableEntryType* type, EntryValue value){
{
- NTSynchronized sync(LOCK);
+ NTSynchronized sync(block_namedEntries);
std::map<std::string, NetworkTableEntry*>::iterator index = namedEntries.find(name);
NetworkTableEntry* tableEntry;
if(index == namedEntries.end())//if the name does not exist in the current entries
@@ -167,7 +167,7 @@
void AbstractNetworkTableEntryStore::offerIncomingAssignment(NetworkTableEntry* entry){
{
- NTSynchronized sync(LOCK);
+ NTSynchronized sync(block_namedEntries);
std::map<std::string, NetworkTableEntry*>::iterator itr = namedEntries.find(entry->name);
NetworkTableEntry* tableEntry;
if(addEntry(entry)){
@@ -203,7 +203,7 @@
*/
void AbstractNetworkTableEntryStore::notifyEntries(ITable* table, ITableListener* listener){
{
- NTSynchronized sync(LOCK);
+ NTSynchronized sync(block_namedEntries);
std::map<std::string, NetworkTableEntry*>::iterator itr;
for(itr = namedEntries.begin(); itr != namedEntries.end(); itr++)
{
diff --git a/aos/externals/WPILib/WPILib/networktables2/AbstractNetworkTableEntryStore.h b/aos/externals/WPILib/WPILib/networktables2/AbstractNetworkTableEntryStore.h
index b394cfb..7d6903f 100644
--- a/aos/externals/WPILib/WPILib/networktables2/AbstractNetworkTableEntryStore.h
+++ b/aos/externals/WPILib/WPILib/networktables2/AbstractNetworkTableEntryStore.h
@@ -36,6 +36,7 @@
class AbstractNetworkTableEntryStore : public IncomingEntryReceiver{
protected:
std::map<EntryId,NetworkTableEntry*> idEntries;
+ NTReentrantSemaphore block_namedEntries;
std::map<std::string,NetworkTableEntry*> namedEntries;
TableListenerManager& listenerManager;
diff --git a/aos/externals/WPILib/WPILib/networktables2/NetworkTableEntry.cpp b/aos/externals/WPILib/WPILib/networktables2/NetworkTableEntry.cpp
index 9538c91..658c7c7 100644
--- a/aos/externals/WPILib/WPILib/networktables2/NetworkTableEntry.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/NetworkTableEntry.cpp
@@ -20,6 +20,17 @@
m_isDirty = false;
}
+NetworkTableEntry::NetworkTableEntry(const NetworkTableEntry &other) :
+ name(other.name),
+ id(other.id),
+ sequenceNumber(other.sequenceNumber),
+ type(other.type),
+ m_isNew(other.m_isNew),
+ m_isDirty(other.m_isDirty)
+{
+ value = type->copyValue(other.value);
+}
+
NetworkTableEntry::~NetworkTableEntry(){
type->deleteValue(value);
}
diff --git a/aos/externals/WPILib/WPILib/networktables2/NetworkTableEntry.h b/aos/externals/WPILib/WPILib/networktables2/NetworkTableEntry.h
index 2a29004..27223e4 100644
--- a/aos/externals/WPILib/WPILib/networktables2/NetworkTableEntry.h
+++ b/aos/externals/WPILib/WPILib/networktables2/NetworkTableEntry.h
@@ -42,6 +42,7 @@
NetworkTableEntry(std::string& name, NetworkTableEntryType* type, EntryValue value);
NetworkTableEntry(EntryId id, std::string& name, SequenceNumber sequenceNumber, NetworkTableEntryType* type, EntryValue value);
+ NetworkTableEntry(const NetworkTableEntry &);
virtual ~NetworkTableEntry();
EntryId GetId();
diff --git a/aos/externals/WPILib/WPILib/networktables2/WriteManager.cpp b/aos/externals/WPILib/WPILib/networktables2/WriteManager.cpp
index bbe08f5..64688e3 100644
--- a/aos/externals/WPILib/WPILib/networktables2/WriteManager.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/WriteManager.cpp
@@ -54,10 +54,15 @@
void WriteManager::offerOutgoingAssignment(NetworkTableEntry* entry) {
{
- NTSynchronized sync(transactionsLock);
- ((std::queue<NetworkTableEntry*>*)incomingAssignmentQueue)->push(entry);
-
- if(((std::queue<NetworkTableEntry*>*)incomingAssignmentQueue)->size()>=queueSize){
+ bool test_queue_overflow=false;
+ {
+ NTSynchronized sync(transactionsLock);
+ ((std::queue<NetworkTableEntry*>*)incomingAssignmentQueue)->push(entry);
+
+ test_queue_overflow=(((std::queue<NetworkTableEntry*>*)incomingAssignmentQueue)->size()>=queueSize);
+ }
+ if (test_queue_overflow)
+ {
run();
writeWarning("assignment queue overflowed. decrease the rate at which you create new entries or increase the write buffer size");
}
@@ -67,9 +72,15 @@
void WriteManager::offerOutgoingUpdate(NetworkTableEntry* entry) {
{
- NTSynchronized sync(transactionsLock);
- ((std::queue<NetworkTableEntry*>*)incomingUpdateQueue)->push(entry);
- if(((std::queue<NetworkTableEntry*>*)incomingUpdateQueue)->size()>=queueSize){
+ bool test_queue_overflow=false;
+ {
+ NTSynchronized sync(transactionsLock);
+ ((std::queue<NetworkTableEntry*>*)incomingUpdateQueue)->push(entry);
+ test_queue_overflow=(((std::queue<NetworkTableEntry*>*)incomingUpdateQueue)->size()>=queueSize);
+
+ }
+ if (test_queue_overflow)
+ {
run();
writeWarning("update queue overflowed. decrease the rate at which you update entries or increase the write buffer size");
}
@@ -97,10 +108,17 @@
entry = ((std::queue<NetworkTableEntry*>*)outgoingAssignmentQueue)->front();
((std::queue<NetworkTableEntry*>*)outgoingAssignmentQueue)->pop();
{
- NTSynchronized sync(entryStore.LOCK);
- entry->MakeClean();
- wrote = true;
- receiver.offerOutgoingAssignment(entry);
+ NetworkTableEntry * entryCopy;
+
+ {
+ NTSynchronized sync(entryStore.LOCK);
+ entry->MakeClean();
+ wrote = true;
+ entryCopy = new NetworkTableEntry(*entry);
+ }
+
+ receiver.offerOutgoingAssignment(entryCopy);
+ delete entryCopy;
}
}
@@ -108,10 +126,17 @@
entry = ((std::queue<NetworkTableEntry*>*)outgoingUpdateQueue)->front();
((std::queue<NetworkTableEntry*>*)outgoingUpdateQueue)->pop();
{
- NTSynchronized sync(entryStore.LOCK);
- entry->MakeClean();
- wrote = true;
- receiver.offerOutgoingUpdate(entry);
+ NetworkTableEntry * entryCopy;
+
+ {
+ NTSynchronized sync(entryStore.LOCK);
+ entry->MakeClean();
+ wrote = true;
+ entryCopy = new NetworkTableEntry(*entry);
+ }
+
+ receiver.offerOutgoingUpdate(entryCopy);
+ delete entryCopy;
}
}
diff --git a/aos/externals/WPILib/WPILib/networktables2/client/ClientNetworkTableEntryStore.cpp b/aos/externals/WPILib/WPILib/networktables2/client/ClientNetworkTableEntryStore.cpp
index d2fc19d..15c0e1f 100644
--- a/aos/externals/WPILib/WPILib/networktables2/client/ClientNetworkTableEntryStore.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/client/ClientNetworkTableEntryStore.cpp
@@ -17,7 +17,7 @@
bool ClientNetworkTableEntryStore::addEntry(NetworkTableEntry* newEntry){
{
- NTSynchronized sync(LOCK);
+ NTSynchronized sync(block_namedEntries);
NetworkTableEntry* entry = (NetworkTableEntry*)namedEntries[newEntry->name];
if(entry!=NULL){
diff --git a/aos/externals/WPILib/WPILib/networktables2/connection/NetworkTableConnection.cpp b/aos/externals/WPILib/WPILib/networktables2/connection/NetworkTableConnection.cpp
index 6f675b0..13c61fc 100644
--- a/aos/externals/WPILib/WPILib/networktables2/connection/NetworkTableConnection.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/connection/NetworkTableConnection.cpp
@@ -19,6 +19,7 @@
void NetworkTableConnection::SetIOStream(IOStream* stream)
{
+ isValid=(stream!=NULL);
ioStream->SetIOStream(stream); //just passing through
}
@@ -102,7 +103,7 @@
}
void NetworkTableConnection::read(ConnectionAdapter& adapter) {
- int messageType = ioStream->readByte();
+ int messageType = (isValid)?ioStream->readByte():KEEP_ALIVE;
switch (messageType) {
case KEEP_ALIVE:
adapter.keepAlive();
diff --git a/aos/externals/WPILib/WPILib/networktables2/server/NetworkTableServer.cpp b/aos/externals/WPILib/WPILib/networktables2/server/NetworkTableServer.cpp
index ea85356..a0f3677 100644
--- a/aos/externals/WPILib/WPILib/networktables2/server/NetworkTableServer.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/server/NetworkTableServer.cpp
@@ -35,6 +35,9 @@
void NetworkTableServer::Close(){
try{
+ //Note: streamProvider must come before the incomingStreamMonitor so the that task can complete first for the thread to close
+ // [9/1/2013 Terminator]
+ streamProvider.close();
incomingStreamMonitor.stop();
writeManager.stop();
connectionList.closeAll();
diff --git a/aos/externals/WPILib/WPILib/networktables2/server/ServerConnectionAdapter.cpp b/aos/externals/WPILib/WPILib/networktables2/server/ServerConnectionAdapter.cpp
index 195f6e7..62323d8 100644
--- a/aos/externals/WPILib/WPILib/networktables2/server/ServerConnectionAdapter.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/server/ServerConnectionAdapter.cpp
@@ -36,6 +36,9 @@
gotoState(new ServerConnectionState_Error(e));
adapterListener.close(*this, true);
m_IsAdapterListenerClosed=true;
+ if (readThread) {
+ readThread->stop();
+ }
}
void ServerConnectionAdapter::ioException(IOException& e) {
@@ -47,6 +50,9 @@
gotoState(new ServerConnectionState_Error(e));
adapterListener.close(*this, false);
m_IsAdapterListenerClosed=true;
+ if (readThread) {
+ readThread->stop();
+ }
}
diff --git a/aos/externals/WPILib/WPILib/networktables2/server/ServerIncomingStreamMonitor.cpp b/aos/externals/WPILib/WPILib/networktables2/server/ServerIncomingStreamMonitor.cpp
index 51c5733..44bf367 100644
--- a/aos/externals/WPILib/WPILib/networktables2/server/ServerIncomingStreamMonitor.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/server/ServerIncomingStreamMonitor.cpp
@@ -7,6 +7,7 @@
#include "networktables2/server/ServerIncomingStreamMonitor.h"
#include "networktables2/stream/IOStream.h"
+#include "networktables2/util/System.h"
ServerIncomingStreamMonitor::ServerIncomingStreamMonitor(IOStreamProvider& _streamProvider, ServerNetworkTableEntryStore& _entryStore,
ServerIncomingConnectionListener& _incomingListener, ServerAdapterManager& _adapterListener, NetworkTableEntryTypeManager& _typeManager,
@@ -69,6 +70,7 @@
ServerConnectionAdapter* connectionAdapter = new ServerConnectionAdapter(newStream, entryStore, entryStore, adapterListener, typeManager, threadManager);
incomingListener.OnNewConnection(*connectionAdapter);
}
+ sleep_ms(100); //avoid busy wait
}
}
catch (IOException& e)
diff --git a/aos/externals/WPILib/WPILib/networktables2/server/ServerNetworkTableEntryStore.cpp b/aos/externals/WPILib/WPILib/networktables2/server/ServerNetworkTableEntryStore.cpp
index b1d86c9..b49bbf5 100644
--- a/aos/externals/WPILib/WPILib/networktables2/server/ServerNetworkTableEntryStore.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/server/ServerNetworkTableEntryStore.cpp
@@ -18,7 +18,7 @@
bool ServerNetworkTableEntryStore::addEntry(NetworkTableEntry* newEntry)
{
- NTSynchronized sync(LOCK);
+ NTSynchronized sync(block_namedEntries);
NetworkTableEntry* entry = namedEntries[newEntry->name];
if (entry == NULL)
@@ -44,13 +44,20 @@
*/
void ServerNetworkTableEntryStore::sendServerHello(NetworkTableConnection& connection)
{
- NTSynchronized sync(LOCK);
- std::map<std::string, NetworkTableEntry*>::iterator itr;
- for (itr = namedEntries.begin(); itr != namedEntries.end(); itr++)
+ std::vector<NetworkTableEntry *> entry_list;
{
- NetworkTableEntry* entry = itr->second;
- connection.sendEntryAssignment(*entry);
+ NTSynchronized sync(block_namedEntries);
+ std::map<std::string, NetworkTableEntry*>::iterator itr;
+ for (itr = namedEntries.begin(); itr != namedEntries.end(); itr++)
+ {
+ NetworkTableEntry* entry = itr->second;
+ entry_list.push_back(entry);
+ }
}
+
+ for (size_t i=0;i<entry_list.size();i++)
+ connection.sendEntryAssignment(*(entry_list[i]));
+
connection.sendServerHelloComplete();
connection.flush();
}
diff --git a/aos/externals/WPILib/WPILib/networktables2/stream/FDIOStream.cpp b/aos/externals/WPILib/WPILib/networktables2/stream/FDIOStream.cpp
index da8e13d..55e2ac2 100644
--- a/aos/externals/WPILib/WPILib/networktables2/stream/FDIOStream.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/stream/FDIOStream.cpp
@@ -11,13 +11,8 @@
#include <errno.h>
#include <stdlib.h>
-#ifdef _WRS_KERNEL
#include <ioLib.h>
#include <selectLib.h>
-#else
-#include <unistd.h>
-#include <sys/time.h>
-#endif
#include <string.h>
#include <stdio.h>
@@ -27,6 +22,13 @@
// f = fdopen(_fd, "rbwb");
// if(f==NULL)
// throw IOException("Could not open stream from file descriptor", errno);
+ // Set the TCP socket to be non-blocking
+ int on = 1;
+ if (ioctl(fd, FIONBIO, (int)&on) < 0)
+ {
+ ::close(fd);
+ throw IOException("Could not set socket to non-blocking mode");
+ }
}
FDIOStream::~FDIOStream(){
close();
@@ -69,14 +71,35 @@
return totalRead;
}
int FDIOStream::write(const void* ptr, int numbytes){
- int numWrote = ::write(fd, (char*)ptr, numbytes);//TODO: this is bad
- //int numWrote = fwrite(ptr, 1, numbytes, f);
- if(numWrote==numbytes)
- return numWrote;
- perror("write error: ");
- fflush(stderr);
- throw IOException("Could not write all bytes to fd stream");
-
+ int numWrote = ::write(fd, (char*)ptr, numbytes);
+ if(numWrote==numbytes)
+ return numWrote;
+
+ if (numWrote == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
+ {
+ // see if write timeout expires
+ struct timeval timeout;
+ fd_set fdSet;
+
+ FD_ZERO(&fdSet);
+ FD_SET(fd, &fdSet);
+ timeout.tv_sec = 1; // wait 1 second for the other side to connect
+ timeout.tv_usec = 0;
+
+ int select_result = select(FD_SETSIZE, NULL, &fdSet, NULL, &timeout);
+ if ( select_result < 0)
+ throw IOException("Select returned an error on write");
+
+ if (FD_ISSET(fd, &fdSet)) {
+ numWrote = ::write(fd, (char*)ptr, numbytes);
+ if(numWrote==numbytes)
+ return numWrote;
+ }
+ }
+
+ perror("write error: ");
+ fflush(stderr);
+ throw IOException("Could not write all bytes to fd stream");
}
void FDIOStream::flush(){
//if(fflush(f)==EOF)
diff --git a/aos/linux_code/ipc_lib/ipc_lib.gyp b/aos/linux_code/ipc_lib/ipc_lib.gyp
index fe8b2e0..68cd13b 100644
--- a/aos/linux_code/ipc_lib/ipc_lib.gyp
+++ b/aos/linux_code/ipc_lib/ipc_lib.gyp
@@ -46,6 +46,26 @@
'core_lib',
'<(AOS)/build/aos.gyp:logging_interface',
],
+ 'defines': [
+ 'QUEUE_DEBUG=0',
+ ],
+ },
+ # A version of the queue code compiled with assertions enabled etc.
+ {
+ 'target_name': 'queue_debug',
+ 'type': 'static_library',
+ 'sources': [
+ 'queue.cc',
+ ],
+ 'dependencies': [
+ 'queue',
+ ],
+ 'export_dependent_settings': [
+ 'queue',
+ ],
+ 'defines': [
+ 'QUEUE_DEBUG=1',
+ ],
},
{
'target_name': 'raw_queue_test',
@@ -55,7 +75,7 @@
],
'dependencies': [
'<(EXTERNALS):gtest',
- 'queue',
+ 'queue_debug',
'<(AOS)/build/aos.gyp:logging',
'core_lib',
'<(AOS)/common/common.gyp:queue_testutils',
diff --git a/aos/linux_code/ipc_lib/queue.cc b/aos/linux_code/ipc_lib/queue.cc
index 211882f..8513e32 100644
--- a/aos/linux_code/ipc_lib/queue.cc
+++ b/aos/linux_code/ipc_lib/queue.cc
@@ -1,3 +1,7 @@
+#if !QUEUE_DEBUG
+#define NDEBUG
+#endif
+
#include "aos/linux_code/ipc_lib/queue.h"
#include <stdio.h>
@@ -43,7 +47,7 @@
struct RawQueue::MessageHeader {
// This gets incremented and decremented with atomic instructions without any
// locks held.
- int ref_count;
+ int32_t ref_count;
MessageHeader *next;
// Gets the message header immediately preceding msg.
static MessageHeader *Get(const void *msg) {
@@ -51,14 +55,10 @@
static_cast<uint8_t *>(const_cast<void *>(msg)) - sizeof(MessageHeader),
alignof(MessageHeader)));
}
- void Swap(MessageHeader *other) {
- MessageHeader temp;
- memcpy(&temp, other, sizeof(temp));
- memcpy(other, this, sizeof(*other));
- memcpy(this, &temp, sizeof(*this));
- }
+ // Padding to make the total size 8 bytes if we have 4-byte pointers or bump
+ // it to 16 if a pointer is 8 bytes by itself.
#if __SIZEOF_POINTER__ == 8
- char padding[16 - sizeof(next) - sizeof(ref_count)];
+ char padding[4];
#elif __SIZEOF_POINTER__ == 4
// No padding needed to get 8 byte total size.
#else
@@ -66,9 +66,16 @@
#endif
};
-struct RawQueue::ReadData {
- bool writable_start;
-};
+inline int RawQueue::index_add1(int index) {
+ // Doing it this way instead of with % is more efficient on ARM.
+ int r = index + 1;
+ assert(index <= data_length_);
+ if (r == data_length_) {
+ return 0;
+ } else {
+ return r;
+ }
+}
void RawQueue::DecrementMessageReferenceCount(const void *msg) {
MessageHeader *header = MessageHeader::Get(msg);
@@ -88,7 +95,7 @@
}
}
-void RawQueue::IncrementMessageReferenceCount(const void *msg) const {
+inline void RawQueue::IncrementMessageReferenceCount(const void *msg) const {
MessageHeader *const header = MessageHeader::Get(msg);
__atomic_add_fetch(&header->ref_count, 1, __ATOMIC_RELAXED);
if (kRefDebug) {
@@ -96,6 +103,71 @@
}
}
+inline void RawQueue::DoFreeMessage(const void *msg) {
+ MessageHeader *header = MessageHeader::Get(msg);
+ if (kRefDebug) {
+ printf("%p ref free to %p: %p\n", this, recycle_, msg);
+ }
+
+ if (__builtin_expect(recycle_ != nullptr, 0)) {
+ void *const new_msg = recycle_->GetMessage();
+ if (new_msg == nullptr) {
+ fprintf(stderr, "queue: couldn't get a message"
+ " for recycle queue %p\n", recycle_);
+ } else {
+ // Nobody else has a reference to the message at this point, so no need to
+ // be fancy about it.
+ ++header->ref_count;
+ if (!recycle_->WriteMessage(const_cast<void *>(msg), kOverride)) {
+ fprintf(stderr, "queue: %p->WriteMessage(%p, kOverride) failed."
+ " aborting\n", recycle_, msg);
+ printf("see stderr\n");
+ abort();
+ }
+ msg = new_msg;
+ header = MessageHeader::Get(new_msg);
+ }
+ }
+
+ // This works around GCC bug 60272 (fixed in 4.8.3).
+ // new_next should just get replaced with header->next (and the body of the
+ // loop should become empty).
+ // The bug is that the store to new_next after the compare/exchange is
+ // unconditional but it should only be if it fails, which could mean
+ // overwriting what somebody else who preempted us right then changed it to.
+ // TODO(brians): Get rid of this workaround once we get a new enough GCC.
+ MessageHeader *new_next = __atomic_load_n(&free_messages_, __ATOMIC_RELAXED);
+ do {
+ header->next = new_next;
+ } while (__builtin_expect(
+ !__atomic_compare_exchange_n(&free_messages_, &new_next, header, true,
+ __ATOMIC_RELEASE, __ATOMIC_RELAXED),
+ 0));
+}
+
+void *RawQueue::GetMessage() {
+ MessageHeader *header = __atomic_load_n(&free_messages_, __ATOMIC_RELAXED);
+ do {
+ if (__builtin_expect(header == nullptr, 0)) {
+ LOG(FATAL, "overused pool of queue %p\n", this);
+ }
+ } while (__builtin_expect(
+ !__atomic_compare_exchange_n(&free_messages_, &header, header->next, true,
+ __ATOMIC_ACQ_REL, __ATOMIC_RELAXED),
+ 0));
+ void *msg = reinterpret_cast<uint8_t *>(header + 1);
+ // It might be uninitialized, 0 from a previous use, or 1 from previously
+ // being recycled.
+ header->ref_count = 1;
+ static_assert(
+ __atomic_always_lock_free(sizeof(header->ref_count), &header->ref_count),
+ "we access this using not specifically atomic loads and stores");
+ if (kRefDebug) {
+ printf("%p ref alloc: %p\n", this, msg);
+ }
+ return msg;
+}
+
RawQueue::RawQueue(const char *name, size_t length, int hash, int queue_length)
: readable_(&data_lock_), writable_(&data_lock_) {
static_assert(shm_ok<RawQueue::MessageHeader>::value,
@@ -103,6 +175,10 @@
static_assert((sizeof(RawQueue::MessageHeader) % 8) == 0,
"need to revalidate size/alignent assumptions");
+ if (queue_length < 1) {
+ LOG(FATAL, "queue length %d needs to be at least 1\n", queue_length);
+ }
+
const size_t name_size = strlen(name) + 1;
char *temp = static_cast<char *>(shm_malloc(name_size));
memcpy(temp, name, name_size);
@@ -120,9 +196,6 @@
}
data_length_ = queue_length + 1;
- if (data_length_ < 2) { // TODO(brians) when could this happen?
- data_length_ = 2;
- }
data_ = static_cast<void **>(shm_malloc(sizeof(void *) * data_length_));
data_start_ = 0;
data_end_ = 0;
@@ -130,26 +203,31 @@
msg_length_ = length + sizeof(MessageHeader);
- MessageHeader *previous = nullptr;
- for (int i = 0; i < queue_length + kExtraMessages; ++i) {
- MessageHeader *const message =
- static_cast<MessageHeader *>(shm_malloc(msg_length_));
- free_messages_ = message;
- message->next = previous;
- previous = message;
+ // Create all of the messages for the free list and stick them on.
+ {
+ MessageHeader *previous = nullptr;
+ for (int i = 0; i < queue_length + kExtraMessages; ++i) {
+ MessageHeader *const message =
+ static_cast<MessageHeader *>(shm_malloc(msg_length_));
+ free_messages_ = message;
+ message->next = previous;
+ previous = message;
+ }
}
if (kFetchDebug) {
printf("made queue %s\n", name);
}
}
+
RawQueue *RawQueue::Fetch(const char *name, size_t length, int hash,
int queue_length) {
if (kFetchDebug) {
printf("fetching queue %s\n", name);
}
if (mutex_lock(&global_core->mem_struct->queues.lock) != 0) {
- return NULL;
+ LOG(FATAL, "mutex_lock(%p) failed\n",
+ &global_core->mem_struct->queues.lock);
}
RawQueue *current = static_cast<RawQueue *>(
global_core->mem_struct->queues.pointer);
@@ -183,6 +261,7 @@
mutex_unlock(&global_core->mem_struct->queues.lock);
return r;
}
+
RawQueue *RawQueue::Fetch(const char *name, size_t length, int hash,
int queue_length,
int recycle_hash, int recycle_length, RawQueue **recycle) {
@@ -198,58 +277,17 @@
return r;
}
-void RawQueue::DoFreeMessage(const void *msg) {
- MessageHeader *header = MessageHeader::Get(msg);
- if (kRefDebug) {
- printf("%p ref free->%p: %p\n", this, recycle_, msg);
- }
-
- if (recycle_ != NULL) {
- void *const new_msg = recycle_->GetMessage();
- if (new_msg == NULL) {
- fprintf(stderr, "queue: couldn't get a message"
- " for recycle queue %p\n", recycle_);
- } else {
- IncrementMessageReferenceCount(msg);
- if (!recycle_->WriteMessage(const_cast<void *>(msg), kOverride)) {
- fprintf(stderr, "queue: %p->WriteMessage(%p, kOverride) failed."
- " aborting\n", recycle_, msg);
- printf("see stderr\n");
- abort();
- }
- msg = new_msg;
- header = MessageHeader::Get(new_msg);
- }
- }
-
- header->next = __atomic_load_n(&free_messages_, __ATOMIC_RELAXED);
- while (
- !__atomic_compare_exchange_n(&free_messages_, &header->next, header,
- true, __ATOMIC_RELEASE, __ATOMIC_RELAXED)) {
- }
-}
-
bool RawQueue::WriteMessage(void *msg, int options) {
- // TODO(brians): Test this function.
if (kWriteDebug) {
printf("queue: %p->WriteMessage(%p, %x)\n", this, msg, options);
}
- if (msg == NULL || msg < reinterpret_cast<void *>(global_core->mem_struct) ||
- msg > static_cast<void *>((
- reinterpret_cast<char *>(global_core->mem_struct) +
- global_core->size))) {
- fprintf(stderr, "queue: attempt to write bad message %p to %p. aborting\n",
- msg, this);
- printf("see stderr\n");
- abort();
- }
{
MutexLocker locker(&data_lock_);
bool writable_waited = false;
int new_end;
while (true) {
- new_end = (data_end_ + 1) % data_length_;
+ new_end = index_add1(data_end_);
// If there is room in the queue right now.
if (new_end != data_start_) break;
if (options & kNonBlock) {
@@ -264,7 +302,7 @@
}
// Avoid leaking the message that we're going to overwrite.
DecrementMessageReferenceCount(data_[data_start_]);
- data_start_ = (data_start_ + 1) % data_length_;
+ data_start_ = index_add1(data_start_);
} else { // kBlock
if (kWriteDebug) {
printf("queue: going to wait for writable_ of %p\n", this);
@@ -297,17 +335,18 @@
return true;
}
-void RawQueue::ReadCommonEnd(ReadData *read_data) {
+inline void RawQueue::ReadCommonEnd() {
if (is_writable()) {
if (kReadDebug) {
printf("queue: %ssignalling writable_ of %p\n",
- read_data->writable_start ? "not " : "", this);
+ writable_start_ ? "not " : "", this);
}
- if (!read_data->writable_start) writable_.Signal();
+ if (!writable_start_) writable_.Signal();
}
}
-bool RawQueue::ReadCommonStart(int options, int *index, ReadData *read_data) {
- read_data->writable_start = is_writable();
+
+bool RawQueue::ReadCommonStart(int options, int *index) {
+ writable_start_ = is_writable();
while (data_start_ == data_end_ || ((index != NULL) && messages_ <= *index)) {
if (options & kNonBlock) {
if (kReadDebug) {
@@ -331,27 +370,15 @@
}
return true;
}
-void *RawQueue::ReadPeek(int options, int start) const {
- void *ret;
- if (options & kFromEnd) {
- int pos = data_end_ - 1;
- if (pos < 0) { // if it needs to wrap
- pos = data_length_ - 1;
- }
- if (kReadDebug) {
- printf("queue: %p reading from line %d: %d\n", this, __LINE__, pos);
- }
- ret = data_[pos];
- } else {
- assert(start != -1);
- if (kReadDebug) {
- printf("queue: %p reading from line %d: %d\n", this, __LINE__, start);
- }
- ret = data_[start];
+
+inline int RawQueue::LastMessageIndex() const {
+ int pos = data_end_ - 1;
+ if (pos < 0) { // If it wrapped around.
+ pos = data_length_ - 1;
}
- IncrementMessageReferenceCount(ret);
- return ret;
+ return pos;
}
+
const void *RawQueue::ReadMessage(int options) {
// TODO(brians): Test this function.
if (kReadDebug) {
@@ -361,25 +388,28 @@
MutexLocker locker(&data_lock_);
- ReadData read_data;
- if (!ReadCommonStart(options, NULL, &read_data)) {
+ if (!ReadCommonStart(options, nullptr)) {
if (kReadDebug) {
printf("queue: %p common returned false\n", this);
}
return NULL;
}
- if (options & kPeek) {
- msg = ReadPeek(options, data_start_);
- } else {
- if (options & kFromEnd) {
+ if (options & kFromEnd) {
+ if (options & kPeek) {
+ if (kReadDebug) {
+ printf("queue: %p shortcutting c2: %d\n", this, LastMessageIndex());
+ }
+ msg = data_[LastMessageIndex()];
+ IncrementMessageReferenceCount(msg);
+ } else {
while (true) {
if (kReadDebug) {
printf("queue: %p start of c2\n", this);
}
// This loop pulls each message out of the buffer.
const int pos = data_start_;
- data_start_ = (data_start_ + 1) % data_length_;
+ data_start_ = index_add1(data_start_);
// If this is the last one.
if (data_start_ == data_end_) {
if (kReadDebug) {
@@ -391,20 +421,25 @@
// This message is not going to be in the queue any more.
DecrementMessageReferenceCount(data_[pos]);
}
+ }
+ } else {
+ if (kReadDebug) {
+ printf("queue: %p reading from d2: %d\n", this, data_start_);
+ }
+ msg = data_[data_start_];
+ if (options & kPeek) {
+ IncrementMessageReferenceCount(msg);
} else {
- if (kReadDebug) {
- printf("queue: %p reading from d2: %d\n", this, data_start_);
- }
- msg = data_[data_start_];
- data_start_ = (data_start_ + 1) % data_length_;
+ data_start_ = index_add1(data_start_);
}
}
- ReadCommonEnd(&read_data);
+ ReadCommonEnd();
if (kReadDebug) {
printf("queue: %p read returning %p\n", this, msg);
}
return msg;
}
+
const void *RawQueue::ReadMessageIndex(int options, int *index) {
if (kReadDebug) {
printf("queue: %p->ReadMessageIndex(%x, %p(*=%d))\n",
@@ -414,8 +449,7 @@
MutexLocker locker(&data_lock_);
- ReadData read_data;
- if (!ReadCommonStart(options, index, &read_data)) {
+ if (!ReadCommonStart(options, index)) {
if (kReadDebug) {
printf("queue: %p common returned false\n", this);
}
@@ -424,12 +458,16 @@
// TODO(parker): Handle integer wrap on the index.
- // Where we're going to start reading.
- int my_start;
-
if (options & kFromEnd) {
- my_start = -1;
+ if (kReadDebug) {
+ printf("queue: %p reading from c1: %d\n", this, LastMessageIndex());
+ }
+ msg = data_[LastMessageIndex()];
+ if (!(options & kPeek)) *index = messages_;
} else {
+ // Where we're going to start reading.
+ int my_start;
+
const int unread_messages = messages_ - *index;
assert(unread_messages > 0);
int current_messages = data_end_ - data_start_;
@@ -457,72 +495,25 @@
printf("queue: %p original read from %d\n", this, my_start);
}
if (data_start_ < data_end_) {
- assert(my_start >= data_start_);
- } else {
- if (my_start < 0) my_start += data_length_;
+ assert(my_start >= 0);
}
+ if (my_start < 0) my_start += data_length_;
}
- }
- if (options & kPeek) {
- msg = ReadPeek(options, my_start);
- } else {
- if (options & kFromEnd) {
- if (kReadDebug) {
- printf("queue: %p start of c1\n", this);
- }
- int pos = data_end_ - 1;
- if (kReadIndexDebug) {
- printf("queue: %p end pos start %d\n", this, pos);
- }
- if (pos < 0) { // If it wrapped.
- pos = data_length_ - 1; // Unwrap it.
- }
- if (kReadDebug) {
- printf("queue: %p reading from c1: %d\n", this, pos);
- }
- msg = data_[pos];
- *index = messages_;
- } else {
- if (kReadDebug) {
- printf("queue: %p reading from d1: %d\n", this, my_start);
- }
- // This assert checks that we're either within both endpoints (duh) or
- // not between them (if the queue is wrapped around).
- assert((my_start >= data_start_ && my_start < data_end_) ||
- ((my_start >= data_start_) == (my_start > data_end_)));
- // More sanity checking.
- assert((my_start >= 0) && (my_start < data_length_));
- msg = data_[my_start];
- ++(*index);
+ if (kReadDebug) {
+ printf("queue: %p reading from d1: %d\n", this, my_start);
}
- IncrementMessageReferenceCount(msg);
+ // We have to be either after the start or before the end, even if the queue
+ // is wrapped around (should be both if it's not).
+ assert((my_start >= data_start_) || (my_start < data_end_));
+ // More sanity checking.
+ assert((my_start >= 0) && (my_start < data_length_));
+ msg = data_[my_start];
+ if (!(options & kPeek)) ++(*index);
}
- ReadCommonEnd(&read_data);
- return msg;
-}
+ IncrementMessageReferenceCount(msg);
-void *RawQueue::GetMessage() {
- // TODO(brians): Test this function.
-
- MessageHeader *header = __atomic_load_n(&free_messages_, __ATOMIC_RELAXED);
- do {
- if (__builtin_expect(header == nullptr, 0)) {
- LOG(FATAL, "overused pool of queue %p\n", this);
- }
- } while (
- !__atomic_compare_exchange_n(&free_messages_, &header, header->next, true,
- __ATOMIC_ACQ_REL, __ATOMIC_RELAXED));
- void *msg = reinterpret_cast<uint8_t *>(header + 1);
- // It might be uninitialized, 0 from a previous use, or 1 from previously
- // getting recycled.
- header->ref_count = 1;
- static_assert(
- __atomic_always_lock_free(sizeof(header->ref_count), &header->ref_count),
- "we access this using not specifically atomic loads and stores");
- if (kRefDebug) {
- printf("%p ref alloc: %p\n", this, msg);
- }
+ ReadCommonEnd();
return msg;
}
diff --git a/aos/linux_code/ipc_lib/queue.h b/aos/linux_code/ipc_lib/queue.h
index 33ed9f4..d4d2609 100644
--- a/aos/linux_code/ipc_lib/queue.h
+++ b/aos/linux_code/ipc_lib/queue.h
@@ -1,6 +1,8 @@
#ifndef AOS_LINUX_CODE_IPC_LIB_QUEUE_H_
#define AOS_LINUX_CODE_IPC_LIB_QUEUE_H_
+#include <assert.h>
+
#include "aos/linux_code/ipc_lib/shared_mem.h"
#include "aos/common/mutex.h"
#include "aos/common/condition.h"
@@ -33,6 +35,7 @@
// length is how large each message will be
// hash can differentiate multiple otherwise identical queues
// queue_length is how many messages the queue will be able to hold
+ // Will never return NULL.
static RawQueue *Fetch(const char *name, size_t length, int hash,
int queue_length);
// Same as above, except sets up the returned queue so that it will put
@@ -47,6 +50,7 @@
// NOTE: calling this function with the same (name,length,hash,queue_length)
// but multiple recycle_queue_lengths will result in each freed message being
// put onto an undefined one of the recycle queues.
+ // Will never return NULL.
static RawQueue *Fetch(const char *name, size_t length, int hash,
int queue_length,
int recycle_hash, int recycle_queue_length,
@@ -81,7 +85,8 @@
// Writes a message into the queue.
// This function takes ownership of msg.
// NOTE: msg must point to a valid message from this queue
- // Returns true on success.
+ // Returns true on success. A return value of false means msg has already been
+ // freed.
bool WriteMessage(void *msg, int options);
// Reads a message out of the queue.
@@ -92,9 +97,9 @@
// IMPORTANT: The return value (if not NULL) must eventually be passed to
// FreeMessage.
const void *ReadMessage(int options);
- // Exactly the same as aos_queue_read_msg, except it will never return the
- // same message twice with the same index argument. However, it may not
- // return some messages that pass through the queue.
+ // The same as ReadMessage, except it will never return the
+ // same message twice (when used with the same index argument). However,
+ // may not return some messages that pass through the queue.
// *index should start as 0. index does not have to be in shared memory, but
// it can be.
const void *ReadMessageIndex(int options, int *index);
@@ -105,7 +110,7 @@
// valid memory where it's pointing to.
// Returns NULL for error.
// IMPORTANT: The return value (if not NULL) must eventually be passed to
- // FreeMessage.
+ // FreeMessage or WriteMessage.
void *GetMessage();
// It is ok to call this method with a NULL msg.
@@ -119,10 +124,12 @@
private:
struct MessageHeader;
- struct ReadData;
+
+ // Adds 1 to the given index and handles wrapping correctly.
+ int index_add1(int index);
bool is_readable() { return data_end_ != data_start_; }
- bool is_writable() { return ((data_end_ + 1) % data_length_) != data_start_; }
+ bool is_writable() { return index_add1(data_end_) != data_start_; }
// These next 4 allow finding the right one.
const char *name_;
@@ -149,6 +156,10 @@
// A pointer to the first in the linked list of free messages.
MessageHeader *free_messages_;
+ // Keeps track of if the queue was writable before a read so we can Signal() a
+ // reader if we transition it.
+ bool writable_start_;
+
// Actually frees the given message.
void DoFreeMessage(const void *msg);
// Calls DoFreeMessage if appropriate.
@@ -159,14 +170,14 @@
// Must be called with data_lock_ locked.
// *read_data will be initialized.
// Returns with a readable message in data_ or false.
- bool ReadCommonStart(int options, int *index, ReadData *read_data);
+ bool ReadCommonStart(int options, int *index);
// Deals with setting/unsetting readable_ and writable_.
// Must be called after data_lock_ has been unlocked.
// read_data should be the same thing that was passed in to ReadCommonStart.
- void ReadCommonEnd(ReadData *read_data);
- // Handles reading with kPeek.
- // start can be -1 if options has kFromEnd set.
- void *ReadPeek(int options, int start) const;
+ void ReadCommonEnd();
+ // Returns the index of the last message.
+ // Useful for reading with kPeek.
+ int LastMessageIndex() const;
// Gets called by Fetch when necessary (with placement new).
RawQueue(const char *name, size_t length, int hash, int queue_length);
diff --git a/aos/linux_code/ipc_lib/raw_queue_test.cc b/aos/linux_code/ipc_lib/raw_queue_test.cc
index e91655a..ca84c51 100644
--- a/aos/linux_code/ipc_lib/raw_queue_test.cc
+++ b/aos/linux_code/ipc_lib/raw_queue_test.cc
@@ -471,6 +471,12 @@
EXPECT_EQ(message2, queue->GetMessage());
}
+// All of the tests from here down are designed to test every branch to
+// make sure it does what it's supposed to. They are generally pretty repetitive
+// and boring, and some of them may duplicate other tests above, but these ones
+// make it a lot easier to figure out what's wrong with bugs not related to race
+// conditions.
+
TEST_F(RawQueueTest, ReadIndexNotFull) {
RawQueue *const queue = RawQueue::Fetch("Queue", sizeof(TestMessage), 1, 2);
const TestMessage *message, *peek_message;
@@ -877,5 +883,47 @@
EXPECT_EQ(0, kExtraMessages + 2 - queue->FreeMessages());
}
+// Tests that writing with kNonBlock fails and frees the message.
+TEST_F(RawQueueTest, WriteDontBlock) {
+ RawQueue *const queue = RawQueue::Fetch("Queue", sizeof(TestMessage), 1, 1);
+ void *message;
+
+ PushMessage(queue, 971);
+ int free_before = queue->FreeMessages();
+ message = queue->GetMessage();
+ ASSERT_NE(nullptr, message);
+ EXPECT_NE(free_before, queue->FreeMessages());
+ EXPECT_FALSE(queue->WriteMessage(message, RawQueue::kNonBlock));
+ EXPECT_EQ(free_before, queue->FreeMessages());
+}
+
+// Tests that writing with kOverride pushes the last message out of the queue.
+TEST_F(RawQueueTest, WriteOverride) {
+ RawQueue *const queue = RawQueue::Fetch("Queue", sizeof(TestMessage), 1, 2);
+ TestMessage *message1;
+
+ PushMessage(queue, 971);
+ PushMessage(queue, 1768);
+ int free_before = queue->FreeMessages();
+ message1 = static_cast<TestMessage *>(queue->GetMessage());
+ ASSERT_NE(nullptr, message1);
+ EXPECT_NE(free_before, queue->FreeMessages());
+ message1->data = 254;
+ EXPECT_TRUE(queue->WriteMessage(message1, RawQueue::kOverride));
+ EXPECT_EQ(free_before, queue->FreeMessages());
+
+ const TestMessage *message2;
+ message2 =
+ static_cast<const TestMessage *>(queue->ReadMessage(RawQueue::kNonBlock));
+ EXPECT_EQ(1768, message2->data);
+ queue->FreeMessage(message2);
+ EXPECT_EQ(free_before + 1, queue->FreeMessages());
+ message2 =
+ static_cast<const TestMessage *>(queue->ReadMessage(RawQueue::kNonBlock));
+ EXPECT_EQ(254, message2->data);
+ queue->FreeMessage(message2);
+ EXPECT_EQ(free_before + 2, queue->FreeMessages());
+}
+
} // namespace testing
} // namespace aos
diff --git a/aos/linux_code/logging/binary_log_writer.cc b/aos/linux_code/logging/binary_log_writer.cc
index 7b9b6da..a14cd6c 100644
--- a/aos/linux_code/logging/binary_log_writer.cc
+++ b/aos/linux_code/logging/binary_log_writer.cc
@@ -186,22 +186,17 @@
case LogMessage::Type::kStruct: {
char *position = output_strings + msg->name_length;
- memcpy(position, &msg->structure.type_id,
- sizeof(msg->structure.type_id));
+ memcpy(position, &msg->structure.type_id, sizeof(msg->structure.type_id));
position += sizeof(msg->structure.type_id);
output->message_size += sizeof(msg->structure.type_id);
- uint32_t length = msg->structure.string_length;
+ const uint32_t length = msg->structure.string_length;
memcpy(position, &length, sizeof(length));
position += sizeof(length);
- memcpy(position, msg->structure.serialized, length);
- position += length;
+ memcpy(position, msg->structure.serialized, length + msg->message_length);
+ position += length + msg->message_length;
output->message_size += sizeof(length) + length;
- memcpy(position,
- msg->structure.serialized + msg->structure.string_length,
- msg->message_length);
-
output->type = LogFileMessageHeader::MessageType::kStruct;
} break;
case LogMessage::Type::kMatrix: {
diff --git a/aos/linux_code/logging/log_displayer.cc b/aos/linux_code/logging/log_displayer.cc
index 1cc5f43..cbf4891 100644
--- a/aos/linux_code/logging/log_displayer.cc
+++ b/aos/linux_code/logging/log_displayer.cc
@@ -10,8 +10,9 @@
#include <algorithm>
#include "aos/linux_code/logging/binary_log_file.h"
-#include "aos/common/logging/logging_impl.h"
#include "aos/common/queue_types.h"
+#include "aos/common/logging/logging_impl.h"
+#include "aos/common/logging/logging_printf_formats.h"
using ::aos::logging::linux_code::LogFileMessageHeader;
@@ -156,7 +157,6 @@
}
const LogFileMessageHeader *msg;
- ::aos::logging::LogMessage log_message;
do {
msg = accessor.ReadNextMessage(follow);
if (msg == NULL) {
@@ -192,84 +192,82 @@
}
}
- log_message.source = msg->source;
- log_message.sequence = msg->sequence;
- log_message.level = msg->level;
- log_message.seconds = msg->time_sec;
- log_message.nseconds = msg->time_nsec;
- memcpy(log_message.name, reinterpret_cast<const char *>(msg) + sizeof(*msg),
- ::std::min<size_t>(sizeof(log_message.name), msg->name_size));
- log_message.message_length = msg->message_size;
- log_message.name_length = msg->name_size;
-
+ const char *position =
+ reinterpret_cast<const char *>(msg + 1) + msg->name_size;
+#define BASE_ARGS \
+ AOS_LOGGING_BASE_ARGS( \
+ msg->name_size, reinterpret_cast<const char *>(msg + 1), msg->source, \
+ msg->sequence, msg->level, msg->time_sec, msg->time_nsec)
switch (msg->type) {
- case LogFileMessageHeader::MessageType::kStruct: {
- const char *position =
- reinterpret_cast<const char *>(msg + 1) + msg->name_size;
- memcpy(&log_message.structure.type_id, position,
- sizeof(log_message.structure.type_id));
- position += sizeof(log_message.structure.type_id);
-
- uint32_t length;
- memcpy(&length, position, sizeof(length));
- log_message.structure.string_length = length;
- position += sizeof(length);
- memcpy(log_message.structure.serialized, position, length);
- position += length;
-
- log_message.message_length -=
- sizeof(log_message.structure.type_id) + sizeof(uint32_t) +
- log_message.structure.string_length;
- memcpy(log_message.structure.serialized +
- log_message.structure.string_length,
- position, log_message.message_length);
-
- log_message.type = ::aos::logging::LogMessage::Type::kStruct;
+ case LogFileMessageHeader::MessageType::kString:
+ fprintf(stdout, AOS_LOGGING_BASE_FORMAT "%.*s", BASE_ARGS,
+ static_cast<int>(msg->message_size), position);
break;
- }
- case LogFileMessageHeader::MessageType::kMatrix: {
- const char *position =
- reinterpret_cast<const char *>(msg + 1) + msg->name_size;
- memcpy(&log_message.matrix.type, position,
- sizeof(log_message.matrix.type));
- position += sizeof(log_message.matrix.type);
+ case LogFileMessageHeader::MessageType::kStruct: {
+ uint32_t type_id;
+ memcpy(&type_id, position, sizeof(type_id));
+ position += sizeof(type_id);
- uint32_t length;
- memcpy(&length, position, sizeof(length));
- log_message.matrix.string_length = length;
- position += sizeof(length);
+ uint32_t string_length;
+ memcpy(&string_length, position, sizeof(string_length));
+ position += sizeof(string_length);
+
+ char buffer[2048];
+ size_t output_length = sizeof(buffer);
+ size_t input_length =
+ msg->message_size -
+ (sizeof(type_id) + sizeof(uint32_t) + string_length);
+ if (!PrintMessage(buffer, &output_length, position + string_length,
+ &input_length, ::aos::type_cache::Get(type_id))) {
+ LOG(FATAL, "printing message (%.*s) of type %s into %zu-byte buffer "
+ "failed\n",
+ static_cast<int>(string_length), position,
+ ::aos::type_cache::Get(type_id).name.c_str(), sizeof(buffer));
+ }
+ if (input_length > 0) {
+ LOG(WARNING, "%zu extra bytes on message of type %s\n",
+ input_length, ::aos::type_cache::Get(type_id).name.c_str());
+ }
+ fprintf(stdout, AOS_LOGGING_BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
+ static_cast<int>(string_length), position,
+ static_cast<int>(sizeof(buffer) - output_length), buffer);
+ } break;
+ case LogFileMessageHeader::MessageType::kMatrix: {
+ uint32_t type;
+ memcpy(&type, position, sizeof(type));
+ position += sizeof(type);
+
+ uint32_t string_length;
+ memcpy(&string_length, position, sizeof(string_length));
+ position += sizeof(string_length);
uint16_t rows;
memcpy(&rows, position, sizeof(rows));
- log_message.matrix.rows = rows;
position += sizeof(rows);
uint16_t cols;
memcpy(&cols, position, sizeof(cols));
- log_message.matrix.cols = cols;
position += sizeof(cols);
- log_message.message_length -=
- sizeof(log_message.matrix.type) + sizeof(uint32_t) +
- sizeof(uint16_t) + sizeof(uint16_t) + length;
- CHECK_EQ(
- log_message.message_length,
- ::aos::MessageType::Sizeof(log_message.matrix.type) * rows * cols);
- memcpy(log_message.matrix.data, position,
- log_message.message_length + length);
-
- log_message.type = ::aos::logging::LogMessage::Type::kMatrix;
- break;
- } case LogFileMessageHeader::MessageType::kString:
- memcpy(
- log_message.message,
- reinterpret_cast<const char *>(msg) + sizeof(*msg) + msg->name_size,
- ::std::min<size_t>(sizeof(log_message.message), msg->message_size));
- log_message.type = ::aos::logging::LogMessage::Type::kString;
- break;
+ const size_t matrix_bytes =
+ msg->message_size -
+ (sizeof(type) + sizeof(uint32_t) + sizeof(uint16_t) +
+ sizeof(uint16_t) + string_length);
+ CHECK_EQ(matrix_bytes, ::aos::MessageType::Sizeof(type) * rows * cols);
+ char buffer[2048];
+ size_t output_length = sizeof(buffer);
+ if (!::aos::PrintMatrix(buffer, &output_length,
+ position + string_length, type, rows, cols)) {
+ LOG(FATAL, "printing %dx%d matrix of type %" PRIu32 " failed\n", rows,
+ cols, type);
+ }
+ fprintf(stdout, AOS_LOGGING_BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
+ static_cast<int>(string_length), position,
+ static_cast<int>(sizeof(buffer) - output_length), buffer);
+ } break;
case LogFileMessageHeader::MessageType::kStructType:
LOG(FATAL, "shouldn't get here\n");
break;
- };
- ::aos::logging::internal::PrintMessage(stdout, log_message);
+ }
+#undef BASE_ARGS
} while (msg != NULL);
}
diff --git a/aos/prime/output/motor_output.cc b/aos/prime/output/motor_output.cc
index 54add2d..249ccfd 100644
--- a/aos/prime/output/motor_output.cc
+++ b/aos/prime/output/motor_output.cc
@@ -53,14 +53,14 @@
values_.compressor_channel = 0;
values_.solenoid_module = -1;
+ RunIteration();
+
::aos::robot_state.FetchLatest();
if (!::aos::robot_state.get() || ::aos::robot_state->fake) {
LOG(DEBUG, "fake robot state -> not outputting\n");
continue;
}
- RunIteration();
-
char buffer[sizeof(values_) + ::buffers::kOverhead];
ssize_t size = values_.SerializeTo(buffer, sizeof(buffer));
if (size <= 0) {
@@ -89,6 +89,10 @@
values_.pwm_outputs[channel - 1] = bounds.Map(value);
}
+void MotorOutput::SetRawPWMOutput(uint8_t channel, uint8_t value) {
+ values_.pwm_outputs[channel - 1] = value;
+}
+
void MotorOutput::DisablePWMOutput(uint8_t channel) {
values_.pwm_outputs[channel - 1] = 0;
}
diff --git a/aos/prime/output/motor_output.h b/aos/prime/output/motor_output.h
index 53bdc83..01e271a 100644
--- a/aos/prime/output/motor_output.h
+++ b/aos/prime/output/motor_output.h
@@ -51,11 +51,13 @@
void SetSolenoid(uint8_t channel, bool set);
void SetPWMOutput(uint8_t channel, double value,
const MotorControllerBounds &bounds);
+ void SetRawPWMOutput(uint8_t cahnnel, uint8_t value);
void DisablePWMOutput(uint8_t channel);
void SetDigitalOutput(uint8_t channel, bool value);
// The data that's going to get sent over.
- // Gets reset (everything set so that it won't do anything) each time through.
+ // Gets reset (everything set so that it won't do anything) each time through
+ // except for solenoids.
NetworkRobotMotors values_;
private:
diff --git a/bbb_cape/src/bbb/bbb.gyp b/bbb_cape/src/bbb/bbb.gyp
index 1da4732..5f5b590 100644
--- a/bbb_cape/src/bbb/bbb.gyp
+++ b/bbb_cape/src/bbb/bbb.gyp
@@ -46,6 +46,17 @@
],
},
{
+ 'target_name': 'export_uart',
+ 'type': 'static_library',
+ 'sources': [
+ 'export_uart.cc',
+ ],
+ 'dependencies': [
+ '<(AOS)/build/aos.gyp:logging',
+ '<(AOS)/common/common.gyp:time',
+ ],
+ },
+ {
'target_name': 'uart_reader',
'type': 'static_library',
'sources': [
@@ -56,6 +67,7 @@
'<(AOS)/build/aos.gyp:logging',
'<(AOS)/common/common.gyp:time',
'byte_io',
+ 'export_uart',
],
'export_dependent_settings': [
'<(AOS)/common/common.gyp:time',
diff --git a/bbb_cape/src/bbb/export_uart.cc b/bbb_cape/src/bbb/export_uart.cc
new file mode 100644
index 0000000..ccf751c
--- /dev/null
+++ b/bbb_cape/src/bbb/export_uart.cc
@@ -0,0 +1,59 @@
+#include "bbb/export_uart.h"
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include "aos/common/logging/logging.h"
+#include "aos/common/time.h"
+
+namespace bbb {
+namespace {
+
+// TODO(brians): Determine this in some way that allows easy switching for
+// testing with /dev/ttyUSB0 for example.
+const char *device = "/dev/ttyO1";
+
+bool easy_access(const char *path) {
+ if (access(path, R_OK | W_OK) == 0) return true;
+ if (errno == EACCES || errno == ENOENT) return false;
+ LOG(FATAL, "access(%s, F_OK) failed with %d: %s\n", path, errno,
+ strerror(errno));
+}
+
+} // namespace
+
+const char *UartDevice() { return device; }
+
+void ExportUart() {
+ if (easy_access(device)) {
+ LOG(INFO, "unexporting BB-UART1\n");
+ if (system("bash -c 'echo -$(cat /sys/devices/bone_capemgr.*/slots"
+ " | fgrep BB-UART1"
+ " | cut -d : -f 1 | tr -d \" \")"
+ " > /sys/devices/bone_capemgr.*/slots'") == -1) {
+ LOG(FATAL, "system([disable OMAP UART]) failed with %d: %s\n", errno,
+ strerror(errno));
+ }
+ while (easy_access(device)) {
+ LOG(DEBUG, "waiting for BB-UART1 to be unexported\n");
+ ::aos::time::SleepFor(::aos::time::Time::InSeconds(0.1));
+ }
+ }
+
+ LOG(INFO, "exporting BB-UART1\n");
+ // 2 strings to work around a VIM bug where the indenter locks up when they're
+ // combined as 1...
+ if (system("bash -c 'echo BB-UART1 > /sys/devices/bone_capemgr.*"
+ "/slots'") ==
+ -1) {
+ LOG(FATAL, "system([enable OMAP UART]) failed with %d: %s\n", errno,
+ strerror(errno));
+ }
+ while (!easy_access(device)) {
+ LOG(DEBUG, "waiting for BB-UART1 to be exported\n");
+ ::aos::time::SleepFor(::aos::time::Time::InSeconds(0.1));
+ }
+}
+
+} // namespace bbb
diff --git a/bbb_cape/src/bbb/export_uart.h b/bbb_cape/src/bbb/export_uart.h
new file mode 100644
index 0000000..4f91a57
--- /dev/null
+++ b/bbb_cape/src/bbb/export_uart.h
@@ -0,0 +1,15 @@
+#ifndef BBB_EXPORT_UART_H_
+#define BBB_EXPORT_UART_H_
+
+namespace bbb {
+
+// Returns a pointer to static memory with the name of the device file for the
+// UART.
+const char *UartDevice();
+
+// Unexports (if already exported) and then reexports the UART cape slot.
+void ExportUart();
+
+} // namespace bbb
+
+#endif // BBB_EXPORT_UART_H_
diff --git a/bbb_cape/src/bbb/hex_byte_reader.h b/bbb_cape/src/bbb/hex_byte_reader.h
index 8f44c9a..8bbbe6d 100644
--- a/bbb_cape/src/bbb/hex_byte_reader.h
+++ b/bbb_cape/src/bbb/hex_byte_reader.h
@@ -15,8 +15,9 @@
explicit HexByteReader(const ::std::string &filename);
virtual ~HexByteReader() {}
- virtual ssize_t ReadBytes(uint8_t *dest, size_t max_bytes,
- const ::aos::time::Time &timeout) override;
+ virtual ssize_t ReadBytes(
+ uint8_t *dest, size_t max_bytes,
+ const ::aos::time::Time &timeout = ::aos::time::Time(0, 0)) override;
// Returns the total number of bytes that we will eventually read out.
unsigned int GetSize();
diff --git a/bbb_cape/src/bbb/sensor_reader.cc b/bbb_cape/src/bbb/sensor_reader.cc
index c0e9604..86d4d8b 100644
--- a/bbb_cape/src/bbb/sensor_reader.cc
+++ b/bbb_cape/src/bbb/sensor_reader.cc
@@ -16,12 +16,20 @@
uint32_t ReadChecksum(const ::std::string &filename) {
HexByteReader reader(filename);
- uint32_t r = ::cape::CalculateChecksum(&reader);
- /*static const uint8_t fill[4] = {0xFF, 0xFF, 0xFF, 0xFF};
- for (size_t i = reader.GetSize(); i < 0x100000 - 0x4000; i += 4) {
- r = ::cape::CalculateChecksum(fill, 4, r);
- }*/
- return r;
+ {
+ static const size_t kSkipBytes = 0x4000;
+ size_t i = 0;
+ uint8_t buffer[1024];
+ while (i < kSkipBytes) {
+ ssize_t read =
+ reader.ReadBytes(buffer, ::std::min<size_t>(sizeof(buffer), kSkipBytes - i));
+ if (read < 0) {
+ LOG(FATAL, "error skipping bytes before actual data\n");
+ }
+ i += read;
+ }
+ }
+ return ::cape::CalculateChecksum(&reader);
}
} // namespace
@@ -49,13 +57,16 @@
LOG(WARNING, "Too long since good packet received. Resetting.\n");
manager_.Reset();
ResetHappened();
+ continue;
}
if (packet_finder_.ReadPacket(next_timeout)) {
last_received_time_ = ::aos::time::Time::Now();
const DataStruct *data = packet_finder_.get_packet<DataStruct>();
- if (data->flash_checksum != expected_checksum_ && false) {
- LOG(WARNING, "Cape code checksum is %" PRIu32 ". Expected %" PRIu32
- ". Reflashing.\n",
+ if (data->flash_checksum != expected_checksum_) {
+ // TODO(brians): Fix the custom bootloader stuff and then change this to
+ // WARNING.
+ LOG(FATAL, "Cape code checksum is 0x%" PRIx32 ". Expected 0x%" PRIx32
+ ". Reflashing.\n",
data->flash_checksum, expected_checksum_);
manager_.DownloadHex(hex_filename_);
ResetHappened();
@@ -65,6 +76,7 @@
LOG(WARNING, "cape timestamp decreased: %" PRIu64 " to %" PRIu64 "\n",
last_cape_timestamp_, data->timestamp);
ResetHappened();
+ continue;
}
last_cape_timestamp_ = data->timestamp;
return data;
diff --git a/bbb_cape/src/bbb/uart_reader.cc b/bbb_cape/src/bbb/uart_reader.cc
index 9abb284..7f88d51 100644
--- a/bbb_cape/src/bbb/uart_reader.cc
+++ b/bbb_cape/src/bbb/uart_reader.cc
@@ -7,6 +7,8 @@
#include "aos/common/logging/logging.h"
+#include "bbb/export_uart.h"
+
// This is the code for receiving data from the cape via UART.
// fragment active.
// `su -c "echo BB-UART1 > /sys/devices/bone_capemgr.*/slots"` works, but
@@ -16,48 +18,10 @@
namespace bbb {
namespace {
-// TODO(brians): Determine this in some way that allows easy switching for
-// testing with /dev/ttyUSB0 for example.
-const char *device = "/dev/ttyO1";
-
-bool easy_access(const char *path) {
- if (access(path, R_OK | W_OK) == 0) return true;
- if (errno == EACCES || errno == ENOENT) return false;
- LOG(FATAL, "access(%s, F_OK) failed with %d: %s\n", path, errno,
- strerror(errno));
-}
-
int open_device() {
- if (easy_access(device)) {
- LOG(INFO, "unexporting BB-UART1\n");
- if (system("bash -c 'echo -$(cat /sys/devices/bone_capemgr.*/slots"
- " | fgrep BB-UART1"
- " | cut -d : -f 1 | tr -d \" \")"
- " > /sys/devices/bone_capemgr.*/slots'") == -1) {
- LOG(FATAL, "system([disable OMAP UART]) failed with %d: %s\n", errno,
- strerror(errno));
- }
- while (easy_access(device)) {
- LOG(DEBUG, "waiting for BB-UART1 to be unexported\n");
- ::aos::time::SleepFor(::aos::time::Time::InSeconds(0.1));
- }
- }
+ ExportUart();
- LOG(INFO, "exporting BB-UART1\n");
- // 2 strings to work around a VIM bug where the indenter locks up when they're
- // combined as 1...
- if (system("bash -c 'echo BB-UART1 > /sys/devices/bone_capemgr.*"
- "/slots'") ==
- -1) {
- LOG(FATAL, "system([enable OMAP UART]) failed with %d: %s\n", errno,
- strerror(errno));
- }
- while (!easy_access(device)) {
- LOG(DEBUG, "waiting for BB-UART1 to be exported\n");
- ::aos::time::SleepFor(::aos::time::Time::InSeconds(0.1));
- }
-
- return open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);
+ return open(UartDevice(), O_RDWR | O_NOCTTY | O_NONBLOCK);
}
} // namespace
@@ -77,7 +41,7 @@
if (fd_ < 0) {
LOG(FATAL, "open(%s, O_RDWR | O_NOCTTY | O_NOBLOCK) failed with %d: %s\n",
- device, errno, strerror(errno));
+ UartDevice(), errno, strerror(errno));
}
if (aos_uart_reader_set_tty_options(fd_, baud_rate) != 0) {
diff --git a/bbb_cape/src/bbb/uart_reader.h b/bbb_cape/src/bbb/uart_reader.h
index a8edc6e..7861003 100644
--- a/bbb_cape/src/bbb/uart_reader.h
+++ b/bbb_cape/src/bbb/uart_reader.h
@@ -17,8 +17,9 @@
explicit UartReader(int32_t baud_rate);
virtual ~UartReader();
- virtual ssize_t ReadBytes(uint8_t *dest, size_t max_bytes,
- const ::aos::time::Time &timeout_time) override;
+ virtual ssize_t ReadBytes(
+ uint8_t *dest, size_t max_bytes,
+ const ::aos::time::Time &timeout_time = ::aos::time::Time(0, 0)) override;
virtual bool WriteBytes(uint8_t *bytes, size_t number_bytes) override;
private:
diff --git a/bbb_cape/src/cape/analog.c b/bbb_cape/src/cape/analog.c
index 297afd6..14c176c 100644
--- a/bbb_cape/src/cape/analog.c
+++ b/bbb_cape/src/cape/analog.c
@@ -48,7 +48,7 @@
}
void TIM_IRQHandler(void) {
- TIM->SR = ~TIM_SR_CC1IF;
+ TIM->SR = ~TIM_SR_UIF;
if (frame != 2) {
// We're not done with the previous reading yet, so we're going to reset and
@@ -91,13 +91,15 @@
NVIC_SetPriority(TIM_IRQn, 6);
NVIC_EnableIRQ(TIM_IRQn);
+ // We set it up to trigger at 4.44KHz (each sensor at just over 500Hz).
+ // 1/(1.875MHz)*32 = 17067ns (58.6Khz), and we don't want to be close (other
+ // interrupts do get in the way, and there's no reason to be).
TIM->CR1 = 0;
- TIM->DIER = TIM_DIER_CC1IE;
- TIM->CCMR1 = 0;
- // Make each tick take 1500ns.
- TIM->PSC = (60 * 1500 / 1000) - 1;
- // Call the interrupt after 1 tick.
- TIM->CCR1 = 1;
+ TIM->DIER = TIM_DIER_UIE;
+ // Make each tick take 45000ns.
+ TIM->PSC = (60 * 45000 / 1000) - 1;
+ // Only count to 5 before triggering the interrupt and wrapping around.
+ TIM->ARR = 5;
SPI->CR1 = 0; // make sure it's disabled
SPI->CR1 =
diff --git a/bbb_cape/src/cape/data_struct.h b/bbb_cape/src/cape/data_struct.h
index d60a0e9..6d747bb 100644
--- a/bbb_cape/src/cape/data_struct.h
+++ b/bbb_cape/src/cape/data_struct.h
@@ -82,9 +82,12 @@
int32_t left_drive;
int32_t right_drive;
- // The length of the pulse from the ultrasonic sensor in 100kHZ ticks.
+ // The length of the pulse from the ultrasonic sensor in 100KHz ticks.
uint32_t ultrasonic_pulse_length;
+ // The length of the pulse from the sidecar PWM output in 10MHz ticks.
+ uint32_t output_check_pulse_length;
+
int32_t shooter_position, pusher_distal_posedge_position,
pusher_proximal_posedge_position;
diff --git a/bbb_cape/src/cape/digital.h b/bbb_cape/src/cape/digital.h
index 698aeed..6071ca8 100644
--- a/bbb_cape/src/cape/digital.h
+++ b/bbb_cape/src/cape/digital.h
@@ -7,6 +7,8 @@
// For all of the digital functions, a high voltage level on the input reads as
// 1 (and a low to high transition is a positive edge).
+// Encoder inputs 0-7 A and B are mapped to "digital inputs" 12-27 (12 is 0A,
+// 13 is B, 14 is 1A, etc).
static inline int digital_read(int num) {
switch (num) {
@@ -34,6 +36,38 @@
return !(GPIOA->IDR & (1 << 7));
case 11:
return !(GPIOB->IDR & (1 << 2));
+ case 12: // encoder 0
+ return !(GPIOC->IDR & (1 << 6));
+ case 13:
+ return !(GPIOC->IDR & (1 << 7));
+ case 14: // encoder 1
+ return !(GPIOC->IDR & (1 << 0));
+ case 15:
+ return !(GPIOC->IDR & (1 << 1));
+ case 16: // encoder 2
+ return !(GPIOA->IDR & (1 << 0));
+ case 17:
+ return !(GPIOA->IDR & (1 << 1));
+ case 18: // encoder 3
+ return !(GPIOA->IDR & (1 << 2));
+ case 19:
+ return !(GPIOA->IDR & (1 << 3));
+ case 20: // encoder 4
+ return !(GPIOA->IDR & (1 << 8));
+ case 21:
+ return !(GPIOB->IDR & (1 << 0));
+ case 22: // encoder 5
+ return !(GPIOA->IDR & (1 << 5));
+ case 23:
+ return !(GPIOB->IDR & (1 << 3));
+ case 24: // encoder 6
+ return !(GPIOA->IDR & (1 << 6));
+ case 25:
+ return !(GPIOB->IDR & (1 << 5));
+ case 26: // encoder 7
+ return !(GPIOB->IDR & (1 << 6));
+ case 27:
+ return !(GPIOB->IDR & (1 << 7));
default:
return 0;
}
diff --git a/bbb_cape/src/cape/fill_packet.c b/bbb_cape/src/cape/fill_packet.c
index 8d1f72a..a0b2b13 100644
--- a/bbb_cape/src/cape/fill_packet.c
+++ b/bbb_cape/src/cape/fill_packet.c
@@ -80,9 +80,14 @@
encoder_init();
digital_init();
- flash_checksum =
- crc_calculate((void *)MAIN_FLASH_START,
- (size_t)(MAIN_FLASH_END - MAIN_FLASH_START) / 4);
+ {
+ extern uint32_t __flash_end, __data_start__, __data_end__;
+ const uint32_t main_flash_end = (uint32_t) & __flash_end + (uint32_t) &
+ __data_end__ - (uint32_t) & __data_start__;
+ flash_checksum =
+ crc_calculate((void *)MAIN_FLASH_START,
+ (size_t)(main_flash_end - MAIN_FLASH_START) / 4);
+ }
led_set(LED_ERR, 0);
gyro_init();
diff --git a/bbb_cape/src/cape/gcc_arm.ld b/bbb_cape/src/cape/gcc_arm.ld
index 1a1cb27..26a43e8 100644
--- a/bbb_cape/src/cape/gcc_arm.ld
+++ b/bbb_cape/src/cape/gcc_arm.ld
@@ -142,4 +142,9 @@
/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
+
+ .flash_end :
+ {
+ __flash_end = .;
+ } > FLASH
}
diff --git a/bbb_cape/src/cape/peripherial_usage.notes b/bbb_cape/src/cape/peripherial_usage.notes
index 757f14a..c8005c3 100644
--- a/bbb_cape/src/cape/peripherial_usage.notes
+++ b/bbb_cape/src/cape/peripherial_usage.notes
@@ -57,4 +57,4 @@
[robots]
robot_comp
TIM11
- TIM11_IRQ:3 (aka TIM1_TRG_COM)
+ TIM11_IRQ:1 (aka TIM1_TRG_COM)
diff --git a/bbb_cape/src/cape/robot_comp.c b/bbb_cape/src/cape/robot_comp.c
index cab3e28..c33dc36 100644
--- a/bbb_cape/src/cape/robot_comp.c
+++ b/bbb_cape/src/cape/robot_comp.c
@@ -6,9 +6,7 @@
#include "cape/analog.h"
#include "cape/digital.h"
#include "cape/util.h"
-
-// TIM11.1 on PB9, aka digital input 6.
-static volatile uint32_t ultrasonic_pulse_length = 0;
+#include "cape/timer.h"
typedef struct {
uint32_t posedges, negedges;
@@ -91,27 +89,15 @@
CLAW(10, 11, 9, bottom_claw, 7);
SHOOTER(7, 5, 4, 8, 0)
-void TIM1_TRG_COM_TIM11_IRQHandler(void) {
- TIM11->SR = ~TIM_SR_CC1IF;
- if (digital_read(6)) {
- TIM11->EGR = TIM_EGR_UG;
- } else {
- ultrasonic_pulse_length = TIM11->CCR1;
- }
-}
+// TIM11.1 on PB9, aka digital input 6.
+timer_declare(TIM11, TIM1_TR_GCOM_TIM11_IRQHandler, 1, 1, ultrasonic)
void robot_init(void) {
gpio_setup_alt(GPIOB, 9, 3);
RCC->APB2ENR |= RCC_APB2ENR_TIM11EN;
- TIM11->CR1 = TIM_CR1_URS;
- TIM11->DIER = TIM_DIER_CC1IE;
TIM11->CCMR1 = TIM_CCMR1_CC1S_0 /* input pin 1 -> timer input 1 */;
- TIM11->CCER = TIM_CCER_CC1P | TIM_CCER_CC1NP | TIM_CCER_CC1E;
- TIM11->EGR = TIM_EGR_UG;
- TIM11->PSC = 1200 - 1; // 100kHZ timer
- TIM11->CR1 |= TIM_CR1_CEN;
- NVIC_SetPriority(TIM1_TRG_COM_TIM11_IRQn, 3);
- NVIC_EnableIRQ(TIM1_TRG_COM_TIM11_IRQn);
+ TIM11->PSC = 1200 - 1; // 100KHz timer
+ //timer_setup(TIM11, TIM1_TRG_COM_TIM11_IRQn, 1);
}
void robot_fill_packet(struct DataStruct *packet) {
@@ -125,7 +111,7 @@
packet->main.battery_voltage_high = analog_get(5);
packet->main.battery_voltage_low = analog_get(3);
- packet->main.ultrasonic_pulse_length = ultrasonic_pulse_length;
+ packet->main.ultrasonic_pulse_length = ultrasonic_length;
fill_top_claw_values(packet);
fill_bottom_claw_values(packet);
diff --git a/bbb_cape/src/cape/timer.h b/bbb_cape/src/cape/timer.h
new file mode 100644
index 0000000..0cca0de
--- /dev/null
+++ b/bbb_cape/src/cape/timer.h
@@ -0,0 +1,34 @@
+#ifndef CAPE_TIMER_H_
+#define CAPE_TIMER_H_
+
+#include <STM32F2XX.h>
+
+// inverted is 1 for timing low periods, 0 for high ones.
+#define timer_declare(timer, irq, input, inverted, name) \
+ static volatile uint32_t name##_length = 0; \
+ void irq(void) { \
+ timer->SR = ~TIM_SR_CC##input##IF; \
+ const uint32_t ccer = timer->CCER; \
+ timer->CCER = ccer ^ (TIM_CCER_CC##input##P | TIM_CCER_CC##input##NP); \
+ const uint32_t rising = ccer & TIM_CCER_CC##input##P; \
+ if (inverted ? rising : !rising) { \
+ name##_length = timer->CCR##input; \
+ } else { \
+ timer->EGR = TIM_EGR_UG; \
+ } \
+ }
+
+// You need to enable the clock, set up the alt function for the input pin,
+// set the prescaler, and set up the timer input before calling this.
+#define timer_setup(timer, irq, input) \
+ do { \
+ timer->CR1 = TIM_CR1_URS; \
+ timer->DIER = TIM_DIER_CC##input##IE; \
+ timer->CCER = TIM_CCER_CC##input##P | TIM_CCER_CC##input##E; \
+ timer->EGR = TIM_EGR_UG; \
+ timer->CR1 |= TIM_CR1_CEN; \
+ NVIC_SetPriority(irq, 1); \
+ NVIC_EnableIRQ(irq); \
+ } while (0)
+
+#endif // CAPE_TIMER_H_
diff --git a/bbb_cape/src/flasher/flasher.gyp b/bbb_cape/src/flasher/flasher.gyp
index 2d506b8..fba1477 100644
--- a/bbb_cape/src/flasher/flasher.gyp
+++ b/bbb_cape/src/flasher/flasher.gyp
@@ -17,6 +17,7 @@
'<(EXTERNALS):stm32flash',
'<(AOS)/build/aos.gyp:logging',
'<(DEPTH)/bbb_cape/src/bbb/bbb.gyp:gpios',
+ '<(DEPTH)/bbb_cape/src/bbb/bbb.gyp:export_uart',
'<(AOS)/common/common.gyp:time',
],
},
diff --git a/bbb_cape/src/flasher/stm32_flasher.cc b/bbb_cape/src/flasher/stm32_flasher.cc
index 48887d2..a48abc4 100644
--- a/bbb_cape/src/flasher/stm32_flasher.cc
+++ b/bbb_cape/src/flasher/stm32_flasher.cc
@@ -19,6 +19,7 @@
}
#include "bbb/gpo.h"
+#include "bbb/export_uart.h"
namespace {
@@ -48,9 +49,6 @@
}
::std::string target = argv[1];
- //::std::string device = "/dev/ttyUSB0";
- // TODO(brians): Figure out an intelligent way to set the device to use.
- ::std::string device = "/dev/ttyO1";
serial_baud_t baud_rate = SERIAL_BAUD_57600;
::std::string filename =
@@ -112,17 +110,21 @@
LOG(FATAL, "opening file %s failed\n", filename.c_str());
}
- serial_t *serial = serial_open(device.c_str());
+ ::bbb::ExportUart();
+
+ const char *device = ::bbb::UartDevice();
+
+ serial_t *serial = serial_open(device);
if (serial == NULL) {
LOG(FATAL, "failed to open serial port %s because of %d: %s\n",
- device.c_str(), errno, strerror(errno));
+ device, errno, strerror(errno));
}
if (serial_setup(serial, baud_rate,
SERIAL_BITS_8,
SERIAL_PARITY_EVEN,
SERIAL_STOPBIT_1) != SERIAL_ERR_OK) {
LOG(FATAL, "setting up serial port %s failed because of %d: %s\n",
- device.c_str(), errno, strerror(errno));
+ device, errno, strerror(errno));
}
LOG(INFO, "serial configuration: %s\n", serial_get_setup_str(serial));
diff --git a/frc971/actions/action.h b/frc971/actions/action.h
index fe17676..9ae31e8 100644
--- a/frc971/actions/action.h
+++ b/frc971/actions/action.h
@@ -8,6 +8,7 @@
#include "aos/common/control_loop/Timing.h"
#include "aos/common/logging/logging.h"
#include "aos/common/network/team_number.h"
+#include "aos/common/time.h"
#include "frc971/constants.h"
@@ -57,18 +58,25 @@
}
}
- // will run until the done condition is met.
+ // will run until the done condition is met or times out.
// will return false if successful and true if the action was canceled or
- // failed.
+ // failed or end_time was reached before it succeeded.
// done condition are defined as functions that return true when done and have
// some sort of blocking statement(FetchNextBlocking) to throttle spin rate.
- bool WaitUntil(::std::function<bool(void)> done_condition) {
+ // end_time is when to stop and return true. Time(0, 0) (the default) means
+ // never time out.
+ bool WaitUntil(::std::function<bool(void)> done_condition,
+ const ::aos::time::Time &end_time = ::aos::time::Time(0, 0)) {
while (!done_condition()) {
if (ShouldCancel() || abort_) {
// Clear abort bit as we have just aborted.
abort_ = false;
return true;
}
+ if (::aos::time::Time::Now() >= end_time) {
+ LOG(INFO, "WaitUntil timed out\n");
+ return true;
+ }
}
if (ShouldCancel() || abort_) {
// Clear abort bit as we have just aborted.
diff --git a/frc971/actions/actions.gyp b/frc971/actions/actions.gyp
index 7cfb7a5..2a840f1 100644
--- a/frc971/actions/actions.gyp
+++ b/frc971/actions/actions.gyp
@@ -97,6 +97,7 @@
'action',
'shoot_action_queue',
'action_client',
+ '<(AOS)/common/common.gyp:time',
],
},
{
@@ -134,12 +135,14 @@
'<(AOS)/build/aos.gyp:logging',
'<(AOS)/common/network/network.gyp:team_number',
'<(DEPTH)/frc971/frc971.gyp:constants',
+ '<(AOS)/common/common.gyp:time',
],
'export_dependent_settings': [
'<(AOS)/common/common.gyp:timing',
'<(AOS)/build/aos.gyp:logging',
'<(AOS)/common/network/network.gyp:team_number',
'<(DEPTH)/frc971/frc971.gyp:constants',
+ '<(AOS)/common/common.gyp:time',
],
},
{
diff --git a/frc971/actions/shoot_action.cc b/frc971/actions/shoot_action.cc
index b1e27b4..3e73b67 100644
--- a/frc971/actions/shoot_action.cc
+++ b/frc971/actions/shoot_action.cc
@@ -12,6 +12,11 @@
namespace frc971 {
namespace actions {
+constexpr double ShootAction::kOffsetRadians;
+constexpr double ShootAction::kClawShootingSeparation;
+constexpr double ShootAction::kClawShootingSeparationGoal;
+constexpr ::aos::time::Time ShootAction::kTimeout;
+
ShootAction::ShootAction(actions::ShootActionQueueGroup* s)
: actions::ActionBase<actions::ShootActionQueueGroup>(s) {}
@@ -38,13 +43,18 @@
LOG(WARNING, "sending shooter goal failed\n");
return;
}
+
+ LOG(INFO, "finished\n");
}
void ShootAction::InnerRunAction() {
- LOG(INFO, "Shooting at the original angle and power.\n");
+ LOG(INFO, "Shooting at the current angle and power.\n");
+ const ::aos::time::Time end_time = ::aos::time::Time::Now() + kTimeout;
// wait for claw to be ready
- if (WaitUntil(::std::bind(&ShootAction::DoneSetupShot, this))) return;
+ if (WaitUntil(::std::bind(&ShootAction::DoneSetupShot, this), end_time)) {
+ return;
+ }
// Turn the intake off.
control_loops::claw_queue_group.goal.FetchLatest();
@@ -77,7 +87,7 @@
}
// wait for record of shot having been fired
- if (WaitUntil(::std::bind(&ShootAction::DoneShot, this))) return;
+ if (WaitUntil(::std::bind(&ShootAction::DoneShot, this), end_time)) return;
// Turn the intake off.
control_loops::claw_queue_group.goal.FetchLatest();
diff --git a/frc971/actions/shoot_action.h b/frc971/actions/shoot_action.h
index 6d29ca7..c5ebb07 100644
--- a/frc971/actions/shoot_action.h
+++ b/frc971/actions/shoot_action.h
@@ -1,5 +1,7 @@
#include <memory>
+#include "aos/common/time.h"
+
#include "frc971/actions/shoot_action.q.h"
#include "frc971/actions/action.h"
#include "frc971/actions/action_client.h"
@@ -23,6 +25,9 @@
static constexpr double kOffsetRadians = 0.4;
static constexpr double kClawShootingSeparation = 0.10;
static constexpr double kClawShootingSeparationGoal = 0.10;
+ // If we don't get to actually shooting within this amount of time, we stop to
+ // avoid firing unexpectedly after a long delay.
+ static constexpr ::aos::time::Time kTimeout = ::aos::time::Time::InSeconds(1);
protected:
// completed shot
diff --git a/frc971/actions/shoot_action.q b/frc971/actions/shoot_action.q
index d080071..081d627 100644
--- a/frc971/actions/shoot_action.q
+++ b/frc971/actions/shoot_action.q
@@ -8,10 +8,7 @@
message Goal {
// If true, run this action. If false, cancel the action if it is
// currently running.
- bool run; // Shot power in joules.
- double shot_power;
- // Claw angle when shooting.
- double shot_angle;
+ bool run;
};
queue Goal goal;
diff --git a/frc971/control_loops/claw/claw.q b/frc971/control_loops/claw/claw.q
index 116a182..53289ee 100644
--- a/frc971/control_loops/claw/claw.q
+++ b/frc971/control_loops/claw/claw.q
@@ -22,7 +22,7 @@
double negedge_value;
};
-// All angles here are 0 horizontal, positive up.
+// All angles here are 0 vertical, positive "up" (aka backwards).
queue_group ClawGroup {
implements aos.control_loops.ControlLoop;
diff --git a/frc971/input/joystick_reader.cc b/frc971/input/joystick_reader.cc
index 7b97bbd..698fe45 100644
--- a/frc971/input/joystick_reader.cc
+++ b/frc971/input/joystick_reader.cc
@@ -87,23 +87,29 @@
const ClawGoal kFlippedIntakeGoal = {2.0, kGrabSeparation};
const ClawGoal kFlippedIntakeOpenGoal = {0.95, 1.0};
-//const ShotGoal kLongShotGoal = {
- //{-M_PI / 2.0 + 0.46, kShootSeparation}, 120, false, kIntakePower};
+// 34" between near edge of colored line and rear edge of bumper
const ShotGoal kLongShotGoal = {
- {-1.04, kShootSeparation}, 140, 0.04, kIntakePower};
-const ShotGoal kMediumShotGoal = {
- {-0.90, kShootSeparation}, 105, 0.2, kIntakePower};
-const ShotGoal kShortShotGoal = {
- {-0.670, kShootSeparation}, 71.0, 0, kIntakePower};
-const ShotGoal kTrussShotGoal = {
- {-0.05, kShootSeparation}, 61.0, 0, kIntakePower};
-
+ {-1.06, kShootSeparation}, 140, 0.04, kIntakePower};
+// 3/4" plunger {-1.04, kShootSeparation}, 140, 0.04, kIntakePower};
const ShotGoal kFlippedLongShotGoal = {
{0.97, kShootSeparation}, 140, 0.08, kIntakePower};
+// 3/4 " plunger {0.97, kShootSeparation}, 140, 0.08, kIntakePower};
+
+// 78" between near edge of colored line and rear edge of bumper
+const ShotGoal kMediumShotGoal = {
+ {-0.95, kShootSeparation}, 105, 0.2, kIntakePower};
+// 3/4" plunger {-0.90, kShootSeparation}, 105, 0.2, kIntakePower};
const ShotGoal kFlippedMediumShotGoal = {
{0.80, kShootSeparation}, 105, 0.2, kIntakePower};
+// 3/4" plunger {0.80, kShootSeparation}, 105, 0.2, kIntakePower};
+
+const ShotGoal kShortShotGoal = {
+ {-0.670, kShootSeparation}, 71.0, 0.4, kIntakePower};
const ShotGoal kFlippedShortShotGoal = {
- {0.57, kShootSeparation}, 80.0, 0, kIntakePower};
+ {0.57, kShootSeparation}, 80.0, 0.4, kIntakePower};
+
+const ShotGoal kTrussShotGoal = {
+ {-0.05, kShootSeparation}, 73.0, 0, kIntakePower};
// Makes a new ShootAction action.
::std::unique_ptr<TypedAction< ::frc971::actions::CatchActionGroup>>
diff --git a/frc971/input/sensor_receiver.cc b/frc971/input/sensor_receiver.cc
index 7648db8..199df99 100644
--- a/frc971/input/sensor_receiver.cc
+++ b/frc971/input/sensor_receiver.cc
@@ -71,7 +71,8 @@
}
double sonar_translate(uint32_t in) {
- return static_cast<double>(in) / 1000.0 * 2.0;
+ return static_cast<double>(in) * 10.0 /*us/tick*/ / 147.0 /*in/us*/ *
+ 0.0254 /*m/in*/;
}
double hall_translate(const constants::ShifterHallEffect &k, uint16_t in_low,
@@ -138,8 +139,8 @@
const ::aos::time::Time &cape_timestamp,
State *state) {
::frc971::logging_structs::CapeReading reading_to_log(
- cape_timestamp.sec(), cape_timestamp.nsec(),
- sizeof(*data), sonar_translate(data->main.ultrasonic_pulse_length),
+ cape_timestamp, static_cast<uint16_t>(sizeof(*data)),
+ sonar_translate(data->main.ultrasonic_pulse_length),
data->main.low_left_drive_hall, data->main.high_left_drive_hall,
data->main.low_right_drive_hall, data->main.high_right_drive_hall);
LOG_STRUCT(DEBUG, "cape reading", reading_to_log);
diff --git a/frc971/output/motor_writer.cc b/frc971/output/motor_writer.cc
index dca221b..eefd7d6 100644
--- a/frc971/output/motor_writer.cc
+++ b/frc971/output/motor_writer.cc
@@ -12,11 +12,10 @@
#include "frc971/control_loops/drivetrain/drivetrain.q.h"
#include "frc971/control_loops/claw/claw.q.h"
#include "frc971/control_loops/shooter/shooter.q.h"
+#include "frc971/queues/output_check.q.h"
using ::aos::util::SimpleLogInterval;
-using ::frc971::control_loops::drivetrain;
-
namespace frc971 {
namespace output {
@@ -39,13 +38,14 @@
values_.solenoid_module = 0;
if (true) {
- drivetrain.output.FetchLatest();
- if (drivetrain.output.IsNewerThanMS(kOutputMaxAgeMS)) {
- LOG_STRUCT(DEBUG, "will output", *drivetrain.output.get());
- SetPWMOutput(3, drivetrain.output->right_voltage / 12.0, kTalonBounds);
- SetPWMOutput(6, -drivetrain.output->left_voltage / 12.0, kTalonBounds);
- SetSolenoid(7, drivetrain.output->left_high);
- SetSolenoid(8, drivetrain.output->right_high);
+ static auto &drivetrain = ::frc971::control_loops::drivetrain.output;
+ drivetrain.FetchLatest();
+ if (drivetrain.IsNewerThanMS(kOutputMaxAgeMS)) {
+ LOG_STRUCT(DEBUG, "will output", *drivetrain);
+ SetPWMOutput(3, drivetrain->right_voltage / 12.0, kTalonBounds);
+ SetPWMOutput(6, -drivetrain->left_voltage / 12.0, kTalonBounds);
+ SetSolenoid(7, drivetrain->left_high);
+ SetSolenoid(8, drivetrain->right_high);
} else {
DisablePWMOutput(3);
DisablePWMOutput(8);
@@ -59,7 +59,7 @@
::frc971::control_loops::shooter_queue_group.output;
shooter.FetchLatest();
if (shooter.IsNewerThanMS(kOutputMaxAgeMS)) {
- LOG_STRUCT(DEBUG, "will output", *shooter.get());
+ LOG_STRUCT(DEBUG, "will output", *shooter);
SetPWMOutput(7, shooter->voltage / 12.0, kTalonBounds);
SetSolenoid(6, !shooter->latch_piston);
SetSolenoid(5, !shooter->brake_piston);
@@ -75,7 +75,7 @@
static auto &claw = ::frc971::control_loops::claw_queue_group.output;
claw.FetchLatest();
if (claw.IsNewerThanMS(kOutputMaxAgeMS)) {
- LOG_STRUCT(DEBUG, "will output", *claw.get());
+ LOG_STRUCT(DEBUG, "will output", *claw);
SetPWMOutput(9, claw->intake_voltage / 12.0, kTalonBounds);
SetPWMOutput(8, claw->intake_voltage / 12.0, kTalonBounds);
SetPWMOutput(1, -claw->bottom_claw_voltage / 12.0, kTalonBounds);
@@ -93,6 +93,16 @@
}
claw_old_.Print();
}
+
+ {
+ auto message = ::frc971::output_check_queue.MakeMessage();
+ ++output_check_;
+ if (output_check_ == 0) output_check_ = 1;
+ SetRawPWMOutput(10, output_check_);
+ message->sent_value = output_check_;
+ LOG_STRUCT(DEBUG, "sending", *message);
+ message.Send();
+ }
}
SimpleLogInterval drivetrain_old_ =
@@ -101,6 +111,8 @@
SimpleLogInterval(kOldLogInterval, WARNING, "shooter too old");
SimpleLogInterval claw_old_ =
SimpleLogInterval(kOldLogInterval, WARNING, "claw too old");
+
+ uint8_t output_check_ = 0;
};
constexpr ::aos::time::Time MotorWriter::kOldLogInterval;
diff --git a/frc971/output/output.gyp b/frc971/output/output.gyp
index bc2d604..de41943 100644
--- a/frc971/output/output.gyp
+++ b/frc971/output/output.gyp
@@ -53,6 +53,7 @@
'<(AOS)/common/logging/logging.gyp:queue_logging',
'<(DEPTH)/frc971/control_loops/claw/claw.gyp:claw_loop',
'<(DEPTH)/frc971/control_loops/shooter/shooter.gyp:shooter_loop',
+ '<(DEPTH)/frc971/queues/queues.gyp:output_check',
],
},
],
diff --git a/frc971/prime/camera/camera.gyp b/frc971/prime/camera/camera.gyp
deleted file mode 100644
index 6a6b13c..0000000
--- a/frc971/prime/camera/camera.gyp
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- 'targets': [
- {
- 'target_name': 'frc971_camera',
- 'variables': {
- 'srcdirs': ['.'],
- 'manifest': 'frc971_camera.mf',
- },
- 'dependencies': [
- '<(AOS)/linux_code/camera/camera.gyp:aos_camera',
- '<(DEPTH)/frc971/queues/queues.gyp:frc971_queues_so',
- ],
- 'export_dependent_settings': [
- '<(AOS)/linux_code/camera/camera.gyp:aos_camera',
- '<(DEPTH)/frc971/queues/queues.gyp:frc971_queues_so',
- ],
- 'includes': ['../../../aos/build/java.gypi'],
- },
- {
- 'target_name': 'frc971',
- 'variables': {
- 'main_jar': 'frc971_camera',
- },
- 'dependencies': [
- 'frc971_camera',
- ],
- 'includes': ['../../../aos/build/onejar.gypi'],
- },
- ],
-}
diff --git a/frc971/prime/camera/frc971_camera.mf b/frc971/prime/camera/frc971_camera.mf
deleted file mode 100644
index e3929a2..0000000
--- a/frc971/prime/camera/frc971_camera.mf
+++ /dev/null
@@ -1,2 +0,0 @@
-Main-Class: org.spartanrobotics.camera.Test
-
diff --git a/frc971/prime/camera/org/spartanrobotics/camera/QueueReader.java b/frc971/prime/camera/org/spartanrobotics/camera/QueueReader.java
deleted file mode 100644
index 347b0c2..0000000
--- a/frc971/prime/camera/org/spartanrobotics/camera/QueueReader.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.spartanrobotics.camera;
-
-import aos.NativeLoader;
-import aos.QueueLogHandler;
-import frc971.control_loops.Piston_q;
-
-public class QueueReader {
-
- public static void main(String[] args) {
- QueueLogHandler.UseForAll();
- NativeLoader.load("frc971_queues_so");
- System.out.println(Piston_q.shifters.FetchLatest());
- System.out.println(Piston_q.shifters.getSet());
- }
-
-}
diff --git a/frc971/prime/camera/org/spartanrobotics/camera/QueueTest.java b/frc971/prime/camera/org/spartanrobotics/camera/QueueTest.java
deleted file mode 100644
index a71f447..0000000
--- a/frc971/prime/camera/org/spartanrobotics/camera/QueueTest.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.spartanrobotics.camera;
-
-import aos.NativeLoader;
-import aos.QueueLogHandler;
-import frc971.control_loops.Piston_q;
-
-public class QueueTest {
-
- public static void main(String[] args) {
- QueueLogHandler.UseForAll();
- NativeLoader.load("frc971_queues_so");
- Piston_q.shifters.SafeMakeWithBuilder().set(false).Send();
- }
-
-}
diff --git a/frc971/prime/camera/org/spartanrobotics/camera/Test.java b/frc971/prime/camera/org/spartanrobotics/camera/Test.java
deleted file mode 100644
index 86c06bc..0000000
--- a/frc971/prime/camera/org/spartanrobotics/camera/Test.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.spartanrobotics.camera;
-
-import java.io.IOException;
-import com.googlecode.javacv.cpp.opencv_core;
-import com.googlecode.javacv.cpp.opencv_core.CvPoint;
-import com.googlecode.javacv.cpp.opencv_core.CvScalar;
-import com.googlecode.javacv.cpp.opencv_core.IplImage;
-import com.googlecode.javacv.cpp.opencv_imgproc;
-
-import aos.CameraProcessor;
-import aos.DebugServer;
-import aos.ImageGetter;
-import aos.ServableImage;
-import aos.Thresholder;
-
-public class Test extends CameraProcessor {
- private final DebugServer server = new DebugServer(9719);
- private final IplImage hsv = IplImage.create(ImageGetter.width, ImageGetter.height, opencv_core.IPL_DEPTH_8U, 3);
- private final ServableImage thresholded = new ServableImage(ImageGetter.width, ImageGetter.height, opencv_core.IPL_DEPTH_8U, 1);
-
- private Test(String[] args) throws IOException {
- super(args);
-
- server.addImage("/start", start);
- server.addImage("/thresholded", thresholded, new DebugServer.Palette().add(0, 0, 0, 0).add(0, 0xFF, 0, 0xFF).add(0, 0, 0xFF, 0xFF));
- }
-
- @Override
- protected void RunIteration() {
- server.setTimestamp(getter.getTimestamp());
-
- opencv_imgproc.cvCvtColor(start.getImage(), hsv, opencv_imgproc.CV_RGB2HSV);
- Thresholder.threshold(hsv, thresholded.getImage(), 0, 100, 160, 0, 255, 0, 255);
- thresholded.recordSnapshot(1);
- if (thresholded.isDebugging()) {
- opencv_core.cvCircle(thresholded.getImage(), new CvPoint(200, 200), 50, new CvScalar(2, 2, 2, 2), 5, 8, 0);
- }
- thresholded.releaseImage();
- }
-
- public static void main(String[] args) throws IOException {
- new Test(args).Run();
- }
-}
diff --git a/frc971/prime/prime.gyp b/frc971/prime/prime.gyp
index c4db795..3ad28ba 100644
--- a/frc971/prime/prime.gyp
+++ b/frc971/prime/prime.gyp
@@ -27,11 +27,30 @@
'<(DEPTH)/bbb_cape/src/flasher/flasher.gyp:stm32_flasher',
'../output/output.gyp:led_setter',
],
+ 'variables': {
+ 'cape_src': '<(DEPTH)/bbb_cape/src/cape',
+ 'cape_hex': '<(cape_src)/.obj/main_comp.hex',
+ },
+ 'actions': [
+ {
+ 'action_name': 'make_cape',
+ 'inputs': [
+ '<!@(find <(cape_src) -name ".*" -prune -o -type f -print)',
+ '<(cape_src)/Makefile',
+ ],
+ 'outputs': [
+ '<(cape_hex)',
+ ],
+ 'action': ['make', '-C', '<(cape_src)'],
+ 'message': 'Building cape code',
+ },
+ ],
'copies': [
{
'destination': '<(rsync_dir)',
'files': [
'start_list.txt',
+ '<(cape_hex)',
],
},
],
diff --git a/frc971/queues/output_check.q b/frc971/queues/output_check.q
new file mode 100644
index 0000000..0573426
--- /dev/null
+++ b/frc971/queues/output_check.q
@@ -0,0 +1,8 @@
+package frc971;
+
+message OutputCheck {
+ uint8_t sent_value;
+};
+// Each message here represents a value that was sent to the cRIO.
+// The sent timestamp of the message is when the value was sent.
+queue OutputCheck output_check_queue;
diff --git a/frc971/queues/queues.gyp b/frc971/queues/queues.gyp
index 8434437..d71be25 100644
--- a/frc971/queues/queues.gyp
+++ b/frc971/queues/queues.gyp
@@ -22,19 +22,14 @@
'includes': ['../../aos/build/queues.gypi'],
},
{
- 'target_name': 'frc971_queues_so',
- 'type': 'loadable_module',
- 'sources': ['<@(queue_files)'],
+ 'target_name': 'output_check',
+ 'type': 'static_library',
+ 'sources': [
+ 'output_check.q',
+ ],
'variables': {
'header_path': 'frc971/queues',
},
- 'dependencies': [
- ],
- 'direct_dependent_settings': {
- 'variables': {
- 'jni_libs': ['frc971_queues_so'],
- },
- },
'includes': ['../../aos/build/queues.gypi'],
},
],
diff --git a/frc971/queues/to_log.q b/frc971/queues/to_log.q
index ded9b64..341d921 100644
--- a/frc971/queues/to_log.q
+++ b/frc971/queues/to_log.q
@@ -1,9 +1,8 @@
package frc971.logging_structs;
struct CapeReading {
- uint32_t sec;
- uint32_t nsec;
- uint64_t struct_size;
+ Time time;
+ uint16_t struct_size;
double sonar;
uint16_t left_low;