New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPI Plugin - added APA102 #722

Merged
merged 49 commits into from Jun 3, 2015
Commits
Jump to file or symbol
Failed to load files and symbols.
+304 −1
Diff settings

Always

Just for now

View
@@ -23,6 +23,10 @@ Thumbs.db
*/*/Thumbs.db
*/*/*/.dirstamp
*/*/*/Thumbs.db
.DS_Store
*.bak
**/nppBackup
.~lock.*
INSTALL
Makefile
Makefile.in
View
@@ -86,9 +86,12 @@ const uint8_t SPIOutput::SPI_MODE = 0;
const uint16_t SPIOutput::WS2801_SLOTS_PER_PIXEL = 3;
const uint16_t SPIOutput::LPD8806_SLOTS_PER_PIXEL = 3;
const uint16_t SPIOutput::P9813_SLOTS_PER_PIXEL = 3;
const uint16_t SPIOutput::APA102_SLOTS_PER_PIXEL = 3;
// Number of bytes that each P9813 pixel uses on the spi wires
// Number of bytes that each pixel uses on the spi wires

This comment has been minimized.

@peternewman

peternewman May 9, 2015

Member

SPaG SPI

@peternewman

peternewman May 9, 2015

Member

SPaG SPI

// (if it differs from 1:1 with colors)
const uint16_t SPIOutput::P9813_SPI_BYTES_PER_PIXEL = 4;
const uint16_t SPIOutput::APA102_SPI_BYTES_PER_PIXEL = 4;
SPIOutput::RDMOps *SPIOutput::RDMOps::instance = NULL;
@@ -187,6 +190,10 @@ SPIOutput::SPIOutput(const UID &uid, SPIBackendInterface *backend,
"P9813 Individual Control"));
personalities.push_back(Personality(P9813_SLOTS_PER_PIXEL,
"P9813 Combined Control"));
personalities.push_back(Personality(m_pixel_count * APA102_SLOTS_PER_PIXEL,
"APA102 Individual Control"));
personalities.push_back(Personality(APA102_SLOTS_PER_PIXEL,
"APA102 Combined Control"));
m_personality_collection.reset(new PersonalityCollection(personalities));
m_personality_manager.reset(new PersonalityManager(
m_personality_collection.get()));
@@ -281,6 +288,7 @@ void SPIOutput::SendRDMRequest(const RDMRequest *request,
request, callback);
}

This comment has been minimized.

@peternewman

peternewman May 9, 2015

Member

Can you remove the extra line please.

@peternewman

peternewman May 9, 2015

Member

Can you remove the extra line please.

bool SPIOutput::InternalWriteDMX(const DmxBuffer &buffer) {
switch (m_personality_manager->ActivePersonalityNumber()) {
case 1:
@@ -301,6 +309,12 @@ bool SPIOutput::InternalWriteDMX(const DmxBuffer &buffer) {
case 6:
CombinedP9813Control(buffer);
break;
case 7:
IndividualAPA102Control(buffer);
break;
case 8:
CombinedAPA102Control(buffer);
break;
default:
break;
}
@@ -486,6 +500,100 @@ uint8_t SPIOutput::P9813CreateFlag(uint8_t red, uint8_t green, uint8_t blue) {
return ~flag;
}
void SPIOutput::IndividualAPA102Control(const DmxBuffer &buffer) {
// some detailed information on the protocol:
// https://cpldcpu.wordpress.com/2014/11/30/understanding-the-apa102-superled/
// Data-Struct
// StartFrame: 4Byte = 32Bits zeros
// LEDFrame: 1Byte FF ; 3Byte color info (Blue, Green, Red)
// EndFrame: (n/2)bits; n = pixel_count
// i don't know how this works.. but it works ;-)
const uint8_t latch_bytes = 3 * APA102_SPI_BYTES_PER_PIXEL;
const unsigned int first_slot = m_start_address - 1; // 0 offset
// only do something if minimum 1pixel can be updated..

This comment has been minimized.

@peternewman

peternewman May 18, 2015

Member

Nit: perhaps rewrite this to "Only do something if at least one pixel can be updated..."

@peternewman

peternewman May 18, 2015

Member

Nit: perhaps rewrite this to "Only do something if at least one pixel can be updated..."

if (buffer.Size() - first_slot < APA102_SLOTS_PER_PIXEL) {

This comment has been minimized.

@peternewman

peternewman May 28, 2015

Member

Can you add brackets round the negation please.

@peternewman

peternewman May 28, 2015

Member

Can you add brackets round the negation please.

This comment has been minimized.

@nomis52

nomis52 May 28, 2015

Member

No, please don't, they aren't needed here and just clutter the code.

@nomis52

nomis52 May 28, 2015

Member

No, please don't, they aren't needed here and just clutter the code.

This comment has been minimized.

@peternewman

peternewman May 28, 2015

Member

Okay.

@peternewman
// not even 3 bytes of data, don't bother updating
return;

This comment has been minimized.

@peternewman

peternewman May 10, 2015

Member

Can you add the OLA_INFO statement you've got in the same check within Combined please.

@peternewman

peternewman May 10, 2015

Member

Can you add the OLA_INFO statement you've got in the same check within Combined please.

}

This comment has been minimized.

@s-light

s-light May 13, 2015

Contributor

just a style question:
from my feeling i would write this in 'positiv-logic' so i do not have multiple breakout/return points in the function -

// only do something if minimum 1pixel can be updated..
if ((buffer.Size() - first_slot) >= APA102_SLOTS_PER_PIXEL) {
  // the ongoing function
  .....
} else {
  OLA_INFO << "Insufficient DMX data, required " << APA102_SLOTS_PER_PIXEL
           << ", got " << buffer.Size() - first_slot;
}

how do you prefer it?

@s-light

s-light May 13, 2015

Contributor

just a style question:
from my feeling i would write this in 'positiv-logic' so i do not have multiple breakout/return points in the function -

// only do something if minimum 1pixel can be updated..
if ((buffer.Size() - first_slot) >= APA102_SLOTS_PER_PIXEL) {
  // the ongoing function
  .....
} else {
  OLA_INFO << "Insufficient DMX data, required " << APA102_SLOTS_PER_PIXEL
           << ", got " << buffer.Size() - first_slot;
}

how do you prefer it?

This comment has been minimized.

@peternewman

peternewman May 13, 2015

Member

Very much a @nomis52 one. I'd generally prefer what you're suggesting, but most/all of the C++ code uses the early returns. I guess the main upside is its easier to read than a few levels of nested ifs.

@peternewman

peternewman May 13, 2015

Member

Very much a @nomis52 one. I'd generally prefer what you're suggesting, but most/all of the C++ code uses the early returns. I guess the main upside is its easier to read than a few levels of nested ifs.

This comment has been minimized.

@nomis52

nomis52 May 14, 2015

Member

We prefer early returns for the reasons Peter mentioned.

@nomis52

nomis52 May 14, 2015

Member

We prefer early returns for the reasons Peter mentioned.

This comment has been minimized.

@peternewman

peternewman May 28, 2015

Member

@s-light has sorted this now.

@peternewman

peternewman May 28, 2015

Member

@s-light has sorted this now.

// We always check out the entire string length, even if we only have data
// for part of it
const unsigned int output_length = m_pixel_count * APA102_SPI_BYTES_PER_PIXEL;
uint8_t *output = m_backend->Checkout(m_output_number, output_length,
latch_bytes);
// only update spi data if possible

This comment has been minimized.

@peternewman

peternewman May 10, 2015

Member

SPaG SPI

@peternewman

peternewman May 10, 2015

Member

SPaG SPI

if (!output)

This comment has been minimized.

@peternewman

peternewman May 10, 2015

Member

Can you add { } brackets around the return, so we don't have a dangling statement.

@peternewman

peternewman May 10, 2015

Member

Can you add { } brackets around the return, so we don't have a dangling statement.

return;

This comment has been minimized.

@nomis52

nomis52 Jun 1, 2015

Member

Please initialize the first 4 bytes here as well rather than relying on the defaults.

@nomis52

nomis52 Jun 1, 2015

Member

Please initialize the first 4 bytes here as well rather than relying on the defaults.

This comment has been minimized.

@s-light

s-light Jun 2, 2015

Contributor

done

@s-light

s-light Jun 2, 2015

Contributor

done

for (unsigned int i = 0; i < m_pixel_count; i++) {
// Convert RGB to APA102 Pixel
unsigned int offset = first_slot + i * APA102_SLOTS_PER_PIXEL;
// We need to avoid the first 4 bytes of the buffer since that acts as a
// start of frame delimiter
unsigned int spi_offset = (i + 1) * APA102_SPI_BYTES_PER_PIXEL;
uint8_t r = 0;
uint8_t b = 0;
uint8_t g = 0;
if (buffer.Size() - offset >= APA102_SLOTS_PER_PIXEL) {
r = buffer.Get(offset);
g = buffer.Get(offset + 1);
b = buffer.Get(offset + 2);
}
// first Byte contains:
// 3bit start mark (111) + 5bit GlobalBrightnes

This comment has been minimized.

@peternewman

peternewman May 28, 2015

Member

Minor nit 3 bits, 5 bits

@peternewman

peternewman May 28, 2015

Member

Minor nit 3 bits, 5 bits

This comment has been minimized.

@peternewman

peternewman May 28, 2015

Member

SPaG Brightness, but perhaps change it to global brightness

@peternewman

peternewman May 28, 2015

Member

SPaG Brightness, but perhaps change it to global brightness

// set GlobalBrightnes fixed to 31 --> that reduces flickering

This comment has been minimized.

@peternewman

peternewman May 28, 2015

Member

SPaG Brightness, or global brightness

@peternewman

peternewman May 28, 2015

Member

SPaG Brightness, or global brightness

// that can be written as 0xE0 & 0x1F
output[spi_offset + 0] = 0xFF;

This comment has been minimized.

@nomis52

nomis52 Jun 1, 2015

Member

remove the + 0

@nomis52

nomis52 Jun 1, 2015

Member

remove the + 0

output[spi_offset + 1] = b;
output[spi_offset + 2] = g;
output[spi_offset + 3] = r;
}
m_backend->Commit(m_output_number);
}
void SPIOutput::CombinedAPA102Control(const DmxBuffer &buffer) {
// for Protocol details see IndividualAPA102Control
const uint8_t latch_bytes = 3 * APA102_SPI_BYTES_PER_PIXEL;

This comment has been minimized.

@nomis52

nomis52 May 2, 2015

Member

I think this should be

const uint8_t latch_bits = m_pixel_count / 2;
const uint8_t latch_bytes = (latch_bits / 8) + (latch_bits % 8 ? 1: 0);

Same comment above, so I'd move this into a function:

CalculateAPA102LatchBytes(m_pixel_count);

@nomis52

nomis52 May 2, 2015

Member

I think this should be

const uint8_t latch_bits = m_pixel_count / 2;
const uint8_t latch_bytes = (latch_bits / 8) + (latch_bits % 8 ? 1: 0);

Same comment above, so I'd move this into a function:

CalculateAPA102LatchBytes(m_pixel_count);

const unsigned int first_slot = m_start_address - 1; // 0 offset
// check if enough data is there.
if (buffer.Size() - first_slot < APA102_SLOTS_PER_PIXEL) {
OLA_INFO << "Insufficient DMX data, required " << APA102_SLOTS_PER_PIXEL
<< ", got " << buffer.Size() - first_slot;
return;
}
// get data for entire string length
const unsigned int output_length = m_pixel_count * APA102_SPI_BYTES_PER_PIXEL;

This comment has been minimized.

@nomis52

nomis52 May 2, 2015

Member

This should be

const unsigned int output_length = (1 + m_pixel_count) * APA102_SPI_BYTES_PER_PIXEL;

@nomis52

nomis52 May 2, 2015

Member

This should be

const unsigned int output_length = (1 + m_pixel_count) * APA102_SPI_BYTES_PER_PIXEL;

uint8_t *output = m_backend->Checkout(m_output_number, output_length,
latch_bytes);

This comment has been minimized.

@nomis52

nomis52 May 7, 2015

Member

I'd call CalculateAPA102LatchBytes(m_pixel_count) here and remove the temporary. Same in the method above as well.

@nomis52

nomis52 May 7, 2015

Member

I'd call CalculateAPA102LatchBytes(m_pixel_count) here and remove the temporary. Same in the method above as well.

// only update spi data if possible
if (!output)

This comment has been minimized.

@peternewman

peternewman May 10, 2015

Member

Add {} again

@peternewman

peternewman May 10, 2015

Member

Add {} again

return;
// create Pixel Data
uint8_t pixel_data[APA102_SPI_BYTES_PER_PIXEL];
pixel_data[0] = 0xff;

This comment has been minimized.

@peternewman

peternewman May 10, 2015

Member

0xFF please.

@peternewman

peternewman May 10, 2015

Member

0xFF please.

pixel_data[1] = buffer.Get(first_slot + 2); // Get Blue
pixel_data[2] = buffer.Get(first_slot + 1); // Get Green
pixel_data[3] = buffer.Get(first_slot); // Get Red
// set all pixel to same value
for (unsigned int i = 0; i < m_pixel_count; i++) {

This comment has been minimized.

@nomis52

nomis52 May 2, 2015

Member

I'd do

for (unsigned int i = 1; i <= m_pixel_count; i++) {
...
}

@nomis52

nomis52 May 2, 2015

Member

I'd do

for (unsigned int i = 1; i <= m_pixel_count; i++) {
...
}

memcpy(&output[(i + 1) * APA102_SPI_BYTES_PER_PIXEL], pixel_data,
APA102_SPI_BYTES_PER_PIXEL);
}
// write output back...
m_backend->Commit(m_output_number);
}
const RDMResponse *SPIOutput::GetDeviceInfo(const RDMRequest *request) {
return ResponderHelper::GetDeviceInfo(
request, ola::rdm::OLA_SPI_DEVICE_MODEL,
View
@@ -104,12 +104,16 @@ class SPIOutput: public ola::rdm::DiscoverableRDMControllerInterface {
// DMX methods
bool InternalWriteDMX(const DmxBuffer &buffer);
void IndividualWS2801Control(const DmxBuffer &buffer);
void CombinedWS2801Control(const DmxBuffer &buffer);
void IndividualLPD8806Control(const DmxBuffer &buffer);
void CombinedLPD8806Control(const DmxBuffer &buffer);
void IndividualP9813Control(const DmxBuffer &buffer);
void CombinedP9813Control(const DmxBuffer &buffer);
void IndividualAPA102Control(const DmxBuffer &buffer);
void CombinedAPA102Control(const DmxBuffer &buffer);
unsigned int LPD8806BufferSize() const;
void WriteSPIData(const uint8_t *data, unsigned int length);
@@ -178,6 +182,8 @@ class SPIOutput: public ola::rdm::DiscoverableRDMControllerInterface {
static const uint16_t LPD8806_SLOTS_PER_PIXEL;
static const uint16_t P9813_SLOTS_PER_PIXEL;
static const uint16_t P9813_SPI_BYTES_PER_PIXEL;
static const uint16_t APA102_SLOTS_PER_PIXEL;
static const uint16_t APA102_SPI_BYTES_PER_PIXEL;
static const ola::rdm::ResponderOps<SPIOutput>::ParamHandler
PARAM_HANDLERS[];
@@ -45,6 +45,8 @@ class SPIOutputTest: public CppUnit::TestFixture {
CPPUNIT_TEST(testCombinedLPD8806Control);
CPPUNIT_TEST(testIndividualP9813Control);
CPPUNIT_TEST(testCombinedP9813Control);
CPPUNIT_TEST(testIndividualAPA102Control);
CPPUNIT_TEST(testCombinedAPA102Control);
CPPUNIT_TEST_SUITE_END();
public:
@@ -61,6 +63,8 @@ class SPIOutputTest: public CppUnit::TestFixture {
void testCombinedLPD8806Control();
void testIndividualP9813Control();
void testCombinedP9813Control();
void testIndividualAPA102Control();
void testCombinedAPA102Control();
private:
UID m_uid;
@@ -421,3 +425,184 @@ void SPIOutputTest::testCombinedP9813Control() {
backend.GetData(1, &length));
OLA_ASSERT_EQ(0u, backend.Writes(1));
}
/**
* Test DMX writes in the individual APA102 mode.
*/
void SPIOutputTest::testIndividualAPA102Control() {
// setup Backend
FakeSPIBackend backend(2);
SPIOutput::Options options(0, "Test SPI Device");
// setup pixel_count to 2 (enough to test all cases)
options.pixel_count = 2;
// setup SPIOutput
SPIOutput output(m_uid, &backend, options);
// set personality to 7= Individual APA102
output.SetPersonality(7);
// simulate incoming dmx data with this buffer

This comment has been minimized.

@peternewman

peternewman May 10, 2015

Member

SPaG DMX

@peternewman

peternewman May 10, 2015

Member

SPaG DMX

DmxBuffer buffer;
// setup an pointer to the returned data (the fake SPI data stream)

This comment has been minimized.

@peternewman

peternewman May 10, 2015

Member

SPaG a

@peternewman
unsigned int length = 0;
const uint8_t *data = NULL;
// test1
// setup some 'DMX' data
buffer.SetFromString("1, 10, 100");
// simulate incoming data
output.WriteDMX(buffer);
// get fake SPI data stream
data = backend.GetData(0, &length);
// this is the expected spi data stream:
const uint8_t EXPECTED0[] = { 0, 0, 0, 0, // StartFrame
0xff, 0x64, 0x0a, 0x01, // first Pixel
0xff, 0, 0, 0, // second Pixel
0, 0, 0, 0, 0, 0, 0, 0}; // EndFrame
// check for Equality
OLA_ASSERT_DATA_EQUALS(EXPECTED0, arraysize(EXPECTED0), data, length);
// check if the output writes are 1
OLA_ASSERT_EQ(1u, backend.Writes(0));
// test2
buffer.SetFromString("255,128,0,10,20,30");
output.WriteDMX(buffer);
data = backend.GetData(0, &length);
const uint8_t EXPECTED1[] = { 0, 0, 0, 0,
0xff, 0, 0x80, 0xff,
0xff, 0x1e, 0x14, 0x0a,
0, 0, 0, 0, 0, 0, 0, 0};
OLA_ASSERT_DATA_EQUALS(EXPECTED1, arraysize(EXPECTED1), data, length);
OLA_ASSERT_EQ(2u, backend.Writes(0));
// test3
buffer.SetFromString("34,56,78");
output.WriteDMX(buffer);
data = backend.GetData(0, &length);
const uint8_t EXPECTED2[] = { 0, 0, 0, 0,
0xff, 0x4e, 0x38, 0x22,
0xff, 0, 0, 0,

This comment has been minimized.

@nomis52

nomis52 May 2, 2015

Member

I think this is the wrong output. Sending a shorter frame shouldn't change what the values of the pixels outside the frame are.

@nomis52

nomis52 May 2, 2015

Member

I think this is the wrong output. Sending a shorter frame shouldn't change what the values of the pixels outside the frame are.

0, 0, 0, 0, 0, 0, 0, 0};
OLA_ASSERT_DATA_EQUALS(EXPECTED2, arraysize(EXPECTED2), data, length);
OLA_ASSERT_EQ(3u, backend.Writes(0));
// test4
// tests what happens if fewer then needed color information are received
buffer.SetFromString("7, 9");
output.WriteDMX(buffer);
data = backend.GetData(0, &length);
// check that the returns are the same as test2 (nothing changed)
OLA_ASSERT_DATA_EQUALS(EXPECTED2, arraysize(EXPECTED2), data, length);
OLA_ASSERT_EQ(3u, backend.Writes(0));
// test5
// test with other StartAddress
// set StartAddress
output.SetStartAddress(3);
// values 1 & 2 should not be visibel in SPI data stream

This comment has been minimized.

@nomis52

nomis52 May 2, 2015

Member

typo: visible

@nomis52

nomis52 May 2, 2015

Member

typo: visible

buffer.SetFromString("1,2,3,4,5,6,7,8");
output.WriteDMX(buffer);
data = backend.GetData(0, &length);
const uint8_t EXPECTED4[] = { 0, 0, 0, 0,
0xff, 0x05, 0x04, 0x03,
0xff, 0x08, 0x07, 0x06,
0, 0, 0, 0, 0, 0, 0, 0};
OLA_ASSERT_DATA_EQUALS(EXPECTED4, arraysize(EXPECTED4), data, length);
OLA_ASSERT_EQ(4u, backend.Writes(0));
// test6
// Check nothing changed on the other output.
OLA_ASSERT_EQ(reinterpret_cast<const uint8_t*>(NULL),
backend.GetData(1, &length));
OLA_ASSERT_EQ(0u, backend.Writes(1));
}
/**
* Test DMX writes in the combined APA102 mode.
*/
void SPIOutputTest::testCombinedAPA102Control() {
// setup Backend
FakeSPIBackend backend(2);
SPIOutput::Options options(0, "Test SPI Device");
// setup pixel_count to 2 (enough to test all cases)
options.pixel_count = 2;
// setup SPIOutput
SPIOutput output(m_uid, &backend, options);
// set personality to 7= Individual APA102

This comment has been minimized.

@nomis52

nomis52 May 2, 2015

Member

Set personality to 8: Combined APA102

@nomis52

nomis52 May 2, 2015

Member

Set personality to 8: Combined APA102

output.SetPersonality(8);
// simulate incoming dmx data with this buffer
DmxBuffer buffer;
// setup an pointer to the returned data (the fake SPI data stream)
unsigned int length = 0;
const uint8_t *data = NULL;
// test1
// setup some 'DMX' data
buffer.SetFromString("1, 10, 100");
// simulate incoming data
output.WriteDMX(buffer);
// get fake SPI data stream
data = backend.GetData(0, &length);
// this is the expected spi data stream:
const uint8_t EXPECTED0[] = { 0, 0, 0, 0, // StartFrame
0xff, 0x64, 0x0a, 0x01, // first Pixel
0xff, 0x64, 0x0a, 0x01, // second Pixel
0, 0, 0, 0, 0, 0, 0, 0}; // EndFrame
// check for Equality
OLA_ASSERT_DATA_EQUALS(EXPECTED0, arraysize(EXPECTED0), data, length);
// check if the output writes are 1
OLA_ASSERT_EQ(1u, backend.Writes(0));
// test2
buffer.SetFromString("255,128,0,10,20,30");
output.WriteDMX(buffer);
data = backend.GetData(0, &length);
const uint8_t EXPECTED1[] = { 0, 0, 0, 0,
0xff, 0, 0x80, 0xff,
0xff, 0, 0x80, 0xff,
0, 0, 0, 0, 0, 0, 0, 0};
OLA_ASSERT_DATA_EQUALS(EXPECTED1, arraysize(EXPECTED1), data, length);
OLA_ASSERT_EQ(2u, backend.Writes(0));
// test3
buffer.SetFromString("34,56,78");
output.WriteDMX(buffer);
data = backend.GetData(0, &length);
const uint8_t EXPECTED2[] = { 0, 0, 0, 0,
0xff, 0x4e, 0x38, 0x22,
0xff, 0x4e, 0x38, 0x22,
0, 0, 0, 0, 0, 0, 0, 0};
OLA_ASSERT_DATA_EQUALS(EXPECTED2, arraysize(EXPECTED2), data, length);
OLA_ASSERT_EQ(3u, backend.Writes(0));
// test4
// tests what happens if fewer then needed color information are received
buffer.SetFromString("7, 9");
output.WriteDMX(buffer);
data = backend.GetData(0, &length);
// check that the returns are the same as test2 (nothing changed)
OLA_ASSERT_DATA_EQUALS(EXPECTED2, arraysize(EXPECTED2), data, length);
OLA_ASSERT_EQ(3u, backend.Writes(0));
// test5
// test with other StartAddress
// set StartAddress
output.SetStartAddress(3);
// values 1 & 2 should not be visibel in SPI data stream

This comment has been minimized.

@nomis52

nomis52 May 2, 2015

Member

typo: visible

@nomis52

nomis52 May 2, 2015

Member

typo: visible

buffer.SetFromString("1,2,3,4,5,6,7,8");
output.WriteDMX(buffer);
data = backend.GetData(0, &length);
const uint8_t EXPECTED4[] = { 0, 0, 0, 0,
0xff, 0x05, 0x04, 0x03,
0xff, 0x05, 0x04, 0x03,
0, 0, 0, 0, 0, 0, 0, 0};
OLA_ASSERT_DATA_EQUALS(EXPECTED4, arraysize(EXPECTED4), data, length);
OLA_ASSERT_EQ(4u, backend.Writes(0));
// test6
// Check nothing changed on the other output.
OLA_ASSERT_EQ(reinterpret_cast<const uint8_t*>(NULL),
backend.GetData(1, &length));
OLA_ASSERT_EQ(0u, backend.Writes(1));
}
ProTip! Use n and p to navigate between commits in a pull request.