Skip to content

Commit 76e74b0

Browse files
yliu80jren1
authored andcommitted
IOC mediator: support CBC signal services
This patch implements the IOC CBC signal serivces including single signal, multi-signal and group signal. All of them are used for CAN devices communication and IOC on-board peripherals control. Signed-off-by: Liu Yuan <yuan1.liu@intel.com> Reviewed-by: Wang Yu <yu1.wang@intel.com> Reviewed-by: Liu Shuo <shuo.a.liu@intel.com> Reviewed-by: Zhao Yakui <yakui.zhao@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
1 parent 61db2c7 commit 76e74b0

File tree

1 file changed

+275
-0
lines changed

1 file changed

+275
-0
lines changed

devicemodel/hw/platform/ioc_cbc.c

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
*/
3434

3535
#include <stdio.h>
36+
#include <stdbool.h>
3637

3738
#include "ioc.h"
3839

@@ -44,6 +45,8 @@ static int ioc_cbc_debug;
4445
do { if (ioc_cbc_debug) printf(fmt, ##args); } while (0)
4546
#define WPRINTF(fmt, args...) printf(fmt, ##args)
4647

48+
static void cbc_send_pkt(struct cbc_pkt *pkt);
49+
4750
/*
4851
* Buffer bytes of reading from the virtual UART, because the bytes maybe can
4952
* not generate one complete CBC frame.
@@ -235,6 +238,197 @@ cbc_unpack_link(struct ioc_dev *ioc)
235238
}
236239
}
237240

241+
/*
242+
* Find a CBC signal from CBC signal table.
243+
*/
244+
static inline struct cbc_signal *
245+
cbc_find_signal(uint16_t id, struct cbc_signal *table, size_t size)
246+
{
247+
int i;
248+
249+
for (i = 0; i < size; i++) {
250+
if (id == table[i].id)
251+
return &table[i];
252+
}
253+
return NULL;
254+
}
255+
256+
/*
257+
* Find a CBC signal group from CBC signal group table.
258+
*/
259+
static inline struct cbc_group *
260+
cbc_find_signal_group(uint16_t id, struct cbc_group *table, size_t size)
261+
{
262+
int i;
263+
264+
for (i = 0; i < size; i++) {
265+
if (id == table[i].id)
266+
return &table[i];
267+
}
268+
return NULL;
269+
}
270+
271+
/*
272+
* Signal length unit is bit in signal definition not byte,
273+
* if the length is 3 bits then return 1 byte,
274+
* if the length is 10 bits then return 2 bytes.
275+
*/
276+
static int
277+
cbc_get_signal_len(uint16_t id, struct cbc_signal *table, size_t size)
278+
{
279+
struct cbc_signal *p;
280+
281+
p = cbc_find_signal(id, table, size);
282+
return (p == NULL ? 0 : (p->len + 7)/8);
283+
}
284+
285+
/*
286+
* Set signal flag to inactive.
287+
*/
288+
static void
289+
cbc_disable_signal(uint16_t id, struct cbc_signal *table, size_t size)
290+
{
291+
struct cbc_signal *p;
292+
293+
p = cbc_find_signal(id, table, size);
294+
if (p)
295+
p->flag = CBC_INACTIVE;
296+
}
297+
298+
/*
299+
* Set signal group flag to inactive.
300+
*/
301+
static void
302+
cbc_disable_signal_group(uint16_t id, struct cbc_group *table, size_t size)
303+
{
304+
struct cbc_group *p;
305+
306+
p = cbc_find_signal_group(id, table, size);
307+
if (p)
308+
p->flag = CBC_INACTIVE;
309+
}
310+
311+
/*
312+
* Whitelist verification for a signal.
313+
*/
314+
static int
315+
wlist_verify_signal(uint16_t id, struct wlist_signal *list, size_t size)
316+
{
317+
/* TODO: implementation */
318+
return 0;
319+
}
320+
321+
/*
322+
* Whiltelist verification for a signal group.
323+
*/
324+
static int
325+
wlist_verify_group(uint16_t id, struct wlist_group *list, size_t size)
326+
{
327+
/* TODO: implementation */
328+
return 0;
329+
}
330+
331+
/*
332+
* CBC invalidates signals/groups.
333+
*/
334+
static void
335+
cbc_set_invalidation(struct cbc_pkt *pkt, int type)
336+
{
337+
int i;
338+
uint8_t *payload;
339+
uint8_t num;
340+
uint16_t id;
341+
342+
payload = pkt->req->buf + CBC_PAYLOAD_POS;
343+
344+
/* Number of signals or groups */
345+
num = payload[1];
346+
347+
/*
348+
* Safty check.
349+
* Each signal/group id length is 2 bytes and 2 bytes of service header,
350+
* the service length should less than the maximum service size.
351+
*/
352+
if ((num * 2 + 2) >= CBC_MAX_SERVICE_SIZE) {
353+
DPRINTF("ioc cbc group number is invalid, number is %d\r\n",
354+
num);
355+
return;
356+
}
357+
for (i = 0; i < num; i++) {
358+
id = payload[i * 2 + 2] | payload[i * 2 + 3] << 8;
359+
if (type == CBC_INVAL_T_SIGNAL)
360+
cbc_disable_signal(id, pkt->cfg->cbc_sig_tbl,
361+
pkt->cfg->cbc_sig_num);
362+
else if (type == CBC_INVAL_T_GROUP)
363+
cbc_disable_signal_group(id, pkt->cfg->cbc_grp_tbl,
364+
pkt->cfg->cbc_grp_num);
365+
else
366+
DPRINTF("%s", "ioc invalidation is not defined\r\n");
367+
}
368+
}
369+
370+
/*
371+
* CBC multi-signal data process.
372+
* Forwarding signal should be in whitelist, otherwise abandon the signal.
373+
*/
374+
static void
375+
cbc_forward_signals(struct cbc_pkt *pkt)
376+
{
377+
int i, j;
378+
int offset = 1;
379+
uint8_t *payload = pkt->req->buf + CBC_PAYLOAD_POS;
380+
uint8_t num = 0;
381+
uint16_t id;
382+
int signal_len;
383+
int valids = 1;
384+
385+
for (i = 0; i < payload[0]; i++) {
386+
id = payload[offset] | payload[offset + 1] << 8;
387+
388+
/* The length includes two bytes of signal ID occupation */
389+
signal_len = cbc_get_signal_len(id, pkt->cfg->cbc_sig_tbl,
390+
pkt->cfg->cbc_sig_num) + 2;
391+
392+
/* Whitelist verification */
393+
if (wlist_verify_signal(id, pkt->cfg->wlist_sig_tbl,
394+
pkt->cfg->wlist_sig_num) == 0) {
395+
396+
num++;
397+
if (valids < offset) {
398+
for (j = 0; j < signal_len; j++, valids++)
399+
payload[valids] = payload[offset + j];
400+
} else
401+
valids += signal_len;
402+
}
403+
offset += signal_len;
404+
405+
/* Safty check */
406+
if (offset + 1 > CBC_MAX_SERVICE_SIZE) {
407+
DPRINTF("ioc offset=%d is error in forward signal\r\n",
408+
offset);
409+
return;
410+
}
411+
}
412+
413+
/* Send permitted signals */
414+
if (num > 0) {
415+
/*
416+
* Set permitted signal numbers
417+
*/
418+
payload[0] = num;
419+
420+
/*
421+
* Set multi-signal value for CBC service layer header,
422+
* one service frame is generated completely.
423+
*/
424+
pkt->req->buf[CBC_SRV_POS] = CBC_SD_MULTI_SIGNAL;
425+
pkt->req->srv_len = valids + CBC_SRV_HDR_SIZE;
426+
427+
/* Send the CBC packet */
428+
cbc_send_pkt(pkt);
429+
}
430+
}
431+
238432
/*
239433
* Pack CBC link header includes SOF value, extension bits, frame length bits,
240434
* tx sequence bits, link alignment paddings and checksum byte.
@@ -457,6 +651,87 @@ cbc_process_lifecycle(struct cbc_pkt *pkt)
457651
static void
458652
cbc_process_signal(struct cbc_pkt *pkt)
459653
{
654+
/*
655+
* TODO: put the is_active into pkt structure instead local static
656+
* variable when the cbc_process_signal is seperated.
657+
*/
658+
static bool is_active;
659+
uint8_t cmd;
660+
uint8_t *payload;
661+
uint16_t id;
662+
663+
payload = pkt->req->buf + CBC_PAYLOAD_POS;
664+
cmd = pkt->req->buf[CBC_SRV_POS];
665+
666+
/*
667+
* FIXME:seperate the logic in two functions
668+
* link_len is 0 means the packet is transmitted to PTY(UART DM)
669+
* if the signal channel is not active, do not transmit it to PTY
670+
* to CBC cdevs, always forward the signals because signal channel
671+
* status only for UOS
672+
*/
673+
if (pkt->req->link_len == 0 && is_active == false &&
674+
(cmd == CBC_SD_SINGLE_SIGNAL ||
675+
cmd == CBC_SD_MULTI_SIGNAL ||
676+
cmd == CBC_SD_GROUP_SIGNAL))
677+
return;
678+
679+
switch (cmd) {
680+
/* Bidirectional command */
681+
case CBC_SD_SINGLE_SIGNAL:
682+
id = payload[0] | payload[1] << 8;
683+
if (wlist_verify_signal(id, pkt->cfg->wlist_sig_tbl,
684+
pkt->cfg->wlist_sig_num) == 0)
685+
cbc_send_pkt(pkt);
686+
break;
687+
/* Bidirectional command */
688+
case CBC_SD_MULTI_SIGNAL:
689+
cbc_forward_signals(pkt);
690+
break;
691+
/* Bidirectional command */
692+
case CBC_SD_GROUP_SIGNAL:
693+
id = payload[0] | payload[1] << 8;
694+
if (wlist_verify_group(id, pkt->cfg->wlist_grp_tbl,
695+
pkt->cfg->wlist_grp_num) == 0)
696+
cbc_send_pkt(pkt);
697+
break;
698+
/* Bidirectional command */
699+
case CBC_SD_INVAL_SSIG:
700+
id = payload[0] | payload[1] << 8;
701+
cbc_disable_signal(id, pkt->cfg->cbc_sig_tbl,
702+
pkt->cfg->cbc_sig_num);
703+
break;
704+
/* Bidirectional command */
705+
case CBC_SD_INVAL_MSIG:
706+
cbc_set_invalidation(pkt, CBC_INVAL_T_SIGNAL);
707+
break;
708+
/* Bidirectional command */
709+
case CBC_SD_INVAL_SGRP:
710+
id = payload[0] | payload[1] << 8;
711+
cbc_disable_signal_group(id, pkt->cfg->cbc_grp_tbl,
712+
pkt->cfg->cbc_grp_num);
713+
break;
714+
/* Bidirectional command */
715+
case CBC_SD_INVAL_MGRP:
716+
cbc_set_invalidation(pkt, CBC_INVAL_T_GROUP);
717+
break;
718+
/*
719+
* FIXME: seperate into rx signal process
720+
* Open/reset/close are not bidirectional operations
721+
* only for IOC rx thread
722+
*/
723+
case CBC_SD_OPEN_CHANNEL:
724+
case CBC_SD_RESET_CHANNEL:
725+
is_active = true;
726+
break;
727+
case CBC_SD_CLOSE_CHANNEL:
728+
is_active = false;
729+
break;
730+
default:
731+
DPRINTF("ioc got an new operation of signal channel=%d\r\n",
732+
cmd);
733+
break;
734+
}
460735
}
461736

462737
/*

0 commit comments

Comments
 (0)