/*
 * Check that SetChannel works
 */
void DmxBufferTest::testSetChannel() {
  DmxBuffer buffer;
  buffer.SetChannel(1, 10);
  buffer.SetChannel(10, 50);

  uint8_t expected[DMX_UNIVERSE_SIZE];
  memset(expected, 0, DMX_UNIVERSE_SIZE);
  expected[1] = 10;
  expected[10] = 50;
  OLA_ASSERT_EQ((unsigned int) DMX_UNIVERSE_SIZE, buffer.Size());
  OLA_ASSERT_EQ(0, memcmp(expected, buffer.GetRaw(), buffer.Size()));

  // Check we can't set values greater than the buffer size
  buffer.SetChannel(999, 50);
  OLA_ASSERT_EQ((unsigned int) DMX_UNIVERSE_SIZE, buffer.Size());
  OLA_ASSERT_EQ(0, memcmp(expected, buffer.GetRaw(), buffer.Size()));

  // Check we can't set values outside the current valida data range
  unsigned int slice_size = 20;
  buffer.Set(expected, slice_size);
  buffer.SetChannel(30, 90);
  buffer.SetChannel(200, 10);

  OLA_ASSERT_EQ(slice_size, buffer.Size());
  OLA_ASSERT_EQ(0, memcmp(expected, buffer.GetRaw(), buffer.Size()));
}
Exemple #2
0
/*
 * Test receiving works.
 */
void RobeWidgetTest::testReceive() {
  DmxBuffer buffer;
  buffer.SetFromString("0,1,2,3,4");

  // change to recv mode & setup the callback
  m_endpoint->AddExpectedRobeMessage(
      DMX_IN_REQUEST_LABEL,
      NULL,
      0,
      ola::NewSingleCallback(this, &RobeWidgetTest::Terminate));
  m_widget->ChangeToReceiveMode();
  m_ss.Run();
  m_endpoint->Verify();
  m_widget->SetDmxCallback(
      ola::NewCallback(this, &RobeWidgetTest::NewDMXData));
  CPPUNIT_ASSERT(!m_new_dmx_data);

  // now send some data
  m_endpoint->SendUnsolicitedRobeData(DMX_IN_RESPONSE_LABEL,
                                      buffer.GetRaw(),
                                      buffer.Size());
  m_ss.Run();
  CPPUNIT_ASSERT(m_new_dmx_data);
  const DmxBuffer &new_data = m_widget->FetchDMX();
  CPPUNIT_ASSERT(buffer == new_data);
}
Exemple #3
0
/*
 * Send some DMX data
 */
bool KiNetNode::SendDMX(const IPV4Address &target_ip, const DmxBuffer &buffer) {
  static const uint8_t port = 0;
  static const uint8_t flags = 0;
  static const uint16_t timer_val = 0;
  static const uint32_t universe = 0xffffffff;

  if (!buffer.Size()) {
    OLA_DEBUG << "Not sending 0 length packet";
    return true;
  }

  m_output_queue.Clear();
  PopulatePacketHeader(KINET_DMX_MSG);
  m_output_stream << port << flags << timer_val << universe;
  m_output_stream << DMX512_START_CODE;
  m_output_stream.Write(buffer.GetRaw(), buffer.Size());

  IPV4SocketAddress target(target_ip, KINET_PORT);
  bool ok = m_socket->SendTo(&m_output_queue, target);
  if (!ok)
    OLA_WARN << "Failed to send KiNet DMX packet";

  if (!m_output_queue.Empty()) {
    OLA_WARN << "Failed to send complete KiNet packet";
    m_output_queue.Clear();
  }
  return ok;
}
/*
 * Send a dmx msg.
 * This has the nasty property of blocking if we remove the device
 * TODO: fix this
 */
bool StageProfiWidget::SendDmx(const DmxBuffer &buffer) const {
  uint16_t index = 0;
  while (index < buffer.Size()) {
    unsigned int size = std::min((unsigned int) DMX_MSG_LEN,
                                 buffer.Size() - index);
    Send255(index, buffer.GetRaw() + index, size);
    index += size;
  }
  return true;
}
bool JaRulePortHandleImpl::SendDMX(const DmxBuffer &buffer) {
  if (m_dmx_in_progress) {
    m_dmx = buffer;
    m_dmx_queued = true;
  } else {
    m_dmx_in_progress = true;
    m_port->SendCommand(JARULE_CMD_TX_DMX, buffer.GetRaw(), buffer.Size(),
                        m_dmx_callback);
  }
  return true;
}
/*
 * Check that SetRangeToValue works
 */
void DmxBufferTest::testSetRangeToValue() {
  const uint8_t RANGE_DATA[] = {50, 50, 50, 50, 50};
  DmxBuffer buffer;
  OLA_ASSERT_FALSE(buffer.SetRangeToValue(600, 50, 2));

  unsigned int range_size = 5;
  OLA_ASSERT_TRUE(buffer.SetRangeToValue(0, 50, range_size));
  OLA_ASSERT_EQ((unsigned int) DMX_UNIVERSE_SIZE, buffer.Size());
  OLA_ASSERT_EQ(0, memcmp(RANGE_DATA, buffer.GetRaw(), range_size));

  // setting outside the value range should fail
  buffer.Reset();
  OLA_ASSERT_FALSE(buffer.SetRange(10, TEST_DATA, range_size));
}
/*
 * Call Encode then Decode and check the results
 */
void RunLengthEncoderTest::checkEncodeDecode(const uint8_t *data,
                                             unsigned int data_size) {
  DmxBuffer src(data, data_size);
  DmxBuffer dst;

  unsigned int dst_size = ola::DMX_UNIVERSE_SIZE;
  memset(m_dst, 0, dst_size);
  OLA_ASSERT_TRUE(m_encoder.Encode(src, m_dst, &dst_size));

  OLA_ASSERT_TRUE(m_encoder.Decode(0, m_dst, dst_size, &dst));
  OLA_ASSERT_TRUE(src == dst);
  OLA_ASSERT_EQ(dst.Size(), data_size);
  OLA_ASSERT_NE(0, memcmp(data, dst.GetRaw(), dst.Size()));
}
Exemple #8
0
bool AnymaThreadedSender::TransmitBuffer(libusb_device_handle *handle,
                                         const DmxBuffer &buffer) {
  int r = m_adaptor->ControlTransfer(
      handle,
      LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE |
      LIBUSB_ENDPOINT_OUT,  // bmRequestType
      UDMX_SET_CHANNEL_RANGE,  // bRequest
      buffer.Size(),  // wValue
      0,  // wIndex
      const_cast<unsigned char*>(buffer.GetRaw()),  // data
      buffer.Size(),  // wLength
      URB_TIMEOUT_MS);  // timeout
  // Sometimes we get PIPE errors here, those are non-fatal
  return r > 0 || r == LIBUSB_ERROR_PIPE;
}
Exemple #9
0
/*
 * Write operation
 * @param buffer the DmxBuffer to write
 * @return true on success, false on failure
 */
bool Dmx4LinuxOutputPort::WriteDMX(const DmxBuffer &buffer,
                                   uint8_t priority) {
  int offset = DMX_UNIVERSE_SIZE * m_d4l_universe;
  if (lseek(m_socket->WriteDescriptor(), offset, SEEK_SET) == offset) {
    ssize_t r = m_socket->Send(buffer.GetRaw(), buffer.Size());
    if ((uint) r != buffer.Size()) {
      OLA_WARN << "only wrote " << r << "/" << buffer.Size() << " bytes: " <<
        strerror(errno);
      return false;
    }
  } else {
    OLA_WARN << "failed to seek: " << strerror(errno);
    return false;
  }
  return true;
}
Exemple #10
0
/**
 * Send a DMXBuffer as a blob to a set of targets
 */
bool OSCNode::SendBlob(const DmxBuffer &dmx_data,
                       const OSCTargetVector &targets) {
  // create the new OSC blob
  lo_blob osc_data = lo_blob_new(dmx_data.Size(), dmx_data.GetRaw());

  bool ok = true;
  // iterate over all the targets, and send to each one.
  OSCTargetVector::const_iterator target_iter = targets.begin();
  for (; target_iter != targets.end(); ++target_iter) {
    OLA_DEBUG << "Sending to " << (*target_iter)->socket_address;
    int ret = lo_send_from((*target_iter)->liblo_address,
                           m_osc_server,
                           LO_TT_IMMEDIATE,
                           (*target_iter)->osc_address.c_str(),
                           "b", osc_data);
    ok &= (ret > 0);
  }
  // free the blob
  lo_blob_free(osc_data);
  return ok;
}
/*
 * Check that SetRange works.
 */
void DmxBufferTest::testSetRange() {
  unsigned int data_size = sizeof(TEST_DATA);
  DmxBuffer buffer;
  OLA_ASSERT_FALSE(buffer.SetRange(0, NULL, data_size));
  OLA_ASSERT_FALSE(buffer.SetRange(600, TEST_DATA, data_size));

  // Setting an uninitialized buffer calls blackout first
  OLA_ASSERT_TRUE(buffer.SetRange(0, TEST_DATA, data_size));
  OLA_ASSERT_EQ((unsigned int) DMX_UNIVERSE_SIZE, buffer.Size());
  OLA_ASSERT_EQ(0, memcmp(TEST_DATA, buffer.GetRaw(), data_size));

  // try overrunning the buffer
  OLA_ASSERT_TRUE(buffer.SetRange(DMX_UNIVERSE_SIZE - 2, TEST_DATA, data_size));
  OLA_ASSERT_EQ((unsigned int) DMX_UNIVERSE_SIZE, buffer.Size());
  OLA_ASSERT_EQ(0, memcmp(TEST_DATA, buffer.GetRaw() + DMX_UNIVERSE_SIZE - 2,
                         2));

  // reset the buffer so that the valid data is 0, and try again
  buffer.Reset();
  OLA_ASSERT_TRUE(buffer.SetRange(0, TEST_DATA, data_size));
  OLA_ASSERT_EQ((unsigned int) data_size, buffer.Size());
  OLA_ASSERT_EQ(0, memcmp(TEST_DATA, buffer.GetRaw(), data_size));

  // setting past the end of the valid data should fail
  OLA_ASSERT_FALSE(buffer.SetRange(50, TEST_DATA, data_size));
  OLA_ASSERT_EQ((unsigned int) data_size, buffer.Size());
  OLA_ASSERT_EQ(0, memcmp(TEST_DATA, buffer.GetRaw(), buffer.Size()));

  // overwrite part of the valid data
  unsigned int offset = 2;
  OLA_ASSERT_TRUE(buffer.SetRange(offset, TEST_DATA, data_size));
  OLA_ASSERT_EQ((unsigned int) data_size + offset,
                       buffer.Size());
  OLA_ASSERT_EQ(0, memcmp(TEST_DATA, buffer.GetRaw(), offset));
  OLA_ASSERT_EQ(0, memcmp(TEST_DATA, buffer.GetRaw() + offset,
                         buffer.Size() - offset));

  // now try writing 1 channel past the valid data
  buffer.Reset();
  OLA_ASSERT_TRUE(buffer.SetRange(0, TEST_DATA, data_size));
  OLA_ASSERT_TRUE(buffer.SetRange(data_size, TEST_DATA,
                                 data_size));
  OLA_ASSERT_EQ((unsigned int) data_size * 2, buffer.Size());
  OLA_ASSERT_EQ(0, memcmp(TEST_DATA, buffer.GetRaw(), data_size));
  OLA_ASSERT_EQ(0, memcmp(TEST_DATA, buffer.GetRaw() + data_size, data_size));
}
/*
 * Send the dmx out the widget
 * @return true on success, false on failure
 */
bool VellemanOutputPort::SendDMX(const DmxBuffer &buffer) {
  unsigned char usb_data[m_chunk_size];
  unsigned int size = buffer.Size();
  const uint8_t *data = buffer.GetRaw();
  unsigned int i = 0;
  unsigned int n;

  // this could be up to 254 for the standard interface but then the shutdown
  // process gets wacky. Limit it to 100 for the standard and 255 for the
  // extended.
  unsigned int max_compressed_channels = m_chunk_size == UPGRADED_CHUNK_SIZE ?
    254 : 100;
  unsigned int compressed_channel_count = m_chunk_size - 2;
  unsigned int channel_count = m_chunk_size - 1;

  memset(usb_data, 0, sizeof(usb_data));

  if (m_chunk_size == UPGRADED_CHUNK_SIZE && size <= m_chunk_size - 2) {
    // if the upgrade is present and we can fit the data in a single packet
    // use the 7 message type
    usb_data[0] = 7;
    usb_data[1] = size;  // number of channels in packet
    memcpy(usb_data + 2, data, std::min(size, m_chunk_size - 2));
  } else {
    // otherwise use 4 to signal the start of frame
    for (n = 0;
         n < max_compressed_channels && n < size - compressed_channel_count
         && !data[n];
         n++) {
    }
    usb_data[0] = 4;
    usb_data[1] = n + 1;  // include start code
    memcpy(usb_data + 2, data + n, compressed_channel_count);
    i += n + compressed_channel_count;
  }

  if (!SendDataChunk(usb_data))
    return false;

  while (i < size - channel_count) {
    for (n = 0;
         n < max_compressed_channels && n + i < size - compressed_channel_count
           && !data[i + n];
         n++) {
    }
    if (n) {
      // we have leading zeros
      usb_data[0] = 5;
      usb_data[1] = n;
      memcpy(usb_data + 2, data + i + n, compressed_channel_count);
      i += n + compressed_channel_count;
    } else {
      usb_data[0] = 2;
      memcpy(usb_data + 1, data + i, channel_count);
      i += channel_count;
    }
    if (!SendDataChunk(usb_data))
      return false;
  }

  // send the last channels
  if (m_chunk_size == UPGRADED_CHUNK_SIZE) {
    // if running in extended mode we can use the 6 message type to send
    // everything at once.
    usb_data[0] = 6;
    usb_data[1] = size - i;
    memcpy(usb_data + 2, data + i, size - i);
    if (!SendDataChunk(usb_data))
      return false;

  } else {
    // else we use the 3 message type to send one at a time
    for (;i != size; i++) {
      usb_data[0] = 3;
      usb_data[1] = data[i];
      if (!SendDataChunk(usb_data))
        return false;
    }
  }
  return true;
}
Exemple #13
0
/*
 * Take a DMXBuffer and RunLengthEncode the data
 * @param src the DmxBuffer with the DMX data
 * @param data where to store the RLE data
 * @param size the size of the data segment, set to the amount of data encoded
 * @return true if we encoded all data, false if we ran out of space
 */
bool RunLengthEncoder::Encode(const DmxBuffer &src,
                              uint8_t *data,
                              unsigned int &data_size) {
  unsigned int src_size = src.Size();
  unsigned int dst_size = data_size;
  unsigned int &dst_index = data_size;
  dst_index = 0;

  unsigned int i;
  for (i = 0; i < src_size && dst_index < dst_size;) {
    // j points to the first non-repeating value
    unsigned int j = i + 1;
    while (j < src_size && src.Get(i) == src.Get(j) && j - i < 0x7f) {
      j++;
    }

    // if the number of repeats is more than 2
    // don't encode only two repeats,
    if (j - i > 2) {
      // if room left in dst buffer
      if (dst_size - dst_index > 1) {
        data[dst_index++] = (REPEAT_FLAG | (j - i));
        data[dst_index++] = src.Get(i);
      } else {
        // else return what we have done so far
        return false;
      }
      i = j;

    } else {
      // this value doesn't repeat more than twice
      // find out where the next repeat starts

      // postcondition: j is one more than the last value we want to send
      for (j = i + 1; j < src_size - 2 && j - i < 0x7f; j++) {
        // at the end  of the array
        if (j == src_size - 2) {
          j = src_size;
          break;
        }

        // if we're found a repeat of 3 or more stop here
        if (src.Get(j) == src.Get(j+1) && src.Get(j) == src.Get(j+2))
          break;
      }
      if (j >= src_size - 2)
        j = src_size;

       // if we have enough room left for all the values
      if (dst_index + j - i < dst_size) {
        data[dst_index++] = j - i;
        memcpy(&data[dst_index], src.GetRaw() + i, j-i);
        dst_index += j - i;
        i = j;

      // see how much data we can get in
      } else if (dst_size - dst_index > 1) {
        unsigned int l = dst_size - dst_index -1;
        data[dst_index++] = l;
        memcpy(&data[dst_index], src.GetRaw() + i, l);
        dst_index += l;
        return false;
      } else {
        return false;
      }
    }
  }

  if (i < src_size)
    return false;
  else
    return true;
}