Release candidate
This commit is contained in:
parent
ab7e4e4644
commit
0e6f1fe714
52
Makefile
Normal file
52
Makefile
Normal file
@ -0,0 +1,52 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# ******************************************************************************
|
||||
#
|
||||
# @file Makefile
|
||||
#
|
||||
# @brief Makefile for CXL Endpoint Emulator API library
|
||||
#
|
||||
# @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||
#
|
||||
# @date Mar 2024
|
||||
# @author Barrett Edwards <code@jrlabs.io>
|
||||
#
|
||||
# ******************************************************************************
|
||||
|
||||
CC=gcc
|
||||
CFLAGS= -g3 -O0 -Wall -Wextra
|
||||
MACROS=
|
||||
INCLUDE_DIR=/usr/local/include
|
||||
LIB_DIR=/usr/local/lib
|
||||
INCLUDE_PATH=-I $(INCLUDE_DIR)
|
||||
LIB_PATH=-L $(LIB_DIR)
|
||||
LIBS=-l arrayutils
|
||||
TARGET=emapi
|
||||
|
||||
all: testbench lib$(TARGET).a
|
||||
|
||||
testbench: testbench.c main.o
|
||||
$(CC) $^ $(CFLAGS) $(MACROS) $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) -o $@
|
||||
|
||||
lib$(TARGET).a: main.o
|
||||
ar rcs $@ $^
|
||||
|
||||
main.o: main.c main.h
|
||||
$(CC) -c $< $(CFLAGS) $(MACROS) $(INCLUDE_PATH) -o $@
|
||||
|
||||
clean:
|
||||
rm -rf ./*.o ./*.a testbench
|
||||
|
||||
doc:
|
||||
doxygen
|
||||
|
||||
install: lib$(TARGET).a
|
||||
sudo cp lib$(TARGET).a $(LIB_DIR)/
|
||||
sudo cp main.h $(INCLUDE_DIR)/$(TARGET).h
|
||||
|
||||
.PHONY: all clean doc install
|
||||
|
||||
# Variables
|
||||
# $^ Will expand to be all the sensitivity list
|
||||
# $< Will expand to be the frist file in sensitivity list
|
||||
# $@ Will expand to be the target name (the left side of the ":" )
|
||||
# -c gcc will compile but not try and link
|
||||
462
main.c
Normal file
462
main.c
Normal file
@ -0,0 +1,462 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
/**
|
||||
* @file emapi.c
|
||||
*
|
||||
* @brief Code file for CXL Emulator API commands
|
||||
*
|
||||
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||
*
|
||||
* @date FEb 2024
|
||||
* @author Barrett Edwards <code@jrlabs.io>
|
||||
*
|
||||
*/
|
||||
/* INCLUDES ==================================================================*/
|
||||
|
||||
/* printf()
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
/* Return error codes from functions
|
||||
*/
|
||||
#include <errno.h>
|
||||
|
||||
/* memcpy()
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include <arrayutils.h>
|
||||
|
||||
#include "emapi.h"
|
||||
|
||||
/* MACROS ====================================================================*/
|
||||
|
||||
/* ENUMERATIONS ==============================================================*/
|
||||
|
||||
/* STRUCTS ===================================================================*/
|
||||
|
||||
/* GLOBAL VARIABLES ==========================================================*/
|
||||
|
||||
/**
|
||||
* String representations of EM API Command Message types (MT)
|
||||
*/
|
||||
const char *STR_EMMT[] = {
|
||||
"Request", // EMMT_REQ = 0
|
||||
"Response", // EMMT_RSP = 1
|
||||
"Event" // EMMT_EVENT = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* String repressentations of EM API Objects (OB)
|
||||
*/
|
||||
const char *STR_EMOB[] = {
|
||||
"Null", // EMOB_NULL = 0,
|
||||
"emob_hdr", // EMOB_HDR = 1, //!< struct emapi_hdr
|
||||
"emob_dev", // EMOB_LIST_DEV = 2, //!< struct emapi_list_dev
|
||||
};
|
||||
|
||||
/**
|
||||
* String repressentations of EM API Opcodes (OP)
|
||||
*/
|
||||
const char *STR_EMOP[] = {
|
||||
"Event Notification", // EMOP_EVENT = 0x00
|
||||
"List Devices", // EMOP_LIST_DEV = 0x01
|
||||
"Connect Device", // EMOP_CONN_DEV = 0x02
|
||||
"Disconnect Device", // EMOP_DISCON_DEV = 0x03
|
||||
};
|
||||
|
||||
/**
|
||||
* String representations of CXL Emulator API Return Codes (RC)
|
||||
*/
|
||||
const char *STR_EMRC[] = {
|
||||
"Success", // EMRC_SUCCESS = 0x00,
|
||||
"Background operation started", // EMRC_BACKGROUND_OP_STARTED = 0x01,
|
||||
"Invalid input", // EMRC_INVALID_INPUT = 0x02,
|
||||
"Unsupported", // EMRC_UNSUPPORTED = 0x03,
|
||||
"Internal error", // EMRC_INTERNAL_ERROR = 0x04,
|
||||
"Busy", // EMRC_BUSY = 0x06,
|
||||
};
|
||||
|
||||
/* PROTOTYPES ================================================================*/
|
||||
|
||||
void emapi_prnt_hdr(void *ptr);
|
||||
void emapi_prnt_list_dev(void *ptr);
|
||||
|
||||
/* FUNCTIONS =================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Convert from a Little Endian byte array to a struct
|
||||
*
|
||||
* @param[out] dst void Pointer to destination struct
|
||||
* @param[in] src void Pointer to unsigned char array
|
||||
* @param[in] type unsigned enum _EMOB representing type of object to deserialize
|
||||
* @param[in] param void * to data needed to deserialize the byte stream
|
||||
* (e.g. count of objects to expect in the stream)
|
||||
* @return number of bytes consumed. -1 upon error otherwise.
|
||||
*/
|
||||
int emapi_deserialize(void *dst, __u8 *src, unsigned type, void *param)
|
||||
{
|
||||
int rv;
|
||||
|
||||
// Initialize variables
|
||||
rv = -1;
|
||||
|
||||
// Validate Inputs
|
||||
if ( (dst == NULL) || (type >= EMOB_MAX) )
|
||||
goto end;
|
||||
|
||||
// Handle each object type
|
||||
switch(type)
|
||||
{
|
||||
case EMOB_NULL:
|
||||
rv = 0;
|
||||
break;
|
||||
|
||||
case EMOB_HDR: //!< struct emapi_hdr
|
||||
{
|
||||
struct emapi_hdr *o = (struct emapi_hdr*) dst;
|
||||
o->ver = (src[ 0] >> 4) & 0x0F;
|
||||
o->type = (src[ 0] ) & 0x0F;
|
||||
o->tag = src[ 1];
|
||||
o->rc = src[ 2];
|
||||
o->opcode = src[ 3];
|
||||
o->a = src[ 4];
|
||||
o->len = (src[ 7] << 8) | src[ 6];
|
||||
o->b = (src[11] << 24) | (src[10] << 16) | (src[ 9] << 8) | src[ 8];
|
||||
rv = EMLN_HDR;
|
||||
}
|
||||
break;
|
||||
|
||||
case EMOB_LIST_DEV: //!< struct emapi_dev
|
||||
{
|
||||
unsigned i, k, num;
|
||||
struct emapi_dev *o;
|
||||
|
||||
// Initialize variables
|
||||
k = 0;
|
||||
o = (struct emapi_dev*) dst;
|
||||
if (param == NULL)
|
||||
num = 1;
|
||||
else
|
||||
num = *((unsigned *) param);
|
||||
|
||||
for ( i = 0 ; i < num ; i++ )
|
||||
{
|
||||
o->id = src[k++];
|
||||
o->len = src[k++];
|
||||
if (o->len == 0)
|
||||
o->name[0] = 0;
|
||||
else
|
||||
memcpy(o->name, &src[k], o->len);
|
||||
k += o->len;
|
||||
o++;
|
||||
}
|
||||
rv = k;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to populate a emapi_hdr object
|
||||
*
|
||||
* @param[out] fh struct emapi_hdr* to fill in
|
||||
* @param[in] type __u8 Request / Response [EMMT]
|
||||
* @param[in] tag __u8 message tag identifier
|
||||
* @param[in] rc __u8 retrun code
|
||||
* @param[in] opcode __u8 opcode [EMOP]
|
||||
* @param[in] len __u16 Length of payload in bytes
|
||||
* @param[in] a __u8 Immediate value A
|
||||
* @param[in] b __u32 Immediate value B
|
||||
*/
|
||||
int emapi_fill_hdr
|
||||
(
|
||||
struct emapi_hdr *h,
|
||||
__u8 type,
|
||||
__u8 tag,
|
||||
__u8 rc,
|
||||
__u8 opcode,
|
||||
__u16 len,
|
||||
__u8 a,
|
||||
__u32 b
|
||||
)
|
||||
{
|
||||
if (h == NULL)
|
||||
return 0;
|
||||
h->ver = 0;
|
||||
h->type = type;
|
||||
h->tag = tag;
|
||||
h->rc = rc;
|
||||
h->opcode = opcode;
|
||||
h->len = len;
|
||||
h->a = a;
|
||||
h->b = b;
|
||||
return EMLN_HDR + len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an EM API Message - Connect
|
||||
*
|
||||
* @param m emapi_msg* to fill
|
||||
* @return 0 upon success, non zero otherwise
|
||||
*/
|
||||
int emapi_fill_conn(struct emapi_msg *m, int ppid, int dev)
|
||||
{
|
||||
int rv;
|
||||
|
||||
// Initialize variables
|
||||
rv = 1;
|
||||
|
||||
// Validate Inputs
|
||||
if (m == NULL)
|
||||
goto end;
|
||||
|
||||
// Clear Header
|
||||
memset(&m->hdr, 0, sizeof(struct emapi_hdr));
|
||||
|
||||
// Set header
|
||||
m->hdr.opcode = EMOP_CONN_DEV;
|
||||
m->hdr.a = ppid;
|
||||
m->hdr.b = dev;
|
||||
|
||||
// Set object
|
||||
|
||||
rv = 0;
|
||||
|
||||
end:
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an EM API Message - Disconnect
|
||||
*
|
||||
* @param m emapi_msg* to fill
|
||||
* @return 0 upon success, non zero otherwise
|
||||
*/
|
||||
int emapi_fill_disconn(struct emapi_msg *m, int ppid, int all)
|
||||
{
|
||||
int rv;
|
||||
|
||||
// Initialize variables
|
||||
rv = 1;
|
||||
|
||||
// Validate Inputs
|
||||
if (m == NULL)
|
||||
goto end;
|
||||
|
||||
// Clear Header
|
||||
memset(&m->hdr, 0, sizeof(struct emapi_hdr));
|
||||
|
||||
// Set header
|
||||
m->hdr.opcode = EMOP_DISCON_DEV;
|
||||
m->hdr.a = ppid;
|
||||
m->hdr.b = all;
|
||||
|
||||
// Set object
|
||||
|
||||
rv = 0;
|
||||
|
||||
end:
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an EM API Message - List Devices
|
||||
*
|
||||
* @param m emapi_msg* to fill
|
||||
* @return 0 upon success, non zero otherwise
|
||||
*/
|
||||
int emapi_fill_listdev(struct emapi_msg *m, int num, int start)
|
||||
{
|
||||
int rv;
|
||||
|
||||
// Initialize variables
|
||||
rv = 1;
|
||||
|
||||
// Validate Inputs
|
||||
if (m == NULL)
|
||||
goto end;
|
||||
|
||||
// Clear Header
|
||||
memset(&m->hdr, 0, sizeof(struct emapi_hdr));
|
||||
|
||||
// Set header
|
||||
m->hdr.opcode = EMOP_LIST_DEV;
|
||||
m->hdr.a = num;
|
||||
m->hdr.b = start;
|
||||
|
||||
// Set object
|
||||
|
||||
rv = 0;
|
||||
|
||||
end:
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert an object into Little Endian byte array format
|
||||
*
|
||||
* @param[out] dst void Pointer to destination unsigned char array
|
||||
* @param[in] src void Pointer to object to serialize
|
||||
* @param[in] type unsigned enum _EMOB representing type of object to serialize
|
||||
* @return number of serialized bytes, 0 if error
|
||||
*/
|
||||
int emapi_serialize(__u8 *dst, void *src, unsigned type, void *param)
|
||||
{
|
||||
int rv;
|
||||
|
||||
// Initialize variables
|
||||
rv = 0;
|
||||
|
||||
// Validate Inputs
|
||||
if ( (type == EMOB_NULL) || (type >= EMOB_MAX) )
|
||||
goto end;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case EMOB_HDR: //!< struct emapi_hdr
|
||||
{
|
||||
struct emapi_hdr *o = (struct emapi_hdr*) src;
|
||||
dst[0] = ((o->ver << 4) & 0xF0) | (o->type & 0x0F);
|
||||
dst[1] = o->tag;
|
||||
dst[2] = o->rc;
|
||||
dst[3] = o->opcode;
|
||||
dst[4] = o->a;
|
||||
dst[6] = (o->len ) & 0x00FF;
|
||||
dst[7] = (o->len >> 8 ) & 0x00FF;
|
||||
dst[ 8] = (o->b ) & 0x00FF;
|
||||
dst[ 9] = (o->b >> 8) & 0x00FF;
|
||||
dst[10] = (o->b >> 16) & 0x00FF;
|
||||
dst[11] = (o->b >> 24) & 0x00FF;
|
||||
rv = EMLN_HDR;
|
||||
}
|
||||
break;
|
||||
|
||||
case EMOB_LIST_DEV: //!< struct emapi_dev
|
||||
{
|
||||
struct emapi_dev *o = (struct emapi_dev*) src;
|
||||
dst[0] = o->id;
|
||||
dst[1] = o->len;
|
||||
memcpy(&dst[2], o->name, o->len);
|
||||
rv = o->len + 2;;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
return rv;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine the Request Object Identifier [EMOB] for an EM API Message Opcode [EMOP]
|
||||
*
|
||||
* @param opcode This is an EM API Opcode [EMOP]
|
||||
* @return int Returns the EM API Object Identifier [EMOB] used in a Request
|
||||
*/
|
||||
int emapi_emob_req(unsigned int opcode)
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
case EMOP_EVENT: return EMOB_NULL;
|
||||
case EMOP_LIST_DEV: return EMOB_LIST_DEV;
|
||||
case EMOP_CONN_DEV: return EMOB_NULL;
|
||||
case EMOP_DISCON_DEV: return EMOB_NULL;
|
||||
default: return EMOB_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the Response Object Identifier [EMOB] for an EM API Message Opcode [EMOP]
|
||||
*
|
||||
* @param opcode This is an EM API Opcode [EMOP]
|
||||
* @return int Returns the EM API Object Identifier [EMOB] used in a Response
|
||||
*/
|
||||
int emapi_emob_rsp(unsigned int opcode)
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
case EMOP_EVENT: return EMOB_NULL;
|
||||
case EMOP_LIST_DEV: return EMOB_LIST_DEV;
|
||||
case EMOP_CONN_DEV: return EMOB_NULL;
|
||||
case EMOP_DISCON_DEV: return EMOB_NULL;
|
||||
default: return EMOB_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Functions to return a string representation of an object*/
|
||||
|
||||
const char *emmt(unsigned int u)
|
||||
{
|
||||
if (u >= EMMT_MAX) return NULL;
|
||||
return STR_EMMT[u];
|
||||
}
|
||||
|
||||
const char *emob(unsigned int u)
|
||||
{
|
||||
if (u >= EMOB_MAX) return NULL;
|
||||
return STR_EMOB[u];
|
||||
}
|
||||
|
||||
const char *emop(unsigned int u)
|
||||
{
|
||||
if (u >= EMOP_MAX) return NULL;
|
||||
return STR_EMOP[u];
|
||||
}
|
||||
|
||||
const char *emrc(unsigned int u)
|
||||
{
|
||||
if (u >= EMRC_MAX) return NULL;
|
||||
return STR_EMRC[u];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Print an object to the screen
|
||||
*
|
||||
* @param ptr A pointer to the object to print
|
||||
* @param type The type of object to be printed from enum _FMOB
|
||||
*/
|
||||
void emapi_prnt(void *ptr, unsigned type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case EMOB_HDR: emapi_prnt_hdr(ptr); break;
|
||||
case EMOB_LIST_DEV: emapi_prnt_list_dev(ptr); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void emapi_prnt_hdr(void *ptr)
|
||||
{
|
||||
struct emapi_hdr *o = (struct emapi_hdr*) ptr;
|
||||
printf("emapi_hdr:\n");
|
||||
printf("Version: 0x%02x\n", o->ver);
|
||||
printf("Type: 0x%02x\n", o->type);
|
||||
printf("Tag: 0x%02x\n", o->tag);
|
||||
printf("Return Code: 0x%02x\n", o->rc);
|
||||
printf("Opcode: 0x%02x\n", o->opcode);
|
||||
printf("Immediate: A 0x%02x\n", o->a);
|
||||
printf("Len: 0x%04x\n", o->len);
|
||||
printf("Immediate: B 0x%08x\n", o->b);
|
||||
}
|
||||
|
||||
void emapi_prnt_list_dev(void *ptr)
|
||||
{
|
||||
struct emapi_dev *o = (struct emapi_dev*) ptr;
|
||||
printf("%02d - %s\n", o->id, o->name);
|
||||
}
|
||||
|
||||
265
main.h
Normal file
265
main.h
Normal file
@ -0,0 +1,265 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
/**
|
||||
* @file emapi.h
|
||||
*
|
||||
* @brief Header file for CXL Emulator API commands
|
||||
*
|
||||
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||
*
|
||||
* @date Feb 2024
|
||||
* @author Barrett Edwards <code@jrlabs.io>
|
||||
*
|
||||
* Macro / Enumeration Prefixes
|
||||
* EMMT - EM API Command Message Category Types (MT)
|
||||
* EMOB - Types of EM API Objects (OB)
|
||||
* EMOP - EM API Command Opcodes (OP)
|
||||
* RMRC - EM API Command Return Codes (RC)
|
||||
*
|
||||
*/
|
||||
#ifndef _EMAPI_H
|
||||
#define _EMAPI_H
|
||||
|
||||
/* INCLUDES ==================================================================*/
|
||||
|
||||
/**
|
||||
* For __u8, __u16, __u32, __u64 types
|
||||
*/
|
||||
#include <linux/types.h>
|
||||
|
||||
/* MACROS ====================================================================*/
|
||||
|
||||
// Length of struct emapi_hdr
|
||||
#define EMLN_HDR 12
|
||||
#define EMLN_MSG 8192 //!< Maximum length of a EM API Message Body (HDR + payload)
|
||||
#define EMLN_PAYLOAD (EMLN_MSG - EMLN_HDR) //!< Maximum length of the EM API Message Payload
|
||||
|
||||
// Maximum Length of a device name
|
||||
#define EMLN_DEV_NAME 125
|
||||
|
||||
// Maximum numberof devices returned
|
||||
#define EMLN_DEV_NUM 64
|
||||
|
||||
/* ENUMERATIONS ==============================================================*/
|
||||
|
||||
/**
|
||||
* Types of EM API Objects (OB)
|
||||
*
|
||||
* The primary purpose of this enum is for serialization/deserialization.
|
||||
*/
|
||||
enum _EMOB
|
||||
{
|
||||
EMOB_NULL = 0,
|
||||
EMOB_HDR = 1, //!< struct emapi_hdr
|
||||
EMOB_LIST_DEV = 2, //!< struct emapi_list_dev
|
||||
EMOB_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* EM API Command Message Category Types (MT)
|
||||
*/
|
||||
enum _EMMT
|
||||
{
|
||||
EMMT_REQ = 0,
|
||||
EMMT_RSP = 1,
|
||||
EMMT_EVENT = 2,
|
||||
EMMT_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* EM API Command Opcodes (OP)
|
||||
*/
|
||||
enum _EMOP
|
||||
{
|
||||
EMOP_EVENT = 0x00,
|
||||
EMOP_LIST_DEV = 0x01,
|
||||
EMOP_CONN_DEV = 0x02,
|
||||
EMOP_DISCON_DEV = 0x03,
|
||||
EMOP_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* EM API Command Return Codes (RC)
|
||||
*/
|
||||
enum _EMRC
|
||||
{
|
||||
EMRC_SUCCESS = 0x0,
|
||||
EMRC_BACKGROUND_OP_STARTED = 0x1,
|
||||
EMRC_INVALID_INPUT = 0x2,
|
||||
EMRC_UNSUPPORTED = 0x3,
|
||||
EMRC_INTERNAL_ERROR = 0x4,
|
||||
EMRC_BUSY = 0x5,
|
||||
EMRC_MAX
|
||||
};
|
||||
|
||||
|
||||
/* STRUCTS ===================================================================*/
|
||||
|
||||
/**
|
||||
* EM API Protocol Header
|
||||
*/
|
||||
struct emapi_hdr
|
||||
{
|
||||
__u8 type : 4; //!< Type of EM API message [EMMT]
|
||||
__u8 ver : 4; //!< Header Version
|
||||
__u8 tag; //!< Tag used to track response messages
|
||||
__u8 rc; //!< Return Code [EMRC]
|
||||
__u8 opcode; //!< OpCode [EMOP]
|
||||
|
||||
__u8 a; //!< Immediate A
|
||||
__u8 rsvd;
|
||||
__u16 len; //!< Payload length in bytes
|
||||
|
||||
__u32 b; //!< Immediate B
|
||||
};
|
||||
|
||||
/**
|
||||
* List devices - Request (Opcode 01h)
|
||||
*
|
||||
* Immediate A: Num requested (0 = all)
|
||||
* Immediate B: Device num to start at
|
||||
* Payload: None
|
||||
*/
|
||||
|
||||
/**
|
||||
* List devices - Response Entry (Opcode 01h)
|
||||
*
|
||||
* Immediate A: Num devices returned
|
||||
* Immediate B: Total devices
|
||||
*/
|
||||
|
||||
/**
|
||||
* List devices - Response Entry (Opcode 01h)
|
||||
*
|
||||
*/
|
||||
struct emapi_dev
|
||||
{
|
||||
__u8 id; //!< Device ID
|
||||
__u8 len; //!< Length of device name
|
||||
char name[EMLN_DEV_NAME]; //!< Device name
|
||||
};
|
||||
|
||||
/**
|
||||
* Connect - Request (Opcode 02h)
|
||||
*
|
||||
* Immediate A: PPID
|
||||
* Immediate B: Device ID
|
||||
*/
|
||||
|
||||
/**
|
||||
* Disconnect - Request (Opcode 02h)
|
||||
*
|
||||
* Immediate A: PPID
|
||||
* Immediate B: All 1=Disconnect all, 0=Disconnect PPID in Immediate A
|
||||
*/
|
||||
|
||||
/**
|
||||
* This struct is to store the serialized EM API header and object
|
||||
*/
|
||||
struct __attribute__((__packed__)) emapi_buf
|
||||
{
|
||||
__u8 hdr[EMLN_HDR]; //!< Buffer to store serialized EM API Header
|
||||
__u8 payload[EMLN_PAYLOAD]; //!< Buffer to store serialized EM API Message Payload
|
||||
};
|
||||
|
||||
/**
|
||||
* EM API Message
|
||||
*/
|
||||
struct emapi_msg
|
||||
{
|
||||
struct emapi_hdr hdr; //!< EM API Header
|
||||
|
||||
//!< This union is to store the deserialized object
|
||||
union
|
||||
{
|
||||
struct emapi_dev dev[EMLN_DEV_NUM];
|
||||
} obj;
|
||||
};
|
||||
|
||||
/* GLOBAL VARIABLES ==========================================================*/
|
||||
|
||||
/* PROTOTYPES ================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Convert from a Little Endian byte array to a struct
|
||||
*
|
||||
* @param[out] dst void Pointer to destination struct
|
||||
* @param[in] src void Pointer to unsigned char array
|
||||
* @param[in] type unsigned enum _EMOB representing type of object to deserialize
|
||||
* @param[in] param void * to data needed to deserialize the byte stream
|
||||
* (e.g. count of objects to expect in the stream)
|
||||
* @return number of bytes consumed. -1 upon error
|
||||
*/
|
||||
int emapi_deserialize(void *dst, __u8 *src, unsigned type, void *param);
|
||||
|
||||
/**
|
||||
* Convenience function to populate a emapi_hdr object
|
||||
*
|
||||
* @param[out] fh struct emapi_hdr* to fill in
|
||||
* @param[in] type __u8 Request / Response [EMMT]
|
||||
* @param[in] tag __u8 message tag identifier
|
||||
* @param[in] rc __u8 retrun code
|
||||
* @param[in] opcode __u8 opcode [EMOP]
|
||||
* @param[in] len __u16 Length of payload in bytes
|
||||
* @param[in] a __u8 Immediate value A
|
||||
* @param[in] b __u32 Immediate value B
|
||||
* @return length of EM API Header + payload
|
||||
*/
|
||||
int emapi_fill_hdr
|
||||
(
|
||||
struct emapi_hdr *eh,
|
||||
__u8 type,
|
||||
__u8 tag,
|
||||
__u8 rc,
|
||||
__u8 opcode,
|
||||
__u16 len,
|
||||
__u8 a,
|
||||
__u32 b
|
||||
);
|
||||
|
||||
/**
|
||||
* Determine the Request Object Identifier [EMOB] for an EM API Message Opcode [EMOP]
|
||||
*
|
||||
* @param opcode This is an EM API Opcode [EMOP]
|
||||
* @return int Returns the EM API Object Identifier [EMOB] used in a Request
|
||||
*/
|
||||
int emapi_emob_req(unsigned int opcode);
|
||||
|
||||
/**
|
||||
* Determine the Response Object Identifier [EMOB] for an EM API Message Opcode [EMOP]
|
||||
*
|
||||
* @param opcode This is an EM API Opcode [EMOP]
|
||||
* @return int Returns the EM API Object Identifier [EMOB] used in a Response
|
||||
*/
|
||||
int emapi_emob_rsp(unsigned int opcode);
|
||||
|
||||
int emapi_fill_conn(struct emapi_msg *m, int ppid, int dev);
|
||||
int emapi_fill_disconn(struct emapi_msg *m, int ppid, int all);
|
||||
int emapi_fill_listdev(struct emapi_msg *m, int num, int start);
|
||||
|
||||
/**
|
||||
* @brief Convert an object into Little Endian byte array format
|
||||
*
|
||||
* @param[out] dst void Pointer to destination unsigned char array
|
||||
* @param[in] src void Pointer to object to serialize
|
||||
* @param[in] type unsigned enum _EMOB representing type of object to serialize
|
||||
* @param[in] param void * to data needed to serialize the byte stream
|
||||
* @return number of serialized bytes, -1 if error
|
||||
*/
|
||||
int emapi_serialize(__u8 *dst, void *src, unsigned type, void *param);
|
||||
|
||||
/**
|
||||
* Print an object to the screen
|
||||
*
|
||||
* @param ptr A pointer to the object to print
|
||||
* @param type The type of object to be printed from enum _EMOB
|
||||
*/
|
||||
void emapi_prnt(void *ptr, unsigned type);
|
||||
|
||||
/* Functions to return a string representation of an object*/
|
||||
const char *emmt(unsigned u);
|
||||
const char *emob(unsigned u);
|
||||
const char *emop(unsigned u);
|
||||
const char *emrc(unsigned u);
|
||||
|
||||
|
||||
#endif //ifndef _EMAPI_H
|
||||
197
testbench.c
Normal file
197
testbench.c
Normal file
@ -0,0 +1,197 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
/**
|
||||
* @file testbench.c
|
||||
*
|
||||
* @brief Code file for testing the EM API commands
|
||||
*
|
||||
* @details This program has a series of tests that can be run to
|
||||
* demonstrate the functionality of the EM API
|
||||
*
|
||||
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||
*
|
||||
* @date Feb 2024
|
||||
* @author Barrett Edwards <code@jrlabs.io>
|
||||
*
|
||||
*/
|
||||
/* INCLUDES ==================================================================*/
|
||||
|
||||
/* printf()
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* memset()
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
/* au_prnt_buf()
|
||||
*/
|
||||
#include <arrayutils.h>
|
||||
|
||||
#include "emapi.h"
|
||||
|
||||
/* MACROS ====================================================================*/
|
||||
|
||||
/* ENUMERATIONS ==============================================================*/
|
||||
|
||||
/* STRUCTS ===================================================================*/
|
||||
|
||||
/* GLOBAL VARIABLES ==========================================================*/
|
||||
|
||||
/* PROTOTYPES ================================================================*/
|
||||
|
||||
void print_strings()
|
||||
{
|
||||
int i;
|
||||
i = 0;
|
||||
|
||||
for ( i = 0 ; i < EMOP_MAX; i++ )
|
||||
printf("emop %d: %s\n", i, emop(i));
|
||||
|
||||
for ( i = 0 ; i < EMMT_MAX; i++ )
|
||||
printf("emmt %d: %s\n", i, emmt(i));
|
||||
|
||||
for ( i = 0 ; i < EMRC_MAX; i++ )
|
||||
printf("emrc %d: %s\n", i, emrc(i));
|
||||
}
|
||||
|
||||
int verify_object(void * obj, unsigned obj_len, unsigned type, unsigned buf_len)
|
||||
{
|
||||
__u8 *data;
|
||||
|
||||
/* STEPS
|
||||
* 1: Allocate Memory
|
||||
* 3: Clear memory
|
||||
* 4: Fill in object with test data
|
||||
* 5: Print Object
|
||||
* 6: Serialize Object
|
||||
* 7: Print the buffer
|
||||
* 8: Clear the object
|
||||
* 9: Deserialize buffer into object
|
||||
* 10: Free memory
|
||||
*/
|
||||
|
||||
// STEP 1: Allocate Memory
|
||||
data = (__u8*) malloc(buf_len);
|
||||
|
||||
// STEP 2: Clear memory
|
||||
memset(data, 0 , buf_len);
|
||||
|
||||
// STEP 5: Print Object
|
||||
emapi_prnt(obj, type);
|
||||
|
||||
// STEP 6: Serialize Object
|
||||
emapi_serialize(data, obj, type, NULL);
|
||||
|
||||
// STEP 6: Print the buffer
|
||||
autl_prnt_buf(data, buf_len, 4, 1);
|
||||
|
||||
// STEP 7: Clear the object
|
||||
memset(obj, 0 , obj_len);
|
||||
|
||||
// STEP 8: Deserialize buffer into object
|
||||
emapi_deserialize(obj, data, type, NULL);
|
||||
|
||||
// STEP 9: Print object
|
||||
emapi_prnt(obj, type);
|
||||
|
||||
// STEP 10: Free memory
|
||||
free(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int verify_hdr()
|
||||
{
|
||||
struct emapi_hdr obj;
|
||||
|
||||
/* STEPS
|
||||
* 1: Clear memory
|
||||
* 2: Fill in object with test data
|
||||
* 3: Verify object
|
||||
*/
|
||||
|
||||
// STEP 1: Clear memory
|
||||
memset(&obj, 0 , sizeof(obj));
|
||||
|
||||
// STEP 2: Fill in object with test data
|
||||
obj.ver = 0;
|
||||
obj.type = EMMT_RSP;
|
||||
obj.tag = 0x42;
|
||||
obj.rc = 0xCD;
|
||||
obj.opcode = 0xAB;
|
||||
obj.len = 0x1FFF;
|
||||
obj.a = 0x23;
|
||||
obj.b = 0x12345678;
|
||||
|
||||
// STEP 3: Verify object
|
||||
return verify_object(&obj, sizeof(obj), EMOB_HDR, EMLN_HDR);
|
||||
}
|
||||
|
||||
int verify_dev()
|
||||
{
|
||||
struct emapi_dev obj;
|
||||
char *name = "Device name";
|
||||
|
||||
/* STEPS
|
||||
* 1: Clear memory
|
||||
* 2: Fill in object with test data
|
||||
* 3: Verify object
|
||||
*/
|
||||
|
||||
// STEP 1: Clear memory
|
||||
memset(&obj, 0 , sizeof(obj));
|
||||
|
||||
// STEP 2: Fill in object with test data
|
||||
obj.id = 0x21;
|
||||
obj.len = strlen(name) + 1;
|
||||
sprintf(obj.name, name, obj.len);
|
||||
|
||||
// STEP 3: Verify object
|
||||
return verify_object(&obj, sizeof(obj), EMOB_LIST_DEV, obj.len+2);
|
||||
}
|
||||
|
||||
int verify_sizes()
|
||||
{
|
||||
printf("Sizeof:\n");
|
||||
printf("struct emapi_hdr: %lu\n", sizeof(struct emapi_hdr));
|
||||
printf("struct emapi_dev: %lu\n", sizeof(struct emapi_dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, max;
|
||||
const char *names[] = {
|
||||
"",
|
||||
"fmapi_hdr", // 1
|
||||
"fmapi_dev", // 2
|
||||
"sizeof()" // 3
|
||||
};
|
||||
|
||||
max = 3;
|
||||
|
||||
if (argc > 1)
|
||||
i = atoi(argv[1]);
|
||||
else {
|
||||
for ( i = 0 ; i <= max ; i++ )
|
||||
printf("TEST %d: %s\n", i, names[i]);
|
||||
goto end;
|
||||
}
|
||||
if (i > max)
|
||||
goto end;
|
||||
|
||||
printf("TEST %d: %s\n", i, names[i]);
|
||||
|
||||
switch(i)
|
||||
{
|
||||
case EMOB_HDR : verify_hdr(); break; // 1, //!< struct emapi_hdr
|
||||
case EMOB_LIST_DEV : verify_dev(); break; // 2, //!< struct emapi_dev
|
||||
case EMOB_MAX : verify_sizes(); break; // 3,
|
||||
default : print_strings(); break;
|
||||
}
|
||||
|
||||
end:
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user