/*----------------------------------------------------------------------------*/ 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; }
/*----------------------------------------------------------------------------*/ 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; }
/*----------------------------------------------------------------------------*/ 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; }