blob: a3b463bbd70bceb91a5779539c0dd91906b33388 [file] [log] [blame]
/*
<:copyright-BRCM:2016:DUAL/GPL:standard
Broadcom Proprietary and Confidential.(c) 2016 Broadcom
All Rights Reserved
Unless you and Broadcom execute a separate written software license
agreement governing use of this software, this software is licensed
to you under the terms of the GNU General Public License version 2
(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
with the following added to such license:
As a special exception, the copyright holders of this software give
you permission to link this software with independent modules, and
to copy and distribute the resulting executable under terms of your
choice, provided that you also meet, for each linked independent
module, the terms and conditions of the license of that module.
An independent module is a module which is not derived from this
software. The special exception does not apply to any modifications
of the software.
Not withstanding the above, under no circumstances may you combine
this software in any way with any other Broadcom software provided
under a license other than the GPL, without Broadcom's express prior
written consent.
:>
*/
#include "bcmos_system.h"
#include "bcm_dev_log.h"
#include "bcmolt_api.h"
#include "bcm_api_cli_helpers.h"
#include "bcmolt_model_types.h"
#include "bcmtr_debug.h"
#include "bcmtr_interface.h"
#include "bcmolt_user_appl_playback.h"
#include "bcmolt_bit_utils.h"
/* 'MPBx' in ASCII (M)aple (P)lay(b)ack version x */
#define VERSION0 0x4d504230
#define VERSION1 0x4d504231
static const uint32_t CHUNK_SIZE = 2000;
static const char *cap_loc_str[BCMOLT_API_CAPTURE_LOCATION__NUM_OF] =
{
"device",
"host"
};
typedef struct
{
dev_log_id log_id;
} playback_context;
static playback_context pb_ctxt[BCMTR_MAX_OLTS];
typedef enum
{
PB_FORMAT_API_CLI,
PB_FORMAT_C_API,
PB_FORMAT__COUNT
} pb_format;
typedef enum
{
PB_CLI_EXTRA_NONE,
PB_CLI_EXTRA_MULTI,
PB_CLI_EXTRA_STAT,
PB_CLI_EXTRA_SUBGROUP
} pb_cli_extra;
typedef enum
{
PB_FIELDS_NONE,
PB_FIELDS_GET,
PB_FIELDS_MULTI,
PB_FIELDS_SET
} pb_fields;
typedef struct
{
uint32_t version;
bcmolt_api_capture_location location;
bcmolt_firmware_sw_version fw_ver;
bcmolt_host_sw_version host_ver;
uint32_t buf_size;
void *capture_buffer;
} bcmolt_playback;
typedef struct
{
bcmolt_buf buf;
bcmtr_capture_entry hdr;
uint8_t *msg_start;
} playback_iterator_raw;
typedef struct
{
playback_iterator_raw raw;
bcmolt_buf msg_buf;
bcmolt_msg *msg;
bcmos_errno err;
} playback_iterator;
#define FOR_EACH_CAPTURE_ENTRY(it, buffer, size) \
bcmolt_buf_init(&(it).buf, size, buffer, BCMOLT_BUF_ENDIAN_FIXED); \
while (bcmtr_capture_entry_get_next(&(it).buf, &(it).hdr, &(it).msg_start))
#define FOR_EACH_PLAYBACK_MSG(it, buffer, size) \
bcmolt_buf_init(&(it).raw.buf, size, buffer, BCMOLT_BUF_ENDIAN_FIXED); \
(it).msg = NULL; \
while (playback_next_entry_unpacked(&(it)))
#define DEVICE_REF "device_id"
#define RC_REF "rc"
#define VAL_REF "val"
#define MSG_REF "msg"
#define KEY_REF "key"
#define LIST_MEM_REF "list_mem"
#define MSG_SET_REF "msg_set"
#define MAX_MSGS_REF "max_msgs"
#define INVERT_FILTER_REF "invert_filter"
#define STAT_FLAGS_REF "stat_flags"
#define DYN_LIST_SIZE "APICLI_DYNAMIC_LIST_BUFFER_SIZE"
static void playback_iterator_cleanup(playback_iterator *it)
{
if ((it->err == BCM_ERR_OK) && (it->msg != NULL))
{
bcmolt_msg_free(it->msg);
it->msg = NULL;
}
}
static bcmos_bool playback_next_entry_unpacked(playback_iterator *it)
{
playback_iterator_cleanup(it);
bcmos_bool ret = bcmtr_capture_entry_get_next(&it->raw.buf, &it->raw.hdr, &it->raw.msg_start);
if (ret)
{
bcmolt_buf_init(&it->msg_buf, it->raw.hdr.msg_size, it->raw.msg_start, BCMOLT_BUF_ENDIAN_FIXED);
it->err = bcmolt_msg_unpack(&it->msg_buf, &it->msg);
}
return ret;
}
static bcmos_errno playback_read_block(uint32_t offset, uint32_t size, uint8_t *buf)
{
bcmos_errno err;
bcmolt_debug_cfg debug_cfg;
bcmolt_debug_key debug_key = { };
bcmolt_api_capture_buffer_reader reader = { .offset = offset, .size = size };
BCMOLT_CFG_INIT(&debug_cfg, debug, debug_key);
BCMOLT_CFG_PROP_SET(&debug_cfg, debug, api_capture_buffer_read, reader);
err = bcmolt_cfg_set(current_device, &debug_cfg.hdr);
if (BCM_ERR_OK != err)
{
BCM_LOG(ERROR, pb_ctxt[current_device].log_id, "Failed to update reader (%u, %u)!\n", offset, size);
}
else
{
BCMOLT_CFG_INIT(&debug_cfg, debug, debug_key);
BCMOLT_CFG_PROP_GET(&debug_cfg, debug, api_capture_buffer);
debug_cfg.data.api_capture_buffer.val = buf;
err = bcmolt_cfg_get(current_device, &debug_cfg.hdr);
if (BCM_ERR_OK != err)
{
BCM_LOG(ERROR, pb_ctxt[current_device].log_id, "Failed to retrieve capture buffer chunk (%u, %u)!\n",
offset, size);
}
}
return err;
}
static bcmos_errno playback_read(void **buffer, uint32_t *length, bcmolt_api_capture_location *capture_location)
{
bcmos_errno err;
bcmolt_debug_cfg debug_cfg;
bcmolt_debug_key debug_key = { };
if ((buffer == NULL) || (length == NULL))
{
BCM_LOG(ERROR, pb_ctxt[current_device].log_id, "buffer (%p) and length (%p) cannot be NULL\n", buffer, length);
}
BCMOLT_CFG_INIT(&debug_cfg, debug, debug_key);
BCMOLT_CFG_PROP_GET(&debug_cfg, debug, api_capture_stats);
BCMOLT_CFG_PROP_GET(&debug_cfg, debug, api_capture_cfg);
err = bcmolt_cfg_get(current_device, &debug_cfg.hdr);
if (BCM_ERR_OK != err)
{
BCM_LOG(ERROR, pb_ctxt[current_device].log_id, "Failed to retrieve capture stats!\n");
}
else
{
void *capture_buffer;
uint32_t buf_size = debug_cfg.data.api_capture_stats.readable_bytes;
uint32_t offset = 0;
*capture_location = debug_cfg.data.api_capture_cfg.location;
BCM_LOG(DEBUG, pb_ctxt[current_device].log_id, "Retrieving %u byte buffer\n", buf_size);
capture_buffer = bcmos_alloc(buf_size);
if (NULL != capture_buffer)
{
while ((offset + CHUNK_SIZE) < buf_size)
{
BCM_LOG(DEBUG, pb_ctxt[current_device].log_id, "Reading bytes %u - %u\n", offset, offset + CHUNK_SIZE);
err = playback_read_block(offset, CHUNK_SIZE, (uint8_t*)capture_buffer + offset);
if (BCM_ERR_OK != err)
{
break;
}
offset += CHUNK_SIZE;
}
if (BCM_ERR_OK == err)
{
BCM_LOG(DEBUG, pb_ctxt[current_device].log_id, "Reading bytes %u - %u\n", offset, buf_size);
err = playback_read_block(offset, buf_size - offset, (uint8_t*)capture_buffer + offset);
}
}
*buffer = capture_buffer;
*length = buf_size;
}
return err;
}
static bcmos_errno playback_dump(bcmcli_session *session, void *capture_buf, uint32_t buf_size)
{
playback_iterator it;
bcmos_errno err = BCM_ERR_OK;
FOR_EACH_PLAYBACK_MSG(it, capture_buf, buf_size)
{
BCM_LOG(DEBUG, pb_ctxt[current_device].log_id, "Dumping message at %u of %u (%u)\n",
bcmolt_buf_get_used(&it.raw.buf), buf_size, it.raw.hdr.msg_size);
bcmcli_session_print(session, "\n%08x %u:\n", it.raw.hdr.timestamp, it.raw.hdr.event);
if (BCM_ERR_OK == it.err)
{
err = apicli_msg_dump(session, it.msg);
BCM_LOG(DEBUG, pb_ctxt[current_device].log_id, "Dump status: %s\n", bcmos_strerror(err));
}
else
{
BCM_LOG(DEBUG, pb_ctxt[current_device].log_id, "Unpacking failed: %s\n", bcmos_strerror(err));
if ((it.raw.msg_start + it.raw.hdr.msg_size) > (it.raw.buf.start + it.raw.buf.len))
{
bcmcli_session_print(session, "Message length is insane!\n");
}
else
{
bcmcli_session_hexdump(session, it.raw.msg_start, 0, it.raw.hdr.msg_size, NULL);
}
}
}
return err;
}
static bcmos_bool playback_should_send(bcmolt_api_capture_location capture_location, bcmtr_cld_event_type event_type)
{
switch (capture_location)
{
case BCMOLT_API_CAPTURE_LOCATION_DEVICE:
switch (event_type)
{
case BCMTR_CLD_EV_RECV:
case BCMTR_CLD_EV_RECV_DISCARD:
return BCMOS_TRUE;
default:
return BCMOS_FALSE;
}
case BCMOLT_API_CAPTURE_LOCATION_HOST:
switch (event_type)
{
case BCMTR_CLD_EV_SEND:
case BCMTR_CLD_EV_RESEND:
return BCMOS_TRUE;
default:
return BCMOS_FALSE;
}
default:
return BCMOS_FALSE;
}
}
/*lint -e{429} */
static bcmos_errno playback_replay(
bcmolt_devid device,
void *capture_buf,
uint32_t buf_size,
bcmolt_api_capture_location location,
bcmos_bool keep_time)
{
bcmos_errno err = BCM_ERR_OK;
playback_iterator_raw it;
uint32_t last_time_us = 0;
bcmos_bool first = BCMOS_TRUE;
FOR_EACH_CAPTURE_ENTRY(it, capture_buf, buf_size)
{
bcmolt_buf msg_buf;
bcmolt_msg *msg = NULL;
BCM_LOG(DEBUG, pb_ctxt[device].log_id, "Processing message (%u,%u,%u)\n",
it.hdr.event, it.hdr.timestamp, it.hdr.msg_size);
if (playback_should_send(location, (bcmtr_cld_event_type)it.hdr.event))
{
if (keep_time)
{
if (!first)
{
/* approximate original timing; doesn't account for processing time in this code - this could be
improved */
BCM_LOG(DEBUG, pb_ctxt[device].log_id, "Sleeping for %u us\n", it.hdr.timestamp - last_time_us);
bcmos_usleep(it.hdr.timestamp - last_time_us);
}
else
{
first = BCMOS_FALSE;
}
last_time_us = it.hdr.timestamp;
}
BCM_LOG(DEBUG, pb_ctxt[device].log_id, "Unpacking message\n");
bcmolt_buf_init(&msg_buf, it.hdr.msg_size, it.msg_start, BCMOLT_BUF_ENDIAN_FIXED);
err = bcmolt_msg_unpack(&msg_buf, &msg);
if (BCM_ERR_OK == err)
{
BCM_LOG(DEBUG, pb_ctxt[device].log_id, "Sending message\n");
err = bcmtr_send(device, msg, BCMTR_SEND_FLAGS_NONE);
bcmolt_msg_free(msg);
if (BCM_ERR_OK != err)
{
BCM_LOG(INFO, pb_ctxt[device].log_id, "Sending failed: %s\n", bcmos_strerror(err));
return err;
}
}
else
{
BCM_LOG(INFO, pb_ctxt[device].log_id, "Unpacking failed: %s\n", bcmos_strerror(err));
return err;
}
}
}
return err;
}
static bcmos_errno playback_cli_dump(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms)
{
bcmos_errno err;
void *capture_buffer;
uint32_t buf_size;
bcmolt_api_capture_location location;
err = playback_read(&capture_buffer, &buf_size, &location);
if (BCM_ERR_OK == err)
{
bcmcli_print(session, "Capture from %s:\n", cap_loc_str[location]);
playback_dump(session, capture_buffer, buf_size);
}
bcmos_free(capture_buffer);
return err;
}
static void playback_fw_version_get(bcmolt_devid device, bcmolt_firmware_sw_version *fw)
{
bcmos_errno err;
bcmolt_device_cfg dev_cfg;
bcmolt_device_key dev_key = { };
BCMOLT_CFG_INIT(&dev_cfg, device, dev_key);
BCMOLT_CFG_PROP_GET(&dev_cfg, device, firmware_sw_version);
err = bcmolt_cfg_get(device, &dev_cfg.hdr);
if (BCM_ERR_OK != err)
{
BCM_LOG(WARNING, pb_ctxt[device].log_id, "Failed to retrieve fw version!\n");
}
else
{
*fw = dev_cfg.data.firmware_sw_version;
}
}
static void playback_host_version_get(bcmolt_devid device, bcmolt_host_sw_version *host)
{
bcmos_errno err;
bcmolt_device_cfg dev_cfg;
bcmolt_device_key dev_key = { };
BCMOLT_CFG_INIT(&dev_cfg, device, dev_key);
BCMOLT_CFG_PROP_GET(&dev_cfg, device, host_sw_version);
err = bcmolt_cfg_get(device, &dev_cfg.hdr);
if (BCM_ERR_OK != err)
{
BCM_LOG(WARNING, pb_ctxt[device].log_id, "Failed to retrieve host version!\n");
}
else
{
*host = dev_cfg.data.host_sw_version;
}
}
static bcmos_errno playback_cli_save(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms)
{
const char *filename = bcmcli_find_named_parm(session, "file")->value.string;
bcmolt_playback mpb = {};
bcmos_errno err;
FILE *file;
uint32_t temp;
err = playback_read(&mpb.capture_buffer, &mpb.buf_size, &mpb.location);
if (BCM_ERR_OK == err)
{
playback_fw_version_get(current_device, &mpb.fw_ver);
playback_host_version_get(current_device, &mpb.host_ver);
file = fopen(filename, "wb");
/* write file version */
temp = BCMOLT_BUF_ENDIAN_CPU_TO_BUF(U32, VERSION1);
fwrite(&temp, sizeof(uint32_t), 1, file);
/* write capture location */
temp = BCMOLT_BUF_ENDIAN_CPU_TO_BUF(U32, (uint32_t)mpb.location);
fwrite(&temp, sizeof(uint32_t), 1, file);
/* write firmware version */
fwrite(&mpb.fw_ver.major, sizeof(uint8_t), 1, file);
fwrite(&mpb.fw_ver.minor, sizeof(uint8_t), 1, file);
fwrite(&mpb.fw_ver.revision, sizeof(uint8_t), 1, file);
temp = BCMOLT_BUF_ENDIAN_CPU_TO_BUF(U32, mpb.fw_ver.model);
fwrite(&temp, sizeof(uint32_t), 1, file);
fwrite(mpb.fw_ver.build_time, sizeof(mpb.fw_ver.build_time), 1, file);
/* write host version */
fwrite(&mpb.host_ver.major, sizeof(uint8_t), 1, file);
fwrite(&mpb.host_ver.minor, sizeof(uint8_t), 1, file);
fwrite(&mpb.host_ver.revision, sizeof(uint8_t), 1, file);
temp = BCMOLT_BUF_ENDIAN_CPU_TO_BUF(U32, mpb.host_ver.model);
fwrite(&temp, sizeof(uint32_t), 1, file);
fwrite(mpb.host_ver.build_time, sizeof(mpb.host_ver.build_time), 1, file);
/* write capture buffer */
temp = BCMOLT_BUF_ENDIAN_CPU_TO_BUF(U32, mpb.buf_size);
fwrite(&temp, sizeof(uint32_t), 1, file);
fwrite(mpb.capture_buffer, mpb.buf_size, 1, file);
fclose(file);
}
bcmos_free(mpb.capture_buffer);
return err;
}
static bcmos_bool playback_version_match(const bcmolt_playback *mpb)
{
bcmolt_firmware_sw_version fw_curr = {};
bcmolt_host_sw_version host_curr = {};
playback_fw_version_get(current_device, &fw_curr);
playback_host_version_get(current_device, &host_curr);
if ((mpb->fw_ver.model != fw_curr.model) || (mpb->host_ver.model != host_curr.model) ||
(fw_curr.model == 0) || (host_curr.model == 0))
{
BCM_LOG(WARNING, pb_ctxt[current_device].log_id,
"Possible version mismatch: Capture FW %u, HOST %u; Current FW %u, HOST %u\n",
mpb->fw_ver.model, mpb->host_ver.model, fw_curr.model, host_curr.model);
return BCMOS_FALSE;
}
return BCMOS_TRUE;
}
static bcmos_errno playback_file_open(const char *filename, bcmolt_playback *mpb)
{
FILE *file;
uint32_t temp;
bcmos_errno err = BCM_ERR_OK;
uint32_t items_read;
file = fopen(filename, "rb");
items_read = fread(&temp, sizeof(uint32_t), 1, file);
if (items_read != 1)
return BCM_ERR_PARSE;
mpb->version = BCMOLT_BUF_ENDIAN_BUF_TO_CPU(U32, temp);
switch (mpb->version)
{
case VERSION0:
items_read = fread(&temp, sizeof(uint32_t), 1, file);
if (items_read != 1)
break;
temp = BCMOLT_BUF_ENDIAN_BUF_TO_CPU(U32, temp);
mpb->location = (bcmolt_api_capture_location)temp;
items_read = fread(&temp, sizeof(uint32_t), 1, file);
if (items_read != 1)
break;
mpb->buf_size = BCMOLT_BUF_ENDIAN_BUF_TO_CPU(U32, temp);
mpb->capture_buffer = bcmos_alloc(mpb->buf_size);
items_read = fread(mpb->capture_buffer, mpb->buf_size, 1, file);
if (items_read != 1)
break;
break;
case VERSION1:
/* read capture location */
items_read = fread(&temp, sizeof(uint32_t), 1, file);
if (items_read != 1)
break;
temp = BCMOLT_BUF_ENDIAN_BUF_TO_CPU(U32, temp);
mpb->location = (bcmolt_api_capture_location)temp;
/* read firmware version */
items_read = fread(&mpb->fw_ver.major, sizeof(uint8_t), 1, file);
if (items_read != 1)
break;
items_read = fread(&mpb->fw_ver.minor, sizeof(uint8_t), 1, file);
if (items_read != 1)
break;
items_read = fread(&mpb->fw_ver.revision, sizeof(uint8_t), 1, file);
if (items_read != 1)
break;
items_read = fread(&temp, sizeof(uint32_t), 1, file);
if (items_read != 1)
break;
mpb->fw_ver.model = BCMOLT_BUF_ENDIAN_BUF_TO_CPU(U32, temp);
items_read = fread(mpb->fw_ver.build_time, sizeof(mpb->fw_ver.build_time), 1, file);
if (items_read != 1)
break;
/* read host version */
items_read = fread(&mpb->host_ver.major, sizeof(uint8_t), 1, file);
if (items_read != 1)
break;
items_read = fread(&mpb->host_ver.minor, sizeof(uint8_t), 1, file);
if (items_read != 1)
break;
items_read = fread(&mpb->host_ver.revision, sizeof(uint8_t), 1, file);
if (items_read != 1)
break;
items_read = fread(&temp, sizeof(uint32_t), 1, file);
if (items_read != 1)
break;
mpb->host_ver.model = BCMOLT_BUF_ENDIAN_BUF_TO_CPU(U32, temp);
items_read = fread(mpb->host_ver.build_time, sizeof(mpb->host_ver.build_time), 1, file);
if (items_read != 1)
break;
/* read capture buffer */
items_read = fread(&temp, sizeof(uint32_t), 1, file);
if (items_read != 1)
break;
mpb->buf_size = BCMOLT_BUF_ENDIAN_BUF_TO_CPU(U32, temp);
mpb->capture_buffer = bcmos_alloc(mpb->buf_size);
items_read = fread(mpb->capture_buffer, mpb->buf_size, 1, file);
if (items_read != 1)
break;
break;
default:
BCM_LOG(ERROR, pb_ctxt[current_device].log_id, "Unknown version: %u\n", mpb->version);
err = BCM_ERR_PARSE;
break;
}
fclose(file);
return err;
}
static bcmos_errno playback_cli_replay(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms)
{
const char *filename = bcmcli_find_named_parm(session, "file")->value.string;
bcmos_bool ignore_ver = BCMOS_FALSE;
bcmos_errno err;
bcmolt_playback mpb = {};
bcmcli_cmd_parm *iv_parm = bcmcli_find_named_parm(session, "ignore_version");
if (iv_parm != NULL)
{
ignore_ver = iv_parm->value.enum_val == (long)BCMOS_TRUE;
}
err = playback_file_open(filename, &mpb);
if (BCM_ERR_OK == err)
{
if (playback_version_match(&mpb) || ignore_ver)
{
err = playback_replay(current_device, mpb.capture_buffer, mpb.buf_size, mpb.location, BCMOS_TRUE);
}
else
{
bcmcli_print(session, "Possible version mismatch; use ignore_version=yes to force playback\n");
err = BCM_ERR_IMAGE_TYPE;
}
bcmos_free(mpb.capture_buffer);
}
return err;
}
static bcmos_errno playback_api_cli_append_prop(
bcmolt_string *api_cli,
uint32_t size,
void *data,
const bcmcli_prop_descr *pd,
const char *prefix)
{
bcmos_errno err;
bcmcli_session *str;
void *prop_data = (void *)((long)data + pd->offset);
BCMOS_CHECK_RETURN_ERROR(pd->offset >= size, BCM_ERR_INTERNAL);
err = bcmcli_session_open_string(&str, api_cli);
BCMOS_RETURN_IF_ERROR(err);
err = apicli_dump_prop_param(str, pd, prop_data, prefix);
bcmcli_session_close(str);
BCMOS_RETURN_IF_ERROR(err);
return BCM_ERR_OK;
}
static bcmos_errno playback_api_cli_key_write(
bcmolt_string* api_cli,
const bcmolt_msg* msg,
uint32_t key_size,
uint32_t key_offset)
{
bcmos_errno err;
const bcmcli_prop_descr *pd;
void *data = (void *)((long)msg + key_offset);
for (uint16_t prop = 0;
api_cli_object_property(msg->obj_type, BCMOLT_MGT_GROUP_KEY, 0, prop, &pd) == BCM_ERR_OK;
++prop)
{
err = playback_api_cli_append_prop(api_cli, key_size, data, pd, " ");
BCMOS_RETURN_IF_ERROR(err);
}
return BCM_ERR_OK;
}
static bcmos_errno playback_api_cli_pm_write(bcmolt_string *api_cli, const bcmolt_msg* msg, bcmolt_presence_mask pm)
{
int n;
const bcmcli_prop_descr *pd;
for (uint16_t prop = 0;
api_cli_object_property(msg->obj_type, msg->group, msg->subgroup, prop, &pd) == BCM_ERR_OK;
++prop)
{
if (!(pm & (1ULL << prop)))
{
continue;
}
n = bcmolt_string_append(api_cli, " %s=yes", pd->name);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
return BCM_ERR_OK;
}
static bcmos_errno playback_api_cli_props_write(
bcmolt_string *api_cli,
const bcmolt_msg* msg,
const char *prefix,
uint32_t size,
uint32_t offset)
{
bcmos_errno err;
const bcmcli_prop_descr *pd;
void *data = (void *)((long)msg + offset);
for (uint16_t prop = 0;
api_cli_object_property(msg->obj_type, msg->group, msg->subgroup, prop, &pd) == BCM_ERR_OK;
++prop)
{
if (!(msg->presence_mask & (1ULL << prop)))
{
continue;
}
err = playback_api_cli_append_prop(api_cli, size, data, pd, prefix);
BCMOS_RETURN_IF_ERROR(err);
}
return BCM_ERR_OK;
}
static bcmos_errno playback_api_cli_cmd_get(
bcmolt_string *api_cli,
const bcmolt_msg* msg,
const char *cmd,
pb_cli_extra extra_parms,
pb_fields field_parms)
{
int n;
bcmos_errno err;
const char *name;
const char *desc;
uint32_t key_size;
uint32_t key_offset;
uint32_t data_size;
uint32_t data_offset;
BCM_LOG(DEBUG, pb_ctxt[current_device].log_id, "Start %s\n", cmd);
err = api_cli_object_name(msg->obj_type, &name, &desc);
BCMOS_RETURN_IF_ERROR(err);
n = bcmolt_string_append(api_cli, "/api/%s object=%s", cmd, name);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
switch (extra_parms)
{
case PB_CLI_EXTRA_MULTI:
n = bcmolt_string_append(
api_cli,
" max_msgs=%u filter_invert=%s",
msg->msg_set->max_instances,
BITS_SET(msg->msg_set->filter_flags, BCMOLT_FILTER_FLAGS_INVERT_SELECTION) ? "yes" : "no");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
break;
case PB_CLI_EXTRA_STAT:
n = bcmolt_string_append(api_cli, " clear=%s", BITS_SET(msg->type, BCMOLT_MSG_TYPE_CLEAR) ? "yes" : "no");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
break;
case PB_CLI_EXTRA_SUBGROUP:
err = api_cli_object_subgroup_name(msg->obj_type, msg->group, msg->subgroup, &name, &desc);
BCMOS_RETURN_IF_ERROR(err);
n = bcmolt_string_append(api_cli, " sub=%s", name);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
break;
default:
break;
}
/* get message info */
err = api_cli_object_struct_size(
msg->obj_type,
msg->group,
msg->subgroup,
&key_size,
&key_offset,
&data_size,
&data_offset);
BCMOS_RETURN_IF_ERROR(err);
if (BCMOLT_MGT_GROUP_AUTO_CFG != msg->group)
{
/* write key */
err = playback_api_cli_key_write(api_cli, msg, key_size, key_offset);
BCMOS_RETURN_IF_ERROR(err);
}
switch (field_parms)
{
case PB_FIELDS_GET:
/* write presence mask */
err = playback_api_cli_pm_write(api_cli, msg, msg->presence_mask);
BCMOS_RETURN_IF_ERROR(err);
break;
case PB_FIELDS_MULTI:
/* write filter */
err = playback_api_cli_props_write(api_cli, msg, " filter.", data_size, data_offset);
BCMOS_RETURN_IF_ERROR(err);
/* write presence mask */
err = playback_api_cli_pm_write(api_cli, msg, msg->msg_set->presence_mask);
BCMOS_RETURN_IF_ERROR(err);
break;
case PB_FIELDS_SET:
/* write properties */
err = playback_api_cli_props_write(api_cli, msg, " ", data_size, data_offset);
BCMOS_RETURN_IF_ERROR(err);
break;
default:
break;
}
n = bcmolt_string_append(api_cli, "\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
BCM_LOG(DEBUG, pb_ctxt[current_device].log_id, "End %s\n", cmd);
return err;
}
static bcmos_errno playback_api_cli_get(bcmolt_string* api_cli, const bcmolt_msg* msg)
{
switch (msg->group)
{
case BCMOLT_MGT_GROUP_CFG:
switch (msg->type)
{
case BCMOLT_MSG_TYPE_GET:
return playback_api_cli_cmd_get(api_cli, msg, "get", PB_CLI_EXTRA_NONE, PB_FIELDS_GET);
case BCMOLT_MSG_TYPE_GET_MULTI:
return playback_api_cli_cmd_get(api_cli, msg, "multiget", PB_CLI_EXTRA_MULTI, PB_FIELDS_MULTI);
case BCMOLT_MSG_TYPE_SET:
return playback_api_cli_cmd_get(api_cli, msg, "set", PB_CLI_EXTRA_NONE, PB_FIELDS_SET);
case BCMOLT_MSG_TYPE_CLEAR:
return playback_api_cli_cmd_get(api_cli, msg, "clear", PB_CLI_EXTRA_NONE, PB_FIELDS_NONE);
default:
return BCM_ERR_INTERNAL;
}
break;
case BCMOLT_MGT_GROUP_STAT:
return playback_api_cli_cmd_get(api_cli, msg, "stat", PB_CLI_EXTRA_STAT, PB_FIELDS_GET);
case BCMOLT_MGT_GROUP_STAT_CFG:
switch (msg->type)
{
case BCMOLT_MSG_TYPE_GET:
return playback_api_cli_cmd_get(api_cli, msg, "saget", PB_CLI_EXTRA_SUBGROUP, PB_FIELDS_NONE);
case BCMOLT_MSG_TYPE_SET:
return playback_api_cli_cmd_get(api_cli, msg, "saset", PB_CLI_EXTRA_SUBGROUP, PB_FIELDS_SET);
default:
return BCM_ERR_INTERNAL;
}
break;
case BCMOLT_MGT_GROUP_AUTO_CFG:
switch (msg->type)
{
case BCMOLT_MSG_TYPE_GET:
return playback_api_cli_cmd_get(api_cli, msg, "acget", PB_CLI_EXTRA_NONE, PB_FIELDS_GET);
case BCMOLT_MSG_TYPE_SET:
return playback_api_cli_cmd_get(api_cli, msg, "acset", PB_CLI_EXTRA_NONE, PB_FIELDS_SET);
default:
return BCM_ERR_INTERNAL;
}
break;
case BCMOLT_MGT_GROUP_OPER:
return playback_api_cli_cmd_get(api_cli, msg, "oper", PB_CLI_EXTRA_SUBGROUP, PB_FIELDS_SET);
case BCMOLT_MGT_GROUP_PROXY:
return playback_api_cli_cmd_get(api_cli, msg, "send", PB_CLI_EXTRA_SUBGROUP, PB_FIELDS_SET);
default:
return BCM_ERR_INTERNAL;
}
}
static bcmos_errno playback_convert_api_cli(bcmolt_playback *mpb, FILE *out_file)
{
playback_iterator it;
bcmos_errno err;
bcmolt_string *str;
err = bcmolt_string_create(&str, 2048);
BCMOS_RETURN_IF_ERROR(err);
FOR_EACH_PLAYBACK_MSG(it, mpb->capture_buffer, mpb->buf_size)
{
if (playback_should_send(mpb->location, (bcmtr_cld_event_type)it.raw.hdr.event))
{
if (BCM_ERR_OK == it.err)
{
bcmolt_string_reset(str);
err = playback_api_cli_get(str, it.msg);
fwrite(bcmolt_string_get(str), sizeof(char), strlen(bcmolt_string_get(str)), out_file);
}
else
{
err = it.err;
BCM_LOG(ERROR, pb_ctxt[current_device].log_id, "Unpacking failed: %s\n", bcmos_strerror(err));
}
}
}
bcmolt_string_destroy(str);
return err;
}
static bcmos_bool playback_field_contains_var_list(const bcmcli_type_descr *type)
{
if (type == NULL)
{
return BCMOS_FALSE;
}
if (type->base_type == BCMOLT_BASE_TYPE_ID_ARR_DYN)
{
return BCMOS_TRUE;
}
else if (type->base_type == BCMOLT_BASE_TYPE_ID_ARR_FIXED)
{
return playback_field_contains_var_list(type->x.arr_fixed.elem_type);
}
else if (type->base_type == BCMOLT_BASE_TYPE_ID_STRUCT)
{
for (uint16_t i = 0; i < type->x.s.num_fields; ++i)
{
if (playback_field_contains_var_list(type->x.s.fields[i].type))
{
return BCMOS_TRUE;
}
}
}
else if (type->base_type == BCMOLT_BASE_TYPE_ID_UNION)
{
for (uint16_t i = 0; i < type->x.u.num_common_fields; ++i)
{
if (playback_field_contains_var_list(type->x.u.common_fields[i].type))
{
return BCMOS_TRUE;
}
}
for (uint16_t i = 0; type->x.u.common_fields[type->x.u.classifier_idx].type->x.e[i].name != NULL; ++i)
{
if (playback_field_contains_var_list(type->x.u.union_fields[i].type))
{
return BCMOS_TRUE;
}
}
}
else
{
/* not a variable sized list */
}
return BCMOS_FALSE;
}
static bcmos_bool playback_msg_contains_var_list(const bcmolt_msg* msg)
{
const bcmcli_prop_descr *pd;
for (uint16_t prop = 0;
api_cli_object_property(msg->obj_type, msg->group, msg->subgroup, prop, &pd) == BCM_ERR_OK;
++prop)
{
if (playback_field_contains_var_list(pd->type))
{
return BCMOS_TRUE;
}
}
return BCMOS_FALSE;
}
static bcmos_errno playback_string_write_upper(bcmolt_string *dest, const char* src)
{
int n;
while (*src != '\0')
{
n = bcmolt_string_append(dest, "%c", (char)toupper((int)*src));
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
++src;
}
return BCM_ERR_OK;
}
static bcmos_errno playback_c_api_pm_write(
bcmolt_string *c_api,
const bcmolt_msg* msg,
bcmolt_presence_mask pm,
const char *extra,
const char *field,
const char *obj)
{
int n;
bcmos_errno err;
const bcmcli_prop_descr *pd;
for (uint16_t prop = 0;
api_cli_object_property(msg->obj_type, msg->group, msg->subgroup, prop, &pd) == BCM_ERR_OK;
++prop)
{
if (!(pm & (1ULL << prop)))
{
continue;
}
n = bcmolt_string_append(c_api, "\tBCMOLT_%s", extra);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
err = playback_string_write_upper(c_api, apicli_mgt_group_to_str(msg->group));
BCMOS_RETURN_IF_ERROR(err);
n = bcmolt_string_append(c_api, "_PROP_GET(%s, %s, %s);\n", field, obj, pd->name);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
return BCM_ERR_OK;
}
static bcmos_errno playback_c_api_append_init(
bcmolt_string *c_api,
void *data,
const bcmcli_type_descr *td,
const char* name)
{
bcmos_errno rc;
bcmcli_session *str;
rc = bcmcli_session_open_string(&str, c_api);
BCMOS_RETURN_IF_ERROR(rc);
rc = apicli_dump_dyn_array(str, td, data, name);
bcmcli_session_close(str);
BCMOS_RETURN_IF_ERROR(rc);
return BCM_ERR_OK;
}
static bcmos_errno playback_c_api_append_prop(
bcmolt_string *c_api,
uint32_t size,
void *data,
const bcmcli_prop_descr *pd)
{
bcmos_errno err;
bcmcli_session *str;
void *prop_data = (void *)((long)data + pd->offset);
BCMOS_CHECK_RETURN_ERROR(pd->offset >= size, BCM_ERR_INTERNAL);
err = bcmcli_session_open_string(&str, c_api);
BCMOS_RETURN_IF_ERROR(err);
err = apicli_dump_prop_initializer(str, pd, prop_data);
bcmcli_session_close(str);
BCMOS_RETURN_IF_ERROR(err);
return BCM_ERR_OK;
}
static bcmos_errno playback_c_api_make_var_lists(
bcmolt_string *c_api,
const bcmcli_type_descr *type,
void *data,
const char *name)
{
int n;
bcmos_errno rc;
if (type == NULL)
{
return BCM_ERR_OK;
}
if (type->base_type == BCMOLT_BASE_TYPE_ID_ARR_DYN)
{
n = bcmolt_string_append(c_api, "\t%s %s[] = ", type->x.arr_dyn.elem_type->name, name);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
rc = playback_c_api_append_init(c_api, data, type, name);
BCMOS_RETURN_IF_ERROR(rc);
n = bcmolt_string_append(c_api, ";\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
else if (type->base_type == BCMOLT_BASE_TYPE_ID_ARR_FIXED)
{
for (uint16_t i = 0; i < type->x.arr_fixed.size; ++i)
{
char index_name[64];
sprintf(index_name, "%s%u", name, i);
rc = playback_c_api_make_var_lists(c_api, type->x.arr_fixed.elem_type, data, index_name);
BCMOS_RETURN_IF_ERROR(rc);
data = (void*)((long)data + type->x.arr_fixed.elem_type->size);
}
}
else if (type->base_type == BCMOLT_BASE_TYPE_ID_STRUCT)
{
for (uint16_t i = 0; i < type->x.s.num_fields; ++i)
{
const bcmcli_field_descr *field = &type->x.s.fields[i];
rc = playback_c_api_make_var_lists(c_api, field->type, (void*)((long)data + field->offset), field->name);
BCMOS_RETURN_IF_ERROR(rc);
}
}
else if (type->base_type == BCMOLT_BASE_TYPE_ID_UNION)
{
for (uint16_t i = 0; i < type->x.u.num_common_fields; ++i)
{
const bcmcli_field_descr *field = &type->x.u.common_fields[i];
rc = playback_c_api_make_var_lists(c_api, field->type, (void*)((long)data + field->offset), field->name);
BCMOS_RETURN_IF_ERROR(rc);
}
for (uint16_t i = 0; type->x.u.common_fields[type->x.u.classifier_idx].type->x.e[i].name != NULL; ++i)
{
const bcmcli_field_descr *field = &type->x.u.union_fields[i];
rc = playback_c_api_make_var_lists(c_api, field->type, (void*)((long)data + field->offset), field->name);
BCMOS_RETURN_IF_ERROR(rc);
}
}
else
{
/* not a variable sized list */
}
return BCM_ERR_OK;
}
static bcmos_errno playback_c_api_props_write(
bcmolt_string *c_api,
const bcmolt_msg* msg,
const char* object,
uint32_t size,
uint32_t offset)
{
int n;
bcmos_errno err;
const char *subgroup;
const char *desc;
const bcmcli_prop_descr *pd;
void *data = (void *)((long)msg + offset);
for (uint16_t prop = 0;
api_cli_object_property(msg->obj_type, msg->group, msg->subgroup, prop, &pd) == BCM_ERR_OK;
++prop)
{
if (!(msg->presence_mask & (1ULL << prop)))
{
continue;
}
playback_c_api_make_var_lists(c_api, pd->type, (void*)((long)data + pd->offset), pd->name);
}
for (uint16_t prop = 0;
api_cli_object_property(msg->obj_type, msg->group, msg->subgroup, prop, &pd) == BCM_ERR_OK;
++prop)
{
if (!(msg->presence_mask & (1ULL << prop)))
{
continue;
}
if ((pd->type->base_type == BCMOLT_BASE_TYPE_ID_STRUCT) ||
(pd->type->base_type == BCMOLT_BASE_TYPE_ID_UNION) ||
(pd->type->base_type == BCMOLT_BASE_TYPE_ID_ARR_DYN) ||
(pd->type->base_type == BCMOLT_BASE_TYPE_ID_ARR_FIXED))
{
n = bcmolt_string_append(c_api, "\t%s "VAL_REF" = ", pd->type->name);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
err = playback_c_api_append_prop(c_api, size, data, pd);
BCMOS_RETURN_IF_ERROR(err);
n = bcmolt_string_append(c_api, ";\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
n = bcmolt_string_append(c_api, "\tBCMOLT_");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
err = playback_string_write_upper(c_api, apicli_mgt_group_to_str(msg->group));
BCMOS_RETURN_IF_ERROR(err);
n = bcmolt_string_append(c_api, "_PROP_SET(&msg, %s", object);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
if ((msg->group == BCMOLT_MGT_GROUP_OPER) || (msg->group == BCMOLT_MGT_GROUP_PROXY))
{
err = api_cli_object_subgroup_name(msg->obj_type, msg->group, msg->subgroup, &subgroup, &desc);
BCMOS_RETURN_IF_ERROR(err);
n = bcmolt_string_append(c_api, ", %s", subgroup);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
n = bcmolt_string_append(c_api, ", %s, "VAL_REF");\n", pd->name);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
else
{
n = bcmolt_string_append(c_api, "\tBCMOLT_");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
err = playback_string_write_upper(c_api, apicli_mgt_group_to_str(msg->group));
BCMOS_RETURN_IF_ERROR(err);
n = bcmolt_string_append(c_api, "_PROP_SET(&msg, %s", object);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
if ((msg->group == BCMOLT_MGT_GROUP_OPER) || (msg->group == BCMOLT_MGT_GROUP_PROXY))
{
err = api_cli_object_subgroup_name(msg->obj_type, msg->group, msg->subgroup, &subgroup, &desc);
BCMOS_RETURN_IF_ERROR(err);
n = bcmolt_string_append(c_api, ", %s", subgroup);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
n = bcmolt_string_append(c_api, ", %s, ", pd->name);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
err = playback_c_api_append_prop(c_api, size, data, pd);
BCMOS_RETURN_IF_ERROR(err);
n = bcmolt_string_append(c_api, ");\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
}
return BCM_ERR_OK;
}
static bcmos_errno playback_c_api_code_get(
bcmolt_string* c_api,
const bcmolt_msg* msg,
const char *call,
pb_fields field_parms)
{
int n;
bcmos_errno err;
const char *object;
const char *group;
const char *subgroup;
const char *desc;
uint32_t key_size;
uint32_t key_offset;
uint32_t data_size;
uint32_t data_offset;
void *data;
const bcmcli_prop_descr *pd;
bcmos_bool var_list = (BCMOLT_MSG_TYPE_GET == msg->type) && playback_msg_contains_var_list(msg);
err = api_cli_object_name(msg->obj_type, &object, &desc);
BCMOS_RETURN_IF_ERROR(err);
err = api_cli_object_subgroup_name(msg->obj_type, msg->group, msg->subgroup, &subgroup, &desc);
BCMOS_RETURN_IF_ERROR(err);
group = apicli_mgt_group_to_str(msg->group);
/* get message info */
err = api_cli_object_struct_size(
msg->obj_type,
msg->group,
msg->subgroup,
&key_size,
&key_offset,
&data_size,
&data_offset);
BCMOS_RETURN_IF_ERROR(err);
/* init variables */
n = bcmolt_string_append(c_api, "\t{\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
if ((msg->group == BCMOLT_MGT_GROUP_OPER) || (msg->group == BCMOLT_MGT_GROUP_PROXY))
{
n = bcmolt_string_append(c_api, "\tbcmolt_%s_%s "MSG_REF";\n", object, subgroup);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
else
{
n = bcmolt_string_append(c_api, "\tbcmolt_%s_%s "MSG_REF";\n", object, group);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
n = bcmolt_string_append(c_api, "\tbcmolt_%s_key "KEY_REF" = { };\n", object);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
if (var_list)
{
n = bcmolt_string_append(c_api, "\tuint8_t* "LIST_MEM_REF";\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
if (msg->type == BCMOLT_MSG_TYPE_GET_MULTI)
{
n = bcmolt_string_append(c_api, "\tbcmolt_msg_set* "MSG_SET_REF" = NULL;\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
n = bcmolt_string_append(c_api, "\tuint32_t "MAX_MSGS_REF";\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
n = bcmolt_string_append(c_api, "\tbcmos_bool "INVERT_FILTER_REF";\n\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
n = bcmolt_string_append(c_api, "\t"MAX_MSGS_REF" = %d;\n", msg->msg_set->max_instances);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
n = bcmolt_string_append(c_api, "\t"INVERT_FILTER_REF" = %s;\n", BITS_SET(msg->msg_set->filter_flags, BCMOLT_FILTER_FLAGS_INVERT_SELECTION) ? "BCMOS_TRUE" : "BCMOS_FALSE");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
n = bcmolt_string_append(c_api, "\tbcmolt_msg_set_alloc(BCMOLT_OBJ_ID_");
err = playback_string_write_upper(c_api, object);
BCMOS_RETURN_IF_ERROR(err);
n = bcmolt_string_append(c_api, ", BCMOLT_MGT_GROUP_");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
err = playback_string_write_upper(c_api, group);
BCMOS_RETURN_IF_ERROR(err);
n = bcmolt_string_append(c_api, ", "MAX_MSGS_REF", &"MSG_SET_REF");\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
else if (msg->group == BCMOLT_MGT_GROUP_STAT)
{
n = bcmolt_string_append(c_api, "\tbcmolt_stat_flags "STAT_FLAGS_REF";\n\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
n = bcmolt_string_append(c_api, "\t"STAT_FLAGS_REF" = %s;\n", BITS_SET(msg->type, BCMOLT_MSG_TYPE_CLEAR) ? "BCMOLT_STAT_FLAGS_CLEAR_ON_READ" : "BCMOLT_STAT_FLAGS_NONE");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
else
{
n = bcmolt_string_append(c_api, "\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
/* set key */
if (BCMOLT_MGT_GROUP_AUTO_CFG != msg->group)
{
/* write key */
data = (void *)((long)msg + key_offset);
for (uint16_t prop = 0;
api_cli_object_property(msg->obj_type, BCMOLT_MGT_GROUP_KEY, 0, prop, &pd) == BCM_ERR_OK;
++prop)
{
n = bcmolt_string_append(c_api, "\t"KEY_REF".%s = ", pd->name);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
if ((BCMOLT_BASE_TYPE_ID_MAC == pd->type->base_type) ||
(BCMOLT_BASE_TYPE_ID_IPV4 == pd->type->base_type) ||
(BCMOLT_BASE_TYPE_ID_STRUCT == pd->type->base_type) ||
(BCMOLT_BASE_TYPE_ID_UNION == pd->type->base_type))
{
n = bcmolt_string_append(c_api, "(%s)", pd->type->name);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
err = playback_c_api_append_prop(c_api, key_size, data, pd);
BCMOS_RETURN_IF_ERROR(err);
n = bcmolt_string_append(c_api, ";\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
}
/* set properties */
n = bcmolt_string_append(c_api, "\tBCMOLT_");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
err = playback_string_write_upper(c_api, group);
BCMOS_RETURN_IF_ERROR(err);
n = bcmolt_string_append(c_api, "_INIT(&"MSG_REF", %s", object);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
if ((msg->group == BCMOLT_MGT_GROUP_STAT_CFG) ||
(msg->group == BCMOLT_MGT_GROUP_OPER) ||
(msg->group == BCMOLT_MGT_GROUP_PROXY))
{
n = bcmolt_string_append(c_api, ", %s", subgroup);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
n = bcmolt_string_append(c_api, ", "KEY_REF");\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
switch (field_parms)
{
case PB_FIELDS_GET:
/* write presence mask */
err = playback_c_api_pm_write(c_api, msg, msg->presence_mask, "", "&"MSG_REF, object);
BCMOS_RETURN_IF_ERROR(err);
if (var_list)
{
n = bcmolt_string_append(c_api, "\t"LIST_MEM_REF" = bcmos_calloc("DYN_LIST_SIZE");\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
n = bcmolt_string_append(
c_api,
"\tBCMOLT_CFG_LIST_BUF_SET(&"MSG_REF", %s, "LIST_MEM_REF", "DYN_LIST_SIZE");\n", object);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
break;
case PB_FIELDS_MULTI:
/* write filter */
err = playback_c_api_props_write(c_api, msg, object, data_size, data_offset);
BCMOS_RETURN_IF_ERROR(err);
/* write presence mask */
err = playback_c_api_pm_write(c_api, msg, msg->presence_mask, "MSGSET_", MSG_SET_REF, object);
BCMOS_RETURN_IF_ERROR(err);
break;
case PB_FIELDS_SET:
/* write properties */
err = playback_c_api_props_write(c_api, msg, object, data_size, data_offset);
BCMOS_RETURN_IF_ERROR(err);
break;
default:
break;
}
/* call API */
n = bcmolt_string_append(c_api, "\t"RC_REF" = bcmolt_%s_%s("DEVICE_REF", &"MSG_REF".hdr", group, call);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
if (msg->type == BCMOLT_MSG_TYPE_GET_MULTI)
{
n = bcmolt_string_append(
c_api,
", ("INVERT_FILTER_REF") ? BCMOLT_FILTER_FLAGS_INVERT_SELECTION : BCMOLT_FILTER_FLAGS_NONE, "MSG_SET_REF);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
else if (msg->group == BCMOLT_MGT_GROUP_STAT)
{
n = bcmolt_string_append(c_api, ", "STAT_FLAGS_REF);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
}
else
{
/* do nothing */
}
n = bcmolt_string_append(c_api, ");\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
n = bcmolt_string_append(c_api, "\tbcmos_printf(\"bcmolt_%s_%s returned %%s (%%d)\\n\", bcmos_strerror("RC_REF"), "RC_REF");\n", group, call);
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
n = bcmolt_string_append(c_api, "\t}\n\n");
BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
return BCM_ERR_OK;
}
static bcmos_errno playback_c_api_get(bcmolt_string* c_api, const bcmolt_msg* msg)
{
switch (msg->group)
{
case BCMOLT_MGT_GROUP_CFG:
switch (msg->type)
{
case BCMOLT_MSG_TYPE_GET:
return playback_c_api_code_get(c_api, msg, "get", PB_FIELDS_GET);
case BCMOLT_MSG_TYPE_GET_MULTI:
return playback_c_api_code_get(c_api, msg, "get_multi", PB_FIELDS_MULTI);
case BCMOLT_MSG_TYPE_SET:
return playback_c_api_code_get(c_api, msg, "set", PB_FIELDS_SET);
case BCMOLT_MSG_TYPE_CLEAR:
return playback_c_api_code_get(c_api, msg, "clear", PB_FIELDS_NONE);
default:
return BCM_ERR_INTERNAL;
}
break;
case BCMOLT_MGT_GROUP_STAT:
return playback_c_api_code_get(c_api, msg, "get", PB_FIELDS_GET);
case BCMOLT_MGT_GROUP_STAT_CFG:
switch (msg->type)
{
case BCMOLT_MSG_TYPE_GET:
return playback_c_api_code_get(c_api, msg, "get", PB_FIELDS_NONE);
case BCMOLT_MSG_TYPE_SET:
return playback_c_api_code_get(c_api, msg, "set", PB_FIELDS_SET);
default:
return BCM_ERR_INTERNAL;
}
break;
case BCMOLT_MGT_GROUP_AUTO_CFG:
switch (msg->type)
{
case BCMOLT_MSG_TYPE_GET:
return playback_c_api_code_get(c_api, msg, "get", PB_FIELDS_GET);
case BCMOLT_MSG_TYPE_SET:
return playback_c_api_code_get(c_api, msg, "set", PB_FIELDS_SET);
default:
return BCM_ERR_INTERNAL;
}
break;
case BCMOLT_MGT_GROUP_OPER:
return playback_c_api_code_get(c_api, msg, "submit", PB_FIELDS_SET);
case BCMOLT_MGT_GROUP_PROXY:
return playback_c_api_code_get(c_api, msg, "send", PB_FIELDS_SET);
default:
return BCM_ERR_INTERNAL;
}
}
static bcmos_errno playback_convert_c_api(bcmolt_playback *mpb, FILE *out_file)
{
playback_iterator it;
bcmos_errno err;
bcmolt_string *str;
uint32_t last_time_us = 0;
bcmos_bool first = BCMOS_TRUE;
err = bcmolt_string_create(&str, 16384);
BCMOS_RETURN_IF_ERROR(err);
fprintf(out_file, "void run_playback(void)\n{\n");
fprintf(out_file, "\tbcmolt_devid "DEVICE_REF" = %d;\n", current_device);
fprintf(out_file, "\tbcmos_errno "RC_REF" = BCM_ERR_OK;\n\n");
FOR_EACH_PLAYBACK_MSG(it, mpb->capture_buffer, mpb->buf_size)
{
if (playback_should_send(mpb->location, (bcmtr_cld_event_type)it.raw.hdr.event))
{
if (BCM_ERR_OK == it.err)
{
if (!first)
{
/* approximate original timing; doesn't account for processing time in this code - this could be
improved */
fprintf(out_file, "\n\tbcmos_usleep(%u);\n\n", it.raw.hdr.timestamp - last_time_us);
}
else
{
first = BCMOS_FALSE;
}
last_time_us = it.raw.hdr.timestamp;
bcmolt_string_reset(str);
err = playback_c_api_get(str, it.msg);
fwrite(bcmolt_string_get(str), sizeof(char), strlen(bcmolt_string_get(str)), out_file);
}
else
{
err = it.err;
BCM_LOG(ERROR, pb_ctxt[current_device].log_id, "Unpacking failed: %s\n", bcmos_strerror(err));
}
}
}
fprintf(out_file, "}\n");
bcmolt_string_destroy(str);
return err;
}
static bcmos_errno playback_convert(bcmolt_playback *mpb, pb_format format, FILE *out_file)
{
bcmos_errno err;
switch (format)
{
case PB_FORMAT_API_CLI:
err = playback_convert_api_cli(mpb, out_file);
break;
case PB_FORMAT_C_API:
err = playback_convert_c_api(mpb, out_file);
break;
default:
err = BCM_ERR_PARM;
BCM_LOG(ERROR, pb_ctxt[current_device].log_id, "Unknown format: %d\n", format);
break;
}
return err;
}
static bcmos_errno playback_cli_conv(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms)
{
const char *infilename = bcmcli_find_named_parm(session, "infile")->value.string;
const char *outfilename = bcmcli_find_named_parm(session, "outfile")->value.string;
pb_format format = (pb_format)bcmcli_find_named_parm(session, "format")->value.enum_val;
bcmos_bool ignore_ver = BCMOS_FALSE;
bcmos_errno err;
bcmolt_playback mpb = {};
FILE *out_file;
bcmcli_cmd_parm *iv_parm = bcmcli_find_named_parm(session, "ignore_version");
if (iv_parm != NULL)
{
ignore_ver = iv_parm->value.enum_val == (long)BCMOS_TRUE;
}
err = playback_file_open(infilename, &mpb);
if (BCM_ERR_OK == err)
{
if (playback_version_match(&mpb) || ignore_ver)
{
out_file = fopen(outfilename, "wb");
playback_convert(&mpb, format, out_file);
fclose(out_file);
}
else
{
bcmcli_print(session, "Possible version mismatch; use ignore_version=yes to force conversion\n");
err = BCM_ERR_IMAGE_TYPE;
}
bcmos_free(mpb.capture_buffer);
}
return err;
}
void bcmolt_user_appl_playback_cli_init(bcmcli_entry *top_dir)
{
#ifdef ENABLE_CLI
bcmcli_entry *plb_dir = bcmcli_dir_add(top_dir, "playback", "playback", BCMCLI_ACCESS_ADMIN, NULL);
BUG_ON(NULL == plb_dir);
static bcmcli_enum_val format_enum_table[PB_FORMAT__COUNT+1] =
{
{.name = "api_cli", .val = (long)PB_FORMAT_API_CLI},
{.name = "c_api", .val = (long)PB_FORMAT_C_API},
BCMCLI_ENUM_LAST
};
BCMCLI_MAKE_CMD_NOPARM(plb_dir, "dump", "dump capture", playback_cli_dump);
BCMCLI_MAKE_CMD(plb_dir, "save", "save capture", playback_cli_save,
BCMCLI_MAKE_PARM("file", "filename", BCMCLI_PARM_STRING, BCMCLI_PARM_FLAG_NONE));
BCMCLI_MAKE_CMD(plb_dir, "replay", "replay capture", playback_cli_replay,
BCMCLI_MAKE_PARM("file", "filename", BCMCLI_PARM_STRING, BCMCLI_PARM_FLAG_NONE),
BCMCLI_MAKE_PARM_ENUM("ignore_version", "Ignore version mismatch", bcmcli_enum_bool_table, BCMCLI_PARM_FLAG_OPTIONAL));
BCMCLI_MAKE_CMD(plb_dir, "conv", "Convert capture", playback_cli_conv,
BCMCLI_MAKE_PARM("infile", "Input filename", BCMCLI_PARM_STRING, BCMCLI_PARM_FLAG_NONE),
BCMCLI_MAKE_PARM("outfile", "Output filename", BCMCLI_PARM_STRING, BCMCLI_PARM_FLAG_NONE),
BCMCLI_MAKE_PARM_ENUM("format", "Output format", format_enum_table, BCMCLI_PARM_FLAG_NONE),
BCMCLI_MAKE_PARM_ENUM("ignore_version", "Ignore version mismatch", bcmcli_enum_bool_table, BCMCLI_PARM_FLAG_OPTIONAL));
#endif
}
void bcmolt_user_appl_playback_init(void)
{
for (uint32_t i = 0; i < BCMTR_MAX_OLTS; i++)
{
char log_name[MAX_DEV_LOG_ID_NAME];
snprintf(log_name, sizeof(log_name)-1, "user_appl_playback_%u", i);
pb_ctxt[i].log_id = bcm_dev_log_id_register(log_name, DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
}
}