Skip to content

Commit

Permalink
wip can service implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
0xfrej committed Dec 13, 2024
1 parent af50a17 commit 4a2417a
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 34 deletions.
32 changes: 28 additions & 4 deletions modules/net/inc/vlcb/net/addr.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,39 @@
#pragma once

#include "vlcb/common/can.h"
#include "vlcb/platform/time.h"
#include <stdint.h>

typedef enum {
VLCB_MEDIUM_CAN,
} VlcbNetMedium;

typedef enum {
VLCB_NET_WIRE_CAN_STATE_UNINITIALIZED = 0,
VLCB_NET_WIRE_CAN_STATE_ENUMERATING,
VLCB_NET_WIRE_CAN_STATE_INITIALIZED,
VLCB_NET_WIRE_CAN_STATE_RESPONDING,
} VlcbNetWireCanState;

typedef union {
VlcbCanId can_id;
} VlcbNetHwAddr;
VlcbCanId can;
} VlcbNetWireAddr;

typedef struct {
union {
struct {
clock_t lastTimestamp;
VlcbNetWireCanState state;
uint8_t occupiedIdCache[16];
} can;
} meta;
VlcbNetWireAddr addr;
} VlcbNetWireEndpoint;

typedef VlcbNetWireEndpoint *const VlcbNetWireEndpointHandle;

bool vlcb_net_IsWireEndpointValid(VlcbNetWireEndpointHandle endpoint);

bool vlcb_net_IsHwAddrValid(VlcbNetMedium medium, VlcbNetHwAddr addr);
bool vlcb_net_IsWireAddrValid(VlcbNetMedium medium, VlcbNetWireAddr addr);

VlcbNetHwAddr vlcb_net_NewCanIdHwAddr(VlcbCanId id);
VlcbNetWireAddr vlcb_net_NewCanWireAddr(VlcbCanId id);
8 changes: 6 additions & 2 deletions modules/net/inc/vlcb/net/socket/datagram.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "../packet/datagram.h"
#include "../socket.h"
#include "../storage/packet_buf.h"
#include "vlcb/net/addr.h"
#include "vlcb/platform/interface.h"
#include <stdint.h>

Expand All @@ -16,10 +17,12 @@ typedef struct {
_INTERFACE_IMPLEMENT(IVlcbNetSocket);
VlcbPacketBuf *const rxBuf;
VlcbPacketBuf *const txBuf;
VlcbNetWireEndpointHandle endpoint;
} VlcbNetSocketDatagram;

VlcbNetSocketDatagram vlcb_net_sock_dgram_New(VlcbPacketBuf *const rxBuf,
VlcbPacketBuf *const txBuf);
VlcbNetSocketDatagram
vlcb_net_sock_dgram_New(VlcbPacketBuf *const rxBuf, VlcbPacketBuf *const txBuf,
VlcbNetWireEndpointHandle endpoint);

typedef enum {
VLCB_NET_SOCK_DGRAM_SEND_ERR_OK = 0,
Expand All @@ -44,6 +47,7 @@ vlcb_net_sock_dgram_Recv(VlcbNetSocketDatagram *const sock,

static inline IVlcbNetSocket *const
vlcb_net_sock_dgram_Upcast(VlcbNetSocketDatagram *const sock) {

return (IVlcbNetSocket *)sock;
}

Expand Down
14 changes: 12 additions & 2 deletions modules/net/inc/vlcb/net/storage/packet_buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,26 @@ typedef struct {
size_t head;
size_t tail;
size_t maxlen;
size_t bucket_size;
size_t bucketSize;
bool isLocked;
uint8_t buffer[];
} VlcbPacketBuf;

void vlcb_net_packetbuf_Init(VlcbPacketBuf *const c, size_t maxlen,
size_t bucket_size);
size_t bucketSize);
void vlcb_net_packetbuf_Reset(VlcbPacketBuf *const c);
bool vlcb_net_packetbuf_IsEmpty(VlcbPacketBuf *const c);
bool vlcb_net_packetbuf_IsFull(VlcbPacketBuf *const c);
size_t vlcb_net_packetbuf_Capacity(VlcbPacketBuf *const c);
size_t vlcb_net_packetbuf_BucketSize(VlcbPacketBuf *const c);
int vlcb_net_packetbuf_Push(VlcbPacketBuf *const c, const void *data);
int vlcb_net_packetbuf_Pop(VlcbPacketBuf *const c, void *data);

typedef struct {
VlcbPacketBuf *buf;
} VlcbPacketBufToken;

int vlcb_net_packetbuf_PopDeferred(VlcbPacketBuf *const c,
VlcbPacketBufToken *const tok, void *data);
void vlcb_net_packetbuf_PopDeferredAccept(VlcbPacketBufToken tok);
void vlcb_net_packetbuf_PopDeferredRefuse(VlcbPacketBufToken tok);
51 changes: 33 additions & 18 deletions modules/net/src/iface/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ VlcbNetIface vlcb_net_iface_New(IVlcbNetAdpt *const adpt,
return iface;
}

bool IngressPackets(VlcbNetIface *const iface) {
bool IngressPackets(VlcbNetIface *const iface, clock_t now) {
bool processed_any = false;

IVlcbNetAdpt *adpt = iface->adpt;
Expand All @@ -41,7 +41,7 @@ bool IngressPackets(VlcbNetIface *const iface) {

switch (caps.medium) {
case VLCB_MEDIUM_CAN:
ProcessCanPacket(iface, phy_packet);
ProcessCanPacket(iface, phy_packet, now);
default:
assert(false /* unsupported medium */);
}
Expand All @@ -52,7 +52,7 @@ bool IngressPackets(VlcbNetIface *const iface) {
return processed_any;
}

bool EgressPackets(VlcbNetIface *const iface) {
bool EgressPackets(VlcbNetIface *const iface, clock_t now) {
bool emitted_any = false;

const VlcbNetAdptCaps caps = _INTERFACE_PTR_CALL(iface->adpt, Caps);
Expand All @@ -61,37 +61,46 @@ bool EgressPackets(VlcbNetIface *const iface) {
while (vlcb_net_sock_list_iter_HasNext(&iter)) {
const VlcbNetSocketHandle sock = vlcb_net_sock_list_iter_Next(&iter);

VlcbNetPacket packet; // TODO: ensure clean packet

const bool emitted_packet =
_INTERFACE_PTR_CALL(sock, DispatchPacket, &packet);
// TODO: reject invalid packets -> for example when the packet wasn't filled
emitted_any |= emitted_packet;
if (emitted_packet) {
const VlcbNetAdptErr err = DispatchVlcbPacket(iface, caps, &packet);
if (err == VLCB_NET_ADPT_ERR_WOULD_BLOCK) {
// todo: handle this somehow
VlcbNetSocketPacketToken packetTok;
{
VlcbNetSocketDispatchErr err =
_INTERFACE_PTR_CALL(sock, DispatchPacket, &packetTok);
if (err != VLCB_NET_SOCK_DISP_ERR_OK) {
if (err == VLCB_NET_SOCK_DISP_ERR_WOULD_BLOCK) {
continue;
}
VLCBLOG_ERROR(vlcb_net_sock_DispatchErrToStr(err));
vlcb_net_sock_packet_token_Refuse(packetTok);
}
}

if (err != VLCB_NET_ADPT_ERR_OK) {
VLCBLOG_ERROR(vlcb_net_adpt_ErrToStr(err));
const VlcbNetAdptErr err =
DispatchVlcbPacket(iface, caps, &packetTok.packet);

if (err != VLCB_NET_ADPT_ERR_OK) {
vlcb_net_sock_packet_token_Refuse(packetTok);
if (err == VLCB_NET_ADPT_ERR_WOULD_BLOCK) {
continue;
}
VLCBLOG_ERROR(vlcb_net_adpt_ErrToStr(err));
}
emitted_any = true;
}

return emitted_any;
}

VlcbNetIfacePollResult vlcb_net_iface_Poll(VlcbNetIface *const iface) {
VlcbNetIfacePollResult vlcb_net_iface_Poll(VlcbNetIface *const iface,
clock_t now) {
assert(iface != NULL && iface->adpt != NULL /* iface, sockets need to be valid pointers and device needs to be initialized */);

bool readiness_may_have_changed = false;

do {
bool did_something = false;

did_something = IngressPackets(iface);
did_something = EgressPackets(iface);
did_something |= IngressPackets(iface, now);
did_something |= EgressPackets(iface, now);

if (did_something) {
readiness_may_have_changed = true;
Expand All @@ -114,3 +123,9 @@ bool vlcb_net_iface_BindSock(VlcbNetIface *const iface,
}
return true;
}

void vlcb_net_iface_FreeSock(VlcbNetIface *const iface,
VlcbNetSocketHandle sock) {
assert(iface != NULL && sock != NULL);
vlcb_net_sock_list_Remove(iface->sockets, sock);
}
36 changes: 30 additions & 6 deletions modules/net/src/iface/iface_can.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,38 @@
#include <stddef.h>
#include <string.h>

#include "iface_can_svc.c"
#include "iface_vlcb.h"
#include "vlcb/net/adapter.h"
#include "vlcb/net/addr.h"
#include "vlcb/net/iface.h"
#include "vlcb/net/packet/vlcb.h"
#include "vlcb/net/socket.h"
#include "vlcb/platform/log.h"

void ProcessCanPacket(VlcbNetIface *const iface, VlcbNetAdptPkt *pkt) {
void ProcessCanPacket(VlcbNetIface *const iface, VlcbNetAdptPkt *pkt,
vlcb_milis now) {
VlcbNetSocketListIter iter = vlcb_net_sock_list_GetIterator(iface->sockets);
while (vlcb_net_sock_list_iter_HasNext(&iter)) {
VlcbNetSocketHandle sock = vlcb_net_sock_list_iter_Next(&iter);
VlcbNetWireEndpointHandle endpoint = sock->WireEndpoint(sock);
CanSvcEventConsume(endpoint, (CanSvcEvent){
.type = CAN_PKT_INGEST,
.data.ingest.pkt = pkt,
});

CanSvcProcess(iface, endpoint, now);
}

if (pkt->meta.can.is_rtr) {
return;
}

if (pkt->payloadLen < 1) {
VLCBLOG_INFO("malformed packet, payload is less than 1 bytes long");
return;
}

VlcbNetAdptPayload *payload = &pkt->payload;
VlcbOpCode opc = *payload[0];
// TODO: should we validate opcodes?
Expand All @@ -19,11 +44,10 @@ void ProcessCanPacket(VlcbNetIface *const iface, VlcbNetAdptPkt *pkt) {
// return;
// }
// }

VlcbNetPacket vlcb_pkt;
{
VlcbNetPacketConstructErr err;
err = vlcb_net_pkt_New(opc, pkt->payload_len,
err = vlcb_net_pkt_New(opc, pkt->payloadLen,
(VlcbNetPayload *)(payload + 1), &vlcb_pkt);
if (err != VLCB_NET_PKT_CONSTRUCT_ERR_OK) {
VLCBLOG_ERROR(vlcb_net_pkt_ConstructErrToStr(err));
Expand All @@ -40,10 +64,10 @@ VlcbNetAdptErr DispatchCanPacket(VlcbNetIface *const iface,

adpt_pkt.medium = VLCB_MEDIUM_CAN;
adpt_pkt.meta.can.is_rtr = false;
adpt_pkt.payload_len = 1 + packet->payload_len;
adpt_pkt.payloadLen = 1 + packet->payloadLen;

if (packet->payload_len) {
memcpy(&adpt_pkt.payload + 1, packet->payload, packet->payload_len);
if (packet->payloadLen) {
memcpy(&adpt_pkt.payload + 1, packet->payload, packet->payloadLen);
}

VlcbNetAdptErr err = _INTERFACE_PTR_CALL(iface->adpt, SendPkt, &adpt_pkt);
Expand Down
3 changes: 2 additions & 1 deletion modules/net/src/iface/iface_can.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
#include "vlcb/net/adapter.h"
#include "vlcb/net/iface.h"

void ProcessCanPacket(VlcbNetIface *const iface, VlcbNetAdptPkt *packet);
void ProcessCanPacket(VlcbNetIface *const iface, VlcbNetAdptPkt *packet,
clock_t now);

VlcbNetAdptErr DispatchCanPacket(VlcbNetIface *const iface,
const VlcbNetPacket *const packet);
102 changes: 102 additions & 0 deletions modules/net/src/iface/iface_can_svc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include "vlcb/common/can.h"
#include "vlcb/net/adapter.h"
#include "vlcb/net/addr.h"
#include "vlcb/net/iface.h"
#include "vlcb/platform/interface.h"
#include "vlcb/platform/time.h"
#include <stdint.h>

typedef struct {
enum { CAN_PKT_INGEST } type;
union {
struct {
const VlcbNetAdptPkt *const pkt;
} ingest;
} data;
} CanSvcEvent;

static inline VlcbCanId ResolveFreeId(const uint8_t (*const idCache)[16]) {
for (uint8_t i = 0; i < 16; i++) {
for (uint8_t j = 0; j < 8 && (i * 8 + j) < 128; j++) {
if (!(*idCache[i] & ((uint8_t)(1 << j)))) {
return i * 8 + j;
} // TODO: fix these two fnctions
}
}
return VLCB_CAN_ID_EMPTY;
}

static inline void ToggleUsedId(uint8_t (*const idCache)[16], VlcbCanId id) {}

inline void CanSvcEventConsume(VlcbNetWireEndpointHandle endpoint,
CanSvcEvent event) {
switch (event.type) {
case CAN_PKT_INGEST:
if (endpoint->meta.can.state == VLCB_NET_WIRE_CAN_STATE_INITIALIZED) {
if (endpoint->addr.can == event.data.ingest.pkt->srcAddr.can) {
// handle collisions
endpoint->meta.can.state = VLCB_NET_WIRE_CAN_STATE_UNINITIALIZED;
endpoint->addr.can = VLCB_CAN_ID_EMPTY;
} else if (event.data.ingest.pkt->meta.can.is_rtr) {
// handle response to enumeration of other nodes
endpoint->meta.can.state = VLCB_NET_WIRE_CAN_STATE_RESPONDING;
}
} else if (endpoint->meta.can.state ==
VLCB_NET_WIRE_CAN_STATE_ENUMERATING) {
// handle enumeration
ToggleUsedId(&endpoint->meta.can.occupiedIdCache,
event.data.ingest.pkt->srcAddr.can);
}
break;
}
}

inline void CanSvcProcess(VlcbNetIface *const iface,
VlcbNetWireEndpointHandle endpoint, clock_t now) {
VlcbNetAdptPkt pkt;
VlcbNetAdptErr err;
switch (endpoint->meta.can.state) {
case VLCB_NET_WIRE_CAN_STATE_UNINITIALIZED:;
pkt = (VlcbNetAdptPkt){
.medium = VLCB_MEDIUM_CAN,
.srcAddr = {.can = VLCB_CAN_ID_EMPTY},
.payloadLen = 0,
.meta = {.can = {.prio = VLCB_CAN_PRIO_SELF_ENUM, .is_rtr = true}}};
err = _INTERFACE_PTR_CALL(iface->adpt, SendPkt, &pkt);
if (err != VLCB_NET_ADPT_ERR_OK) {
if (err == VLCB_NET_ADPT_ERR_WOULD_BLOCK) {
break;
}
// TODO: log error
}
endpoint->meta.can.state = VLCB_NET_WIRE_CAN_STATE_ENUMERATING;
endpoint->meta.can.lastTimestamp = now;
break;
case VLCB_NET_WIRE_CAN_STATE_ENUMERATING:
if (vlcb_platform_time_DiffInMs(endpoint->meta.can.lastTimestamp, now) >
100) {
endpoint->meta.can.state = VLCB_NET_WIRE_CAN_STATE_INITIALIZED;
VlcbCanId newId = ResolveFreeId(&endpoint->meta.can.occupiedIdCache);
ToggleUsedId(&endpoint->meta.can.occupiedIdCache, newId);
endpoint->addr.can = newId;
}
break;
case VLCB_NET_WIRE_CAN_STATE_RESPONDING:;
pkt = (VlcbNetAdptPkt){
.medium = VLCB_MEDIUM_CAN,
.srcAddr = endpoint->addr,
.payloadLen = 0,
.meta = {.can = {.prio = VLCB_CAN_PRIO_SELF_ENUM, .is_rtr = true}}};
err = _INTERFACE_PTR_CALL(iface->adpt, SendPkt, &pkt);
if (err != VLCB_NET_ADPT_ERR_OK) {
if (err == VLCB_NET_ADPT_ERR_WOULD_BLOCK) {
break;
}
// TODO: log error
}
endpoint->meta.can.state = VLCB_NET_WIRE_CAN_STATE_INITIALIZED;
break;
default:
break;
}
}
3 changes: 2 additions & 1 deletion modules/net/src/iface/iface_vlcb.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ VlcbNetAdptErr DispatchVlcbPacket(VlcbNetIface *const iface,
case VLCB_MEDIUM_CAN:
return DispatchCanPacket(iface, packet);
break;
default:
assert(false /* unimplemented behavior guard */);
}
assert(false /* unimplemented behavior guard */);
}

0 comments on commit 4a2417a

Please sign in to comment.