Exemplo n.º 1
0
Arquivo: can.c Projeto: stxent/halm
/*----------------------------------------------------------------------------*/
static void changeRate(struct Can *interface, uint32_t rate)
{
  LPC_CAN_Type * const reg = interface->base.reg;

  reg->MOD |= MOD_RM; /* Enable Reset mode */
  reg->BTR = calcBusTimings(interface, rate);
  reg->MOD &= ~MOD_RM;
}
Exemplo n.º 2
0
Arquivo: can.c Projeto: stxent/halm
/*----------------------------------------------------------------------------*/
static enum Result canInit(void *object, const void *configBase)
{
  const struct CanConfig * const config = configBase;
  assert(config);

  const struct CanBaseConfig baseConfig = {
      .rx = config->rx,
      .tx = config->tx,
      .channel = config->channel
  };
  struct Can * const interface = object;
  enum Result res;

  /* Call base class constructor */
  if ((res = CanBase->init(object, &baseConfig)) != E_OK)
    return res;

  interface->base.handler = interruptHandler;
  interface->callback = 0;
  interface->timer = config->timer;
  interface->mode = MODE_LISTENER;
  interface->sequence = 0;

  const size_t poolSize = config->rxBuffers + config->txBuffers;

  if (!pointerArrayInit(&interface->pool, poolSize))
    return E_MEMORY;
  if (!pointerQueueInit(&interface->rxQueue, config->rxBuffers))
    return E_MEMORY;
  if (!pointerQueueInit(&interface->txQueue, config->txBuffers))
    return E_MEMORY;

  interface->poolBuffer = malloc(sizeof(struct CanStandardMessage) * poolSize);

  struct CanStandardMessage *message = interface->poolBuffer;

  for (size_t index = 0; index < poolSize; ++index)
  {
    pointerArrayPushBack(&interface->pool, message);
    ++message;
  }

  LPC_CAN_Type * const reg = interface->base.reg;

  reg->MOD = MOD_RM; /* Reset CAN */
  reg->IER = 0; /* Disable Receive Interrupt */
  reg->GSR = 0; /* Reset error counter */

  interface->rate = config->rate;
  reg->BTR = calcBusTimings(interface, interface->rate);

  /* Activate Listen Only mode and enable local priority for transmit buffers */
  reg->MOD = MOD_LOM | MOD_TPM;

  LPC_CANAF->AFMR = AFMR_AccBP; //FIXME

#ifdef CONFIG_PLATFORM_NXP_CAN_PM
  if ((res = pmRegister(powerStateHandler, interface)) != E_OK)
    return res;
#endif

  /* Enable interrupts on message reception and bus error */
  reg->IER = IER_RIE | IER_EPIE | IER_BEIE | IER_TIE_MASK;

  irqSetPriority(interface->base.irq, config->priority);
  irqEnable(interface->base.irq);

  return E_OK;
}
/*----------------------------------------------------------------------------*/
#ifndef CONFIG_PLATFORM_NXP_CAN_NO_DEINIT
static void canDeinit(void *object)
{
  struct Can * const interface = object;
  LPC_CAN_Type * const reg = interface->base.reg;

  /* Disable all interrupts */
  irqDisable(interface->base.irq);
  reg->IER = 0;

#ifdef CONFIG_PLATFORM_NXP_CAN_PM
  pmUnregister(interface);
#endif

  pointerQueueDeinit(&interface->txQueue);
  pointerQueueDeinit(&interface->rxQueue);
  pointerArrayDeinit(&interface->pool);
  CanBase->deinit(interface);
}
#endif
/*----------------------------------------------------------------------------*/
static enum Result canSetCallback(void *object, void (*callback)(void *),
    void *argument)
{
  struct Can * const interface = object;

  interface->callbackArgument = argument;
  interface->callback = callback;
  return E_OK;
}
/*----------------------------------------------------------------------------*/
static enum Result canGetParam(void *object, enum IfParameter parameter,
    void *data)
{
  struct Can * const interface = object;

  switch (parameter)
  {
    case IF_AVAILABLE:
      *(size_t *)data = pointerQueueSize(&interface->rxQueue);
      return E_OK;

    case IF_PENDING:
      *(size_t *)data = pointerQueueSize(&interface->txQueue);
      return E_OK;

    case IF_RATE:
      *(uint32_t *)data = interface->rate;
      return E_OK;

    default:
      return E_INVALID;
  }
}
/*----------------------------------------------------------------------------*/
static enum Result canSetParam(void *object, enum IfParameter parameter,
    const void *data)
{
  struct Can * const interface = object;

  switch ((enum CanParameter)parameter)
  {
    case IF_CAN_ACTIVE:
      changeMode(interface, MODE_ACTIVE);
      return E_OK;

    case IF_CAN_LISTENER:
      changeMode(interface, MODE_LISTENER);
      return E_OK;

    case IF_CAN_LOOPBACK:
      changeMode(interface, MODE_LOOPBACK);
      return E_OK;

    default:
      break;
  }

  switch (parameter)
  {
    case IF_RATE:
    {
      const uint32_t rate = *(const uint32_t *)data;

      changeRate(interface, rate);
      interface->rate = rate;

      return E_OK;
    }

    default:
      return E_INVALID;
  }
}
/*----------------------------------------------------------------------------*/
static size_t canRead(void *object, void *buffer, size_t length)
{
  assert(length % sizeof(struct CanStandardMessage) == 0);

  struct Can * const interface = object;
  struct CanStandardMessage *current = buffer;
  const struct CanStandardMessage * const last =
      (const void *)((uintptr_t)buffer + length);

  while (!pointerQueueEmpty(&interface->rxQueue) && current < last)
  {
    irqDisable(interface->base.irq);

    struct CanMessage * const input = pointerQueueFront(&interface->rxQueue);
    pointerQueuePopFront(&interface->rxQueue);

    memcpy(current, input, sizeof(*current));
    pointerArrayPushBack(&interface->pool, input);

    irqEnable(interface->base.irq);
    ++current;
  }

  return (uintptr_t)current - (uintptr_t)buffer;
}
Exemplo n.º 3
-1
/*----------------------------------------------------------------------------*/
static enum result canInit(void *object, const void *configBase)
{
  const struct CanConfig * const config = configBase;
  const struct CanBaseConfig baseConfig = {
      .channel = config->channel,
      .rx = config->rx,
      .tx = config->tx
  };
  struct Can * const interface = object;
  enum result res;

  /* Call base class constructor */
  if ((res = CanBase->init(object, &baseConfig)) != E_OK)
    return res;

  interface->base.handler = interruptHandler;
  interface->callback = 0;
  interface->timer = config->timer;
  interface->mode = MODE_LISTENER;

  const size_t poolSize = config->rxBuffers + config->txBuffers;

  res = queueInit(&interface->pool, sizeof(struct CanMessage *), poolSize);
  if (res != E_OK)
    return res;
  res = queueInit(&interface->rxQueue, sizeof(struct CanMessage *),
      config->rxBuffers);
  if (res != E_OK)
    return res;
  res = queueInit(&interface->txQueue, sizeof(struct CanMessage *),
      config->txBuffers);
  if (res != E_OK)
    return res;

  interface->poolBuffer = malloc(sizeof(struct CanStandardMessage) * poolSize);

  struct CanStandardMessage *message = interface->poolBuffer;

  for (size_t index = 0; index < poolSize; ++index)
  {
    queuePush(&interface->pool, &message);
    ++message;
  }

  LPC_CAN_Type * const reg = interface->base.reg;

  reg->MOD = MOD_RM; /* Reset CAN */
  reg->IER = 0; /* Disable Receive Interrupt */
  reg->GSR = 0; /* Reset error counter */

  interface->rate = config->rate;
  reg->BTR = calcBusTimings(interface, interface->rate);

  /* Disable Reset mode and activate Listen Only mode */
  reg->MOD = MOD_LOM;

  LPC_CANAF->AFMR = AFMR_AccBP; //FIXME

#ifdef CONFIG_CAN_PM
  if ((res = pmRegister(interface, powerStateHandler)) != E_OK)
    return res;
#endif

  irqSetPriority(interface->base.irq, config->priority);

  /* Enable interrupts on message reception and bus error */
  reg->IER = IER_RIE | IER_BEIE;

  return E_OK;
}
/*----------------------------------------------------------------------------*/
static void canDeinit(void *object)
{
  struct Can * const interface = object;
  LPC_CAN_Type * const reg = interface->base.reg;

  /* Disable all interrupts */
  reg->IER = 0;

#ifdef CONFIG_CAN_PM
  pmUnregister(interface);
#endif

  queueDeinit(&interface->txQueue);
  queueDeinit(&interface->rxQueue);
  CanBase->deinit(interface);
}
/*----------------------------------------------------------------------------*/
static enum result canCallback(void *object, void (*callback)(void *),
    void *argument)
{
  struct Can * const interface = object;

  interface->callbackArgument = argument;
  interface->callback = callback;
  return E_OK;
}
/*----------------------------------------------------------------------------*/
static enum result canGet(void *object, enum ifOption option, void *data)
{
  struct Can * const interface = object;

  switch (option)
  {
    case IF_AVAILABLE:
      *(size_t *)data = queueSize(&interface->rxQueue);
      return E_OK;

    case IF_PENDING:
      *(size_t *)data = queueSize(&interface->txQueue);
      return E_OK;

    case IF_RATE:
      *(uint32_t *)data = interface->rate;
      return E_OK;

    default:
      return E_INVALID;
  }
}
/*----------------------------------------------------------------------------*/
static enum result canSet(void *object, enum ifOption option,
    const void *data)
{
  struct Can * const interface = object;
  LPC_CAN_Type * const reg = interface->base.reg;

  switch ((enum canOption)option)
  {
    case IF_CAN_ACTIVE:
      changeMode(interface, MODE_ACTIVE);
      return E_OK;

    case IF_CAN_LISTENER:
      changeMode(interface, MODE_LISTENER);
      return E_OK;

    case IF_CAN_LOOPBACK:
      changeMode(interface, MODE_LOOPBACK);
      return E_OK;

    default:
      break;
  }

  switch (option)
  {
    case IF_RATE:
    {
      const uint32_t rate = *(const uint32_t *)data;

      interface->rate = rate;

      reg->MOD |= MOD_RM; /* Enable Reset mode */
      reg->BTR = calcBusTimings(interface, rate);
      reg->MOD &= ~MOD_RM;

      return E_OK;
    }

    default:
      return E_INVALID;
  }
}
/*----------------------------------------------------------------------------*/
static size_t canRead(void *object, void *buffer, size_t length)
{
  assert(length % sizeof(struct CanStandardMessage) == 0);

  struct Can * const interface = object;
  struct CanStandardMessage *output = buffer;
  size_t read = 0;

  while (read < length && !queueEmpty(&interface->rxQueue))
  {
    struct CanMessage *input;
    const irqState state = irqSave();

    queuePop(&interface->rxQueue, &input);
    memcpy(output, input, sizeof(*output));
    queuePush(&interface->pool, &input);

    irqRestore(state);

    read += sizeof(*output);
    ++output;
  }

  return read;
}