Make raw senders able to send flatbuffers

The senders were placing in the front of the memory region, and the
readers were reading from the end of the memory region.  Align the
raw senders with how flatbuffers use the memory.

This was found by trying to implement message_gateway.

Change-Id: I2d8fd5b6faafbbaf268ee036c851417cf5a02c74
diff --git a/aos/events/event_loop_param_test.cc b/aos/events/event_loop_param_test.cc
index 834ca16..cf3b6df 100644
--- a/aos/events/event_loop_param_test.cc
+++ b/aos/events/event_loop_param_test.cc
@@ -1099,5 +1099,51 @@
   EXPECT_EQ(primary_report.message().fetchers()->Get(1)->count(), 10);
 }
 
+// Tests that a raw watcher and raw fetcher can receive messages from a raw
+// sender without messing up offsets.
+TEST_P(AbstractEventLoopTest, RawBasic) {
+  auto loop1 = Make();
+  auto loop2 = MakePrimary();
+  auto loop3 = Make();
+
+  const std::string kData("971 is the best");
+
+  std::unique_ptr<aos::RawSender> sender =
+      loop1->MakeRawSender(loop1->configuration()->channels()->Get(1));
+
+  std::unique_ptr<aos::RawFetcher> fetcher =
+      loop3->MakeRawFetcher(loop3->configuration()->channels()->Get(1));
+
+  loop2->OnRun(
+      [&]() { EXPECT_TRUE(sender->Send(kData.data(), kData.size())); });
+
+  bool happened = false;
+  loop2->MakeRawWatcher(
+      loop2->configuration()->channels()->Get(1),
+      [this, &kData, &fetcher, &happened](const Context &context,
+                                          const void *message) {
+        happened = true;
+        EXPECT_EQ(std::string_view(kData),
+                  std::string_view(reinterpret_cast<const char *>(message),
+                                   context.size));
+        EXPECT_EQ(std::string_view(kData),
+                  std::string_view(reinterpret_cast<const char *>(context.data),
+                                   context.size));
+
+        ASSERT_TRUE(fetcher->Fetch());
+
+        EXPECT_EQ(std::string_view(kData),
+                  std::string_view(
+                      reinterpret_cast<const char *>(fetcher->context().data),
+                      fetcher->context().size));
+
+        this->Exit();
+      });
+
+  EXPECT_FALSE(happened);
+  Run();
+  EXPECT_TRUE(happened);
+}
+
 }  // namespace testing
 }  // namespace aos
diff --git a/aos/ipc_lib/lockless_queue.cc b/aos/ipc_lib/lockless_queue.cc
index a4539f8..0c87e4d 100644
--- a/aos/ipc_lib/lockless_queue.cc
+++ b/aos/ipc_lib/lockless_queue.cc
@@ -549,7 +549,10 @@
 
 void LocklessQueue::Sender::Send(const char *data, size_t length) {
   CHECK_LE(length, size());
-  memcpy(Data(), data, length);
+  // Flatbuffers write from the back of the buffer to the front.  If we are
+  // going to write an explicit chunk of memory into the buffer, we need to
+  // adhere to this convention and place it at the end.
+  memcpy((reinterpret_cast<char *>(Data()) + size() - length), data, length);
   Send(length);
 }
 
diff --git a/aos/ipc_lib/lockless_queue_death_test.cc b/aos/ipc_lib/lockless_queue_death_test.cc
index 6b3f7c5..e3d6c5e 100644
--- a/aos/ipc_lib/lockless_queue_death_test.cc
+++ b/aos/ipc_lib/lockless_queue_death_test.cc
@@ -595,8 +595,10 @@
             break;
           }
 
-          EXPECT_GT(read_data[6], last_data) << ": Got " << read_data;
-          last_data = read_data[6];
+          EXPECT_GT(read_data[queue.message_data_size() - length + 6],
+                    last_data)
+              << ": Got " << read_data;
+          last_data = read_data[queue.message_data_size() - length + 6];
 
           ++i;
         }
diff --git a/aos/ipc_lib/queue_racer.cc b/aos/ipc_lib/queue_racer.cc
index bb754d8..f3b9d5c 100644
--- a/aos/ipc_lib/queue_racer.cc
+++ b/aos/ipc_lib/queue_racer.cc
@@ -278,7 +278,8 @@
 
     ThreadPlusCount tpc;
     ASSERT_EQ(length, sizeof(ThreadPlusCount));
-    memcpy(&tpc, read_data, sizeof(ThreadPlusCount));
+    memcpy(&tpc, read_data + queue.message_data_size() - length,
+           sizeof(ThreadPlusCount));
 
     if (will_wrap) {
       // The queue won't chang out from under us, so we should get some amount