Enforce channel message limits when building configs

We only support 2^16-1 messages/channel.  Enforce this when building the
configuration, rather than at runtime in the simulation.  This will
make the errors cleaner and more direct.

Change-Id: I368f6c6596a7b0eaa562a70cd385ca1b94e10b93
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/aos/configuration.cc b/aos/configuration.cc
index db00ce7..736f772 100644
--- a/aos/configuration.cc
+++ b/aos/configuration.cc
@@ -29,6 +29,8 @@
 
 namespace aos {
 namespace {
+namespace chrono = std::chrono;
+
 bool EndsWith(std::string_view str, std::string_view end) {
   if (str.size() < end.size()) {
     return false;
@@ -358,6 +360,12 @@
                    << ", can only use [-a-zA-Z0-9_/]";
       }
 
+      CHECK_LT(QueueSize(&config.message(), c) + QueueScratchBufferSize(c),
+               std::numeric_limits<uint16_t>::max())
+          << ": More messages/second configured than the queue can hold on "
+          << CleanedChannelToString(c) << ", " << c->frequency() << "hz for "
+          << config.message().channel_storage_duration() << "ns";
+
       if (c->has_logger_nodes()) {
         // Confirm that we don't have duplicate logger nodes.
         absl::btree_set<std::string_view> logger_nodes;
@@ -1564,5 +1572,22 @@
   return result;
 }
 
+int QueueSize(const Configuration *config, const Channel *channel) {
+  return QueueSize(channel->frequency(),
+                   chrono::nanoseconds(config->channel_storage_duration()));
+}
+
+int QueueSize(size_t frequency, chrono::nanoseconds channel_storage_duration) {
+  // Use integer arithmetic and round up at all cost.
+  return static_cast<int>(
+      (999999999 + static_cast<int64_t>(frequency) *
+                       static_cast<int64_t>(channel_storage_duration.count())) /
+      static_cast<int64_t>(1000000000));
+}
+
+int QueueScratchBufferSize(const Channel *channel) {
+  return channel->num_readers() + channel->num_senders();
+}
+
 }  // namespace configuration
 }  // namespace aos