summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuodong Xu <guodong.xu@linaro.org>2012-06-12 10:26:41 +0800
committerGuodong Xu <guodong.xu@linaro.org>2012-06-12 10:26:41 +0800
commit8538b90627694bf4df9fca2350a28beee1f206a6 (patch)
treeda02eee7c74713667410940323d8ff247c522cce
parent05488cad0e381dc10f54d6d9909ab7eab30f262e (diff)
Add implementation of rm_chan send_msg config_chan
-rw-r--r--Makefile15
-rw-r--r--fileop.c16
-rw-r--r--main.c928
-rw-r--r--test_commands.h46
4 files changed, 932 insertions, 73 deletions
diff --git a/Makefile b/Makefile
index 1ec6fe0..5ce81b0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,15 +1,22 @@
+ifeq ($(CROSS_COMPILE), )
+extra_flags = -DLOCAL_TEST_STUB
+endif
+
+extra_flags += -Wall
+
+CC = $(CROSS_COMPILE)gcc
all: stm_test
stm_test: main.o fileop.o
- gcc -o $@ $^
+ $(CC) $(extra_flags) -o $@ $^
fileop.o: fileop.c
- gcc -c $<
+ $(CC) $(extra_flags) -c $<
main.o: main.c test_commands.h
- gcc -c $<
+ $(CC) $(extra_flags) -c $<
clean:
rm -rf *.o
- rm stm_test
+ rm -rf stm_test
diff --git a/fileop.c b/fileop.c
index 52e5b6d..4cab8a3 100644
--- a/fileop.c
+++ b/fileop.c
@@ -51,13 +51,13 @@ int search_file(const char* path, const char* name)
struct dirent* dir_entry;
char current_filename[MAX_FILEPATH_LENGTH];
- TDBG("Enter %s. name=%s; path=%s\n", __FUNCTION__, name, path);
+ TDBG("In %s(), to search for filename=%s in directory=%s\n", __FUNCTION__, name, path);
if ((directory = opendir(path)) == NULL) {
printf("Error opendir(%s)\n", path);
return -1;
}
- while (dir_entry = readdir(directory)) {
+ while ((dir_entry = readdir(directory))) { /* readdir() returns NULL on reaching the end */
TDBG("dir_entry->d_name is \"%s\"\n", dir_entry->d_name);
/* To check wether this is a directory */
if (!strcmp(dir_entry->d_name, ".") ||
@@ -104,3 +104,15 @@ int search_file(const char* path, const char* name)
/* no findings */
return 0;
}
+
+/* to check existence of a file
+ * Input:
+ * - path: file path to be checked
+ * Return:
+ * - 0: yes, exist
+ * - -1: no such file
+ */
+int check_file_exist(const char* path)
+{
+ return access(path, F_OK);
+}
diff --git a/main.c b/main.c
index da59887..fc7d58e 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,7 @@
-/* Test application of STM Framework and driver
+/* ------------------------------------------------------------------
+ * Test application of STM Framework and driver
*
- */
+ * -----------------------------------------------------------------*/
#include <stdio.h>
#include <stdbool.h>
@@ -14,14 +15,25 @@
#include "test_commands.h"
/* global const */
-#define LOCAL_TEST_STUB
#ifdef LOCAL_TEST_STUB
const char* DEBUGFS_STM = "./debug_stm/";
#else
const char* DEBUGFS_STM = "/sys/kernel/debug/stm/";
#endif
+const char* STR_COMMAND_RESULT_DELIMITER = "#########\n";
-pthread_mutex_t mux;
+/* Following are delimiters used when parsing returned information from STM framework/drivers
+ * NOTE:
+ * - these delimiters are set in STM framework/drivers. When they are changed there,
+ * please change in this program accordingly, manually!
+ */
+const char* DELIMITER_STM_CHAN_NO = "STM channel";
+const char* DELIMITER_CHANNEL_FORMAT = "Channel format";
+const char* DELIMITER_TRANSMIT_BYTE_COUNT = "Transmit Byte Count";
+
+/*
+ * pthread_mutex_t mux;
+ */
command_list stm_test_command_list[] = {
{
@@ -39,11 +51,79 @@ command_list stm_test_command_list[] = {
false,
stm_info_sync_verify,
NULL,
- }
+ },
+ {
+ "chan_info",
+ stm_channel_info,
+ true,
+ false,
+ stm_channel_info_sync_verify,
+ NULL,
+ },
+ {
+ "send_msg",
+ stm_send_msg,
+ true,
+ false,
+ stm_send_msg_sync_verify,
+ NULL,
+ },
+ {
+ "rm_chan",
+ stm_remove_channel,
+ true,
+ false,
+ stm_remove_channel_sync_verify,
+ NULL,
+ },
+ {
+ "config_chan",
+ stm_config_channel,
+ false,
+ false,
+ NULL,
+ NULL,
+ },
+};
+
+/* enum config_id, and char* config_cmds[] are copied from
+ * STM framework in linux kernel, drivers/stm/stm_fw.c
+ * They are, as read-only, checked against to confirm a channel
+ * config command is valid or not.
+ */
+enum config_id {
+ CFGID_CHN_ENABLE,
+ CFGID_CHN_DISABLE,
+ CFGID_PROTECTED,
+ CFGID_UNPROTECTED,
+ CFGID_FMT_USER,
+ CFGID_FMT_VENDOR,
+ CFGID_FMT_RAW,
+ CFGID_SET_HEADER,
+ CFGID_TIMESTAMP_ENABLE,
+ CFGID_TIMESTAMP_DISABLE,
+ CFGID_CHECKSUM_ENABLE,
+ CFGID_CHECKSUM_DISABLE,
+ CFGID_LAST
+};
+
+static char *config_cmds[] = {
+ [CFGID_CHN_ENABLE] = "chn_enable",
+ [CFGID_CHN_DISABLE] = "chn_disable",
+ [CFGID_PROTECTED] = "protected",
+ [CFGID_UNPROTECTED] = "unprotected",
+ [CFGID_FMT_USER] = "fmt_user",
+ [CFGID_FMT_VENDOR] = "fmt_vendor",
+ [CFGID_FMT_RAW] = "fmt_raw",
+ [CFGID_SET_HEADER] = "set_header",
+ [CFGID_TIMESTAMP_ENABLE] = "timestamp_enable",
+ [CFGID_TIMESTAMP_DISABLE] = "timestamp_disable",
+ [CFGID_CHECKSUM_ENABLE] = "checksum_enable",
+ [CFGID_CHECKSUM_DISABLE] = "checksum_disable"
};
/* to check and return command index of stm_test_command_list[]
- * Input:
+stm_channel_config * Input:
* - command_name: null terminated string of STM test command_name
* Return:
* - 0 or positive: index of command_name
@@ -70,11 +150,304 @@ int check_command_index(const char* command_name)
return index;
}
+/* to check a config command is valid or not
+ * Input:
+ * - command: pointer to the command
+ * Return:
+ * - -1: invalid
+ * - 0 or positive: valid, and the returned value is also
+ * the command's index in config_cmds[]
+ */
+int validate_channel_config_command(const char* command)
+{
+ int ret = -1;
+ enum config_id cfg_id;
+ int cfg_len;
+
+ /* Check buf against list of supported commands (config_cmds) */
+ for (cfg_id = CFGID_CHN_ENABLE; cfg_id < CFGID_LAST; cfg_id++) {
+ cfg_len = strlen(config_cmds[cfg_id]);
+ if (!strncmp(command, config_cmds[cfg_id], cfg_len))
+ break;
+ }
+
+ if (cfg_id == CFGID_LAST)
+ ret = -1;
+ else
+ ret = (int)cfg_id;
+
+ return ret;
+}
+
+/* to print help message
+ * Input:
+ * - void
+ * Return:
+ * - 0: success
+ */
+int print_help(void)
+{
+ int index = -1;
+ int total_commands = 0;
+
+ total_commands = (int) (sizeof(stm_test_command_list)/sizeof(command_list));
+
+ printf("The following commands are supported:\n");
+ for(index = 0; index < total_commands; index ++) {
+ printf("%s\n", stm_test_command_list[index].command_name);
+ }
+
+ return 0;
+}
+
+/* to send a command to STM request
+ * Input:
+ * - command: the command to be sent
+ * Return:
+ * - 0: success
+ * - negartive value: error
+ */
+int send_request(const char* command)
+{
+ int ret = -1;
+ char request_filename[MAX_CONFIG_NAME_LENGTH] = "";
+ FILE* fp = NULL;
+
+ TDBG("In %s()\n", __FUNCTION__);
+
+ /* compose the request filename */
+ ret = snprintf(request_filename, MAX_CONFIG_NAME_LENGTH, "%srequest", DEBUGFS_STM);
+ if (ret >= MAX_CONFIG_NAME_LENGTH) {
+ TDBG("STM request fileanme is longer than %d byte in length. Which should not happen.\n", MAX_CONFIG_NAME_LENGTH);
+ return -1;
+ }
+
+ /* open STM request file for appending */
+ fp = fopen(request_filename, "ab");
+ if (fp == NULL) {
+ printf("Error: failed to open STM request file.\n");
+ return -1;
+ }
+
+ /* write to STM request
+ * NOTE: + 1 means the trailing null character
+ */
+ ret = fwrite(command, sizeof(unsigned char), strlen(command) + 1, fp);
+
+ if(ret < strlen(command) + 1) { /* message is not written in its complete */
+ printf("Error: message is not completely written into request file.\n");
+ printf("Total expected: %d, Total written: %d.\n", (int)strlen(command) + 1, ret);
+ /* clear resources */
+ fclose(fp);
+ return -1;
+ }
+ TDBG("%d bytes is sent to request\n", ret);
+
+ /* close channel file */
+ fclose(fp);
+
+ return 0;
+}
+
+/* to read channel information from <debugfs>/stm/<channel_name>_config
+ * Input:
+ * - chan_name: name of the channel
+ * Output:
+ * - ptr_command_result: command result, where private_data is used to store channel information
+ * Return:
+ * - 0: success
+ * - -1: failure
+ */
+int read_channel_config(const char* chan_name, command_result_type* ptr_command_result)
+{
+ int ret = -1;
+ char channel_config_filename[MAX_CONFIG_NAME_LENGTH] = "";
+ unsigned char* stm_channel_information;
+ FILE* fd;
+
+ /* validation of input parameters */
+ if ((strlen(chan_name) == 0) || (ptr_command_result == NULL)) {
+ printf("Error: invalid input parameters in %s.\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* compose the filename */
+ ret = snprintf(channel_config_filename, MAX_CONFIG_NAME_LENGTH, "%s%s_config", DEBUGFS_STM, chan_name);
+ TDBG("channel_config_filename is: %s\n", channel_config_filename);
+
+ if (ret >= MAX_CONFIG_NAME_LENGTH) {
+ printf("channel_config_fileanme is longer than %d byte in length. Which should not happen.\n", MAX_CONFIG_NAME_LENGTH);
+ return -1;
+ }
+
+ /* allocate memory for file reading */
+ stm_channel_information = (unsigned char *)malloc(MAX_SIZE_STM_REQUEST);
+ if (stm_channel_information == NULL) {
+ printf("Memory allocation error in func: %s\n", __FUNCTION__);
+ return -1;
+ }
+
+ memset(stm_channel_information, '\0', MAX_SIZE_STM_REQUEST);
+
+ /* open config file */
+ fd = fopen(channel_config_filename, "rb");
+ if (fd == NULL) {
+ printf("Failed to open channel config file: %s.\n", channel_config_filename);
+ /* in case of error, clear resources */
+ free(stm_channel_information);
+ return -1;
+ }
+
+ /* read file contents */
+ ret = fread(stm_channel_information, sizeof(unsigned char), MAX_SIZE_STM_REQUEST, fd);
+ TDBG("STM channel config file: %s, file length: %d bytes\n", channel_config_filename, ret);
+
+ if (!feof(fd)) {
+ printf("STM request reading returns more than %d bytes. Need to modify the source code to fix this.\n", MAX_SIZE_STM_REQUEST);
+ /* in case of error, clear resources */
+ fclose(fd);
+ free(stm_channel_information);
+ return -1;
+ }
+
+ /* close file */
+ fclose(fd);
+
+ /* for debugging purpose only, dump file contents */
+ TDBG("Dump of channel_config file: %s\n", channel_config_filename);
+ {
+ int i;
+ unsigned char* c;
+ for(i = 0, c = stm_channel_information; i < ret; i ++, c ++) {
+ TDBG("%c", *c);
+ }
+ TDBG("\n");
+ }
+
+ /* link the memory space to private_data */
+ ptr_command_result->private_data = stm_channel_information;
+ ptr_command_result->command_execution_result = COMMAND_EXEC_SUCCESS;
+ return 0;
+}
+
+/* to write a command into <debugfs>/stm/<channel_name>_config
+ * Input:
+ * - chan_name: name of the channel
+ * - command: pointer to command string
+ * Return:
+ * - 0: success
+ * - -1: failure
+ */
+int write_channel_config(const char* chan_name, const char* command)
+{
+ int ret = -1;
+ char channel_config_filename[MAX_CONFIG_NAME_LENGTH] = "";
+ FILE* fd = NULL;
+
+ /* validation of input parameters */
+ if ((strlen(chan_name) == 0) || (strlen(command) == 0)) {
+ printf("Error: invalid input parameters in %s.\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* compose the filename */
+ ret = snprintf(channel_config_filename, MAX_CONFIG_NAME_LENGTH, "%s%s_config", DEBUGFS_STM, chan_name);
+ TDBG("channel_config_filename is: %s\n", channel_config_filename);
+
+ if (ret >= MAX_CONFIG_NAME_LENGTH) {
+ printf("channel_config_fileanme is longer than %d byte in length. Which should not happen.\n", MAX_CONFIG_NAME_LENGTH);
+ return -1;
+ }
+
+ /* check config file exist or not */
+ if (check_file_exist(channel_config_filename) == -1) {
+ printf("Error: channel config file, %s, doesn't exist.\n", channel_config_filename);
+ return -1;
+ }
+
+ /* open config file */
+ fd = fopen(channel_config_filename, "ab");
+
+ if (fd == NULL) {
+ printf("Failed to open channel config file: %s.\n", channel_config_filename);
+ /* in case of error, clear resources */
+ return -1;
+ }
+
+ /* write to file */
+ /* Note: + 1 means to write the trailing null character */
+ ret = fwrite(command, sizeof(char), strlen(command) + 1, fd);
+ if(ret < (strlen(command) + 1)) { /* message is not written in its complete */
+ printf("Error: message is not completely written into channel.\n");
+ printf("Channel config filename: %s\n", channel_config_filename);
+ printf("Total expected: %d, Total actual written: %d.\n", (int)strlen(command) + 1, ret);
+ /* clear resources */
+ fclose(fd);
+ return -1;
+ }
+ TDBG("command: \"%s\", total %d bytes is sent to channel config.\n", command, ret);
+
+ /* close file */
+ fclose(fd);
+
+ return 0;
+}
+
+/* to parse an integer from a string, which follows a leading delimiter string
+ * Input:
+ * - information: the string to be searched in
+ * - delimiter: the leading string before the target integer
+ * Output:
+ * - val: the target integer
+ * Return:
+ * - 0: success
+ * - -1: failure
+ */
+int parse_integer_with_delimiter_string(const char* information, const char* delimiter, int* val)
+{
+ char* ptr_integer = NULL;
+
+ /* to locate the searched string */
+ ptr_integer = strstr(information, delimiter);
+
+ if (ptr_integer == NULL) { /* in case of error */
+ *val = -1;
+ return -1;
+ }
+
+ ptr_integer += strlen(delimiter);
+ *val = atoi(ptr_integer);
+
+ return 0;
+}
+
+/* to parse transmit byte count from channel information
+ * Input:
+ * - channel_information: channel information as read from channel's config file
+ * Output:
+ * - count: transmit byte count
+ * Return:
+ * - 0: success
+ * - -1: failure
+ */
+int parse_transmit_byte_count(const char* channel_information, int* count)
+{
+ int ret = -1;
+
+ ret = parse_integer_with_delimiter_string(channel_information, DELIMITER_TRANSMIT_BYTE_COUNT, count);
+ TDBG("Tansmit Byte Count, as parsed in %s(): %d\n", __FUNCTION__, *count);
+
+ return ret;
+}
+
/* to create one STM channel
* Input:
* - param_num: total number of parameters, incl. command_name, in param_array
* - param_array: an char string array to host all parameters, w/ command_name
* being the first.
+ * SYNOPSIS: create_chan CHANNEL_NAME
+ * Output:
+ * - ptr_command_result: command result
* Return:
* - 0: success
* - negartive value: error
@@ -82,7 +455,7 @@ int check_command_index(const char* command_name)
int stm_create_channel(int param_num, char** param_array, command_result_type* ptr_command_result)
{
int ret = -1;
- char shell_command[MAX_SHELL_COMMAND_LINE_SIZE];
+ char command_buf[MAX_SHELL_COMMAND_LINE_SIZE] = "";
TDBG("In %s()\n", __FUNCTION__);
@@ -92,51 +465,30 @@ int stm_create_channel(int param_num, char** param_array, command_result_type* p
return ret;
}
- /* compose a shell command */
- ret = snprintf(shell_command, MAX_SHELL_COMMAND_LINE_SIZE,
- "echo -n \"user %s\\0\" > %srequest", param_array[1], DEBUGFS_STM);
- if( ret >= MAX_SHELL_COMMAND_LINE_SIZE ) {
- /* a return value of size or more means that the output
- * was truncated. */
- TDBG("Command line too long. %d\n", ret);
- printf("Command line too long. Try to use shorter strings.\n");
- return -ret;
+ /* compose command buffer */
+ ret = snprintf(command_buf, MAX_SHELL_COMMAND_LINE_SIZE, "user %s", *(param_array + 1));
+ if (ret >= MAX_SHELL_COMMAND_LINE_SIZE) {
+ TDBG("STM command length is too long. Maximum allowed in this test program is %d bytes.\n", MAX_SHELL_COMMAND_LINE_SIZE);
+ return -1;
}
+ TDBG("command to be sent to request: %s\n", command_buf);
- /* send this command to shell */
- ret = system(shell_command);
- TDBG("system(\"%s\") returns %d, RAW ret = 0x%x\n", shell_command, WEXITSTATUS(ret), ret);
- if( ret == -1 ) {
- printf("system() returns error %d.", ret);
- return ret;
- }
- switch( WEXITSTATUS(ret) ) {
- case 0:
- ptr_command_result->command_execution_result = COMMAND_EXEC_SUCCESS;
- break;
- case 2:
-
- /* TODO
- * more checks about error conditions
- *
- * 2 means: sh: cannot create /sys/kernel/debug/stm/request: Permission denied system(echo -n -e "user xx" > /sys/kernel/debug/stm/request) returns 2.
- */
- ptr_command_result->command_execution_result = COMMAND_EXEC_FAILURE;
- break;
- default:
- ptr_command_result->command_execution_result = COMMAND_EXEC_FAILURE;
- break;
+ ret = send_request(command_buf);
+
+ if (ret == 0) {
+ ptr_command_result->command_execution_result = COMMAND_EXEC_SUCCESS;
}
- return WEXITSTATUS(ret);
+ return ret; /* carry back return value from send_request() */
}
-
/* to verify the creation of one STM channel
* Input:
* - param_num: total number of parameters, incl. command_name, in param_array
* - param_array: an char string array to host all parameters, w/ command_name
* being the first.
+ * Output:
+ * - ptr_command_result: command result
* Return:
* - 0: success
* - -1: only <channel_name>, no <channel_name>_config;
@@ -194,6 +546,9 @@ verify_result:
* - param_num: total number of parameters, incl. command_name, in param_array
* - param_array: an char string array to host all parameters, w/ command_name
* being the first.
+ * SYNOPSIS: info
+ * Output:
+ * - ptr_command_result: command result
* Return:
* - 0: success
* - -1: failure
@@ -204,7 +559,12 @@ int stm_info(int param_num, char** param_array, command_result_type* ptr_command
char request_filename[MAX_CONFIG_NAME_LENGTH] = "";
unsigned char* stm_information;
FILE* fd;
- int offset = 0;
+
+ /* check validity of input parameters */
+ if(param_num != 1) {
+ TDBG("Invalid parameter numbers in %s.\n", __FUNCTION__);
+ return ret;
+ }
/* compose the filename */
ret = snprintf(request_filename, MAX_CONFIG_NAME_LENGTH, "%srequest", DEBUGFS_STM);
@@ -213,9 +573,6 @@ int stm_info(int param_num, char** param_array, command_result_type* ptr_command
return -1;
}
- /* open <debugfs>/request */
- fd = fopen(request_filename, "rb");
-
/* allocate memory for file reading */
stm_information = (unsigned char *)malloc(MAX_SIZE_STM_REQUEST);
if (stm_information == NULL) {
@@ -224,15 +581,24 @@ int stm_info(int param_num, char** param_array, command_result_type* ptr_command
}
memset(stm_information, '\0', MAX_SIZE_STM_REQUEST);
+ /* open <debugfs>/request */
+ fd = fopen(request_filename, "rb");
+
/* read file contents */
ret = fread(stm_information, sizeof(unsigned char), MAX_SIZE_STM_REQUEST, fd);
TDBG("STM request %s file length: %d byte\n", request_filename, ret);
if (!feof(fd)) {
printf("STM request reading returns more than %d bytes. Need to modify the source code to fix this.\n", MAX_SIZE_STM_REQUEST);
+ /* in case of error, clear resources */
+ fclose(fd);
+ free(stm_information);
return -1;
}
+ /* close file */
+ fclose(fd);
+
/* for debugging purpose only, dump file contents */
TDBG("Dump of STM request file:\n");
{
@@ -246,20 +612,457 @@ int stm_info(int param_num, char** param_array, command_result_type* ptr_command
/* link the memory space to private_data */
ptr_command_result->private_data = stm_information;
+ ptr_command_result->command_execution_result = COMMAND_EXEC_SUCCESS;
+ return 0;
+}
+
+/* to verify information read from <debugfs>/stm/request
+ * Input:
+ * - param_num: total number of parameters, incl. command_name, in param_array
+ * - param_array: an char string array to host all parameters, w/ command_name
+ * being the first.
+ * Output:
+ * - ptr_command_result: command result
+ * Return:
+ * - 0: success
+ * - -1: failure
+ */
+int stm_info_sync_verify(int param_num, char** param_array, command_result_type* ptr_command_result)
+{
+ /* TODO: parse request file reading result */
+ /* simple check, whether the returned bytes are more than 0. */
+ if(strlen(ptr_command_result->private_data) > 0) {
+ ptr_command_result->sync_veri_result = SYNC_VERIFICATION_SUCCESS;
+ } else {
+ ptr_command_result->sync_veri_result = SYNC_VERIFICATION_FAILURE;
+ }
+ TDBG("inside of %s()\n", __FUNCTION__);
+ return 0;
+}
+
+/* to get channel information by reading <debugfs>/stm/<channel_name>_config
+ * Input:
+ * - param_num: total number of parameters, incl. command_name, in param_array
+ * - param_array: an char string array to host all parameters, w/ command_name
+ * being the first.
+ * SYNOPSIS: chan_info CHANNEL_NAME
+ * Output:
+ * - ptr_command_result: command result
+ * Return:
+ * - 0: success
+ * - -1: failure
+ */
+int stm_channel_info(int param_num, char** param_array, command_result_type* ptr_command_result)
+{
+ int ret = -1;
+
+ /* parameter validation */
+ if(param_num != 2) {
+ printf("Error: invalid no. of parameters in %s\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* to read channel's config file, and the result is stored in private_data
+ * of ptr_command_result */
+ ret = read_channel_config(*(param_array + 1), ptr_command_result);
+
+ return ret;
+}
+
+/* to verify information read from <debugfs>/stm/<channel_name>_config
+ * Input:
+ * - param_num: total number of parameters, incl. command_name, in param_array
+ * - param_array: an char string array to host all parameters, w/ command_name
+ * being the first.
+ * Output:
+ * - ptr_command_result: command result
+ * Return:
+ * - 0: success
+ * - -1: failure
+ */
+int stm_channel_info_sync_verify(int param_num, char** param_array, command_result_type* ptr_command_result)
+{
+ /* TODO: parse channel_config file reading result */
+ /* simple check, whether the returned bytes are more than 0. */
+ if(strlen(ptr_command_result->private_data) > 0) {
+ ptr_command_result->sync_veri_result = SYNC_VERIFICATION_SUCCESS;
+ } else {
+ ptr_command_result->sync_veri_result = SYNC_VERIFICATION_FAILURE;
+ }
+ TDBG("inside of %s()\n", __FUNCTION__);
return 0;
}
-int stm_info_sync_verify()
+/* to send a message to a user channel
+ * Input:
+ * - param_num: total number of parameters, incl. command_name, in param_array
+ * - param_array: an char string array to host all parameters, w/ command_name
+ * being the first.
+ * SYNOPSIS: send_msg CHANNEL_NAME MESSAGE
+ * Output:
+ * - ptr_command_result: command result
+ * Return:
+ * - 0: success
+ * - negartive value: error
+ */
+int stm_send_msg(int param_num, char** param_array, command_result_type* ptr_command_result)
+{
+ int ret = -1;
+ private_send_msg* ptr_private_send_msg = NULL;
+ char channel_filename[MAX_CHANNEL_NAME_LENGTH];
+ FILE* fp;
+ command_result_type tmp_command_result;
+
+ TDBG("In %s()\n", __FUNCTION__);
+
+ /* check validity of input parameters */
+ if(param_num != 3) {
+ TDBG("Invalid number of parameters in %s.\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* allocate private_send_msg */
+ ptr_private_send_msg = malloc((size_t)sizeof(private_send_msg));
+ if (ptr_private_send_msg == NULL) { /* allocation failure */
+ printf("Error: private_send_msg memory allocation failure, in %s.\n", __FUNCTION__);
+ return -1;
+ }
+ /* initialize to 0 */
+ ptr_private_send_msg->prev_tx_count = 0;
+ ptr_private_send_msg->new_tx_count = 0;
+ /* hook it to ptr_command_result */
+ ptr_command_result->private_data = ptr_private_send_msg;
+
+ /* read channel's transmit byte count, for later verification purpose */
+ INIT_COMMAND_RESULT(&tmp_command_result);
+ ret = read_channel_config(*(param_array + 1), &tmp_command_result);
+ /* parse transmit byte count */
+ if (ret == 0) /* when channel config is read correctly */
+ ret = parse_transmit_byte_count(tmp_command_result.private_data, &ptr_private_send_msg->prev_tx_count);
+ FREE_COMMAND_RESULT(&tmp_command_result);
+
+ /* compose channel_filename */
+ ret = snprintf(channel_filename, MAX_CHANNEL_NAME_LENGTH,
+ "%s%s", DEBUGFS_STM, param_array[1]);
+ if(ret >= MAX_CHANNEL_NAME_LENGTH) {
+ /* a return value of size or more means that the output
+ * was truncated. */
+ TDBG("Channel filename too long. %d\n", ret);
+ printf("Channel flename too long. Double check please.\n");
+ return -ret;
+ }
+ TDBG("channel_filename is %s\n", channel_filename);
+
+ /* open the channel file for appending */
+ fp = fopen(channel_filename, "ab");
+ if(fp == NULL) { /* failure */
+ printf("channel file open error, %s.\n", channel_filename);
+ return -1;
+ }
+
+ /* write the message to channel file
+ * Note: + 1 means the trailing null character is also sent to channel
+ */
+ ret = fwrite(param_array[2], sizeof(char), strlen(param_array[2]) + 1, fp);
+ if(ret < strlen(param_array[2]) + 1) { /* message is not written in its complete */
+ printf("Error: message is not completely written into channel.\n");
+ printf("Channel filename: %s\n", channel_filename);
+ printf("Total expected: %d, Total written: %d.\n", (int)strlen(param_array[2]) + 1, ret);
+ /* clear resources */
+ fclose(fp);
+ return -1;
+ }
+ TDBG("%d bytes is sent to channel.\n", ret);
+
+ /* close channel file */
+ fclose(fp);
+
+ /* set command execution result */
+ ptr_command_result->command_execution_result = COMMAND_EXEC_SUCCESS;
+
+ return 0;
+}
+
+/* to verify message is sent to a user channel
+ * Input:
+ * - param_num: total number of parameters, incl. command_name, in param_array
+ * - param_array: an char string array to host all parameters, w/ command_name
+ * being the first.
+ * SYNOPSIS: send_msg CHANNEL_NAME MESSAGE
+ * Output:
+ * - ptr_command_result: command result
+ * Return:
+ * - 0: success
+ * - negartive value: error
+ */
+int stm_send_msg_sync_verify(int param_num, char** param_array, command_result_type* ptr_command_result)
{
+ int ret = -1;
+ int sent_bytes = 0;
+ int msg_length = 0;
+ command_result_type tmp_command_result;
+ private_send_msg* ptr_private_send_msg = (private_send_msg*) ptr_command_result->private_data;
+
+ INIT_COMMAND_RESULT(&tmp_command_result);
+
+ /* read channel's transmit byte count, for verification purpose */
+ ret = read_channel_config(*(param_array + 1), &tmp_command_result);
+ /* parse transmit byte count */
+ if (ret == 0) /* when channel config is read correctly */
+ ret = parse_transmit_byte_count(tmp_command_result.private_data,
+ &ptr_private_send_msg->new_tx_count);
+
+ FREE_COMMAND_RESULT(&tmp_command_result);
+
+ /* comparing with previous value */
+ sent_bytes = ptr_private_send_msg->new_tx_count -
+ ptr_private_send_msg->prev_tx_count;
+
+ msg_length = strlen(*(param_array + 2)) + 1; /* + 1, because trailing null character is sent in stm_send_msg() */
+
+ if (sent_bytes == msg_length) {
+ ptr_command_result->sync_veri_result = SYNC_VERIFICATION_SUCCESS;
+ }
+
return 0;
}
+/* to remove one STM channel
+ * Input:
+ * - param_num: total number of parameters, incl. command_name, in param_array
+ * - param_array: an char string array to host all parameters, w/ command_name
+ * being the first.
+ * SYNOPSIS: rm_chan CHANNEL_NAME
+ * Output:
+ * - ptr_command_result: command result
+ * Return:
+ * - 0: success
+ * - negartive value: error
+ */
+int stm_remove_channel(int param_num, char ** param_array, command_result_type* ptr_command_result)
+{
+ int ret = -1;
+ char command_buf[MAX_SHELL_COMMAND_LINE_SIZE] = "";
+
+ TDBG("In %s()\n", __FUNCTION__);
+
+ /* check validity of input parameters */
+ if(param_num != 2) {
+ TDBG("Invalid parameter numbers in %s.\n", __FUNCTION__);
+ return ret;
+ }
+
+ /* compose command buffer */
+ ret = snprintf(command_buf, MAX_SHELL_COMMAND_LINE_SIZE, "rm %s", *(param_array + 1));
+ if (ret >= MAX_SHELL_COMMAND_LINE_SIZE) {
+ TDBG("STM command length is too long. Maximum allowed in this test program is %d bytes.\n", MAX_SHELL_COMMAND_LINE_SIZE);
+ return -1;
+ }
+ TDBG("command to be sent to request: %s\n", command_buf);
+
+ ret = send_request(command_buf);
+
+ if (ret == 0) {
+ ptr_command_result->command_execution_result = COMMAND_EXEC_SUCCESS;
+ }
+
+ return ret; /* carry back return value from send_request() */
+}
+
+/* to verify the removal of one STM channel
+ * Input:
+ * - param_num: total number of parameters, incl. command_name, in param_array
+ * - param_array: an char string array to host all parameters, w/ command_name
+ * being the first.
+ * Output:
+ * - ptr_command_result: command result
+ * Return:
+ * - 0: success, both <channel_name> and <channel_name>_config are removed.
+ * - -1: only <channel_name> is removed; not <channel_name>_config;
+ * - -2: only <channel_name>_config is removed; not <channel_name>;
+ * - -3: neither of <channel_name> and <channel_name>_config are removed;
+ * - negartive value: error, other
+ */
+int stm_remove_channel_sync_verify(int param_num, char ** param_array, command_result_type* ptr_command_result)
+{
+ int ret = -1;
+ bool removed_channel_name = false;
+ bool removed_channel_config = false;
+ char channel_config_name[MAX_CONFIG_NAME_LENGTH];
+ char* channel_name = param_array[1];
+
+ TDBG("In %s: channel_name is %s.\n", __FUNCTION__, channel_name);
+
+ /* set verification result as failure */
+ ptr_command_result->sync_veri_result = SYNC_VERIFICATION_FAILURE;
+
+ /* to check two new nodes under stm/: <channel_name> and <channel_name>_config */
+ if (search_file(DEBUGFS_STM, channel_name) == 0)
+ removed_channel_name = true;
+
+ ret = snprintf(channel_config_name, MAX_CONFIG_NAME_LENGTH, "%s_config", channel_name);
+ /* check if truncated */
+ if (ret >= MAX_CONFIG_NAME_LENGTH ) {
+ printf("config file name exceeds maximum allowed length %d. %s.",
+ MAX_CONFIG_NAME_LENGTH, channel_name);
+ goto verify_result;
+ }
+ if (search_file(DEBUGFS_STM, channel_config_name) == 0)
+ removed_channel_config = true;
+
+verify_result:
+ if (removed_channel_name) {
+ if (removed_channel_config) {
+ ptr_command_result->sync_veri_result = SYNC_VERIFICATION_SUCCESS;
+ return 0;
+ }
+ else
+ return -1;
+ } else {
+ if (removed_channel_config)
+ return -2;
+ else
+ return -3;
+ }
+
+ return -4; /* should never been here*/
+}
+
+/* to log command and test result into stdout.
+ * Input:
+ * - ptr_command_result: pointer to command result to be logged.
+ * Return:
+ * - 0: success
+ * - -1: failure
+ */
+int result_logging(const command_result_type *ptr_command_result)
+{
+ int ret = -1;
+ FILE* fp_logging = stdout; /* using stdout as default */
+
+ if(ptr_command_result == NULL) { /* invalid input */
+ TDBG("Invalid input parameter in %s().\n", __FUNCTION__);
+ return ret;
+ }
+
+ /* print delimiter */
+ fprintf(fp_logging, "%s", STR_COMMAND_RESULT_DELIMITER);
+
+ /* print command_name */
+ fprintf(fp_logging, "command_name: %s\n", ptr_command_result->current_command->command_name);
+ /* print command sequencial id and execution result */
+ fprintf(fp_logging, "sequencial_id: %d\n", ptr_command_result->sequencial_id);
+ switch(ptr_command_result->command_execution_result) {
+ case COMMAND_EXEC_SUCCESS:
+ fprintf(fp_logging, "command_execution_result: %s\n", "SUCCESS");
+ break;
+ case COMMAND_EXEC_FAILURE:
+ fprintf(fp_logging, "command_execution_result: %s\n", "FAILURE");
+ break;
+ default:
+ TDBG("Invalid command_execution_result. Please check.\n");
+ break;
+ }
+ /* print command in sync verification result, if applicable */
+ if(ptr_command_result->current_command->is_sync) {
+ switch(ptr_command_result->sync_veri_result) {
+ case SYNC_VERIFICATION_SUCCESS:
+ fprintf(fp_logging, "sync_veri_result: %s\n", "SUCCESS");
+ break;
+ case SYNC_VERIFICATION_FAILURE:
+ fprintf(fp_logging, "sync_veri_result: %s\n", "FAILURE");
+ break;
+ default:
+ TDBG("Invalid sync_veri_result. Please check.\n");
+ break;
+ }
+ } else {
+ fprintf(fp_logging, "sync_veri_result: N/A\n");
+ }
+ /* print command in sync verification result, if applicable */
+ if(ptr_command_result->current_command->is_async) {
+ switch(ptr_command_result->async_veri_result) {
+ case ASYNC_VERIFICATION_SUCCESS:
+ fprintf(fp_logging, "async_veri_result: %s\n", "SUCCESS");
+ break;
+ case ASYNC_VERIFICATION_FAILURE:
+ fprintf(fp_logging, "async_veri_result: %s\n", "FAILURE");
+ break;
+ default:
+ TDBG("Invalid async_veri_result. Please check.\n");
+ break;
+ }
+ } else {
+ fprintf(fp_logging, "async_veri_result: N/A\n");
+ }
+#if 0
+ /* print private data */
+ /* CAUSION:
+ * 1. private_data is not always printable. Eg. in send_msg
+ * 2. private_data can be NULL. Eg. in create_chan
+ * 3. private_data may not be a null terminated string.
+ */
+ fprintf(fp_logging, "private_data: \n");
+ fprintf(fp_logging, "____Begin of private_data____\n");
+ fprintf(fp_logging, "%s\n", (char *)ptr_command_result->private_data);
+ fprintf(fp_logging, "____End of private_data____\n");
+#endif
+
+ /* flush */
+ fflush(fp_logging);
+
+ ret = 0;
+ return ret;
+}
+
+/* to send command to channel's config file
+ * Input:
+ * - param_num: total number of parameters, incl. command_name, in param_array
+ * - param_array: an char string array to host all parameters, w/ command_name
+ * being the first.
+ * SYNOPSIS: config_chan CHANNEL_NAME COMMAND
+ * Output:
+ * - ptr_command_result: command result
+ * Return:
+ * - 0: success
+ * - negartive value: error
+ */
+int stm_config_channel(int param_num, char ** param_array, command_result_type* ptr_command_result)
+{
+ int ret = -1;
+
+ TDBG("In %s()\n", __FUNCTION__);
+
+ /* check validity of input parameters */
+ if(param_num != 3) {
+ TDBG("Invalid parameter numbers in %s.\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* check the config command is a valid one */
+ ret = validate_channel_config_command(*(param_array + 2));
+ if (ret == -1) { /* invalid channel config command */
+ TDBG("Invalid channel config command. %s\n", *(param_array + 2));
+ return ret;
+ }
+
+ TDBG("channel name: %s\n", *(param_array + 1));
+ TDBG("command to be sent to channel config: %s\n", *(param_array + 2));
+
+ ret = write_channel_config(*(param_array + 1), *(param_array + 2));
+
+ if (ret == 0) {
+ ptr_command_result->command_execution_result = COMMAND_EXEC_SUCCESS;
+ }
+
+ return ret; /* carry back return value from send_request() */
+}
+
static int command_sequencial_count = 0; /* to record total number of commands executed */
int main(int argc, char** argv)
{
- int ret = 0;
- bool succ = true;
+ int ret = -1;
int cmd_index = -1;
command_list* current_command = NULL;
command_result_type current_command_result;
@@ -273,9 +1076,11 @@ int main(int argc, char** argv)
/* check command line information */
if (argc == 1) {
- TDBG("Test commands come from standard input.\n");
+ print_help(); /* print help information */
+ TDBG("\n or \nTest commands come from standard input.\n");
/* read test commands from standard input */
/* TODO */
+ TDBG("Do nothing. \n");
return ret;
}
@@ -296,31 +1101,34 @@ int main(int argc, char** argv)
/* increase the global command seq count by 1 */
command_sequencial_count ++;
- /* make and send shell command */
+ /* send command to STM Framework/driver */
(* current_command->command_consumer_callback)(argc - 1, argv + 1, &current_command_result);
+ /* TODO
+ * in case of command execution error, should verification be canclled?
+ */
/* to call sync_verification API if proper */
- if (current_command->is_sync == true && current_command->sync_verification_callback != NULL) {
+ if (current_command_result.command_execution_result == COMMAND_EXEC_SUCCESS &&
+ current_command->is_sync == true &&
+ current_command->sync_verification_callback != NULL) {
TDBG("to call sync_verification API.\n");
- (* current_command->sync_verification_callback)(argc - 1, argv +1, &current_command_result);
+ (* current_command->sync_verification_callback)(argc - 1, argv + 1, &current_command_result);
}
/* to call async_verification API if proper */
- if (current_command->is_async == true && current_command->async_verification_callback != NULL) {
+ if (current_command_result.command_execution_result == COMMAND_EXEC_SUCCESS &&
+ current_command->is_async == true &&
+ current_command->async_verification_callback != NULL) {
TDBG("to call async_verification API.\n");
(* current_command->async_verification_callback)();
}
/* to record the command result */
- /* TODO */
+ result_logging(&current_command_result);
/* to free memory before exit */
- /* TODO */
- if (current_command_result.private_data != NULL) {
- /* TODO: double check here. what if the private_data is not one single block allocated by malloc? should we define a command specific private_data freeing API? */
- free(current_command_result.private_data);
- }
+ FREE_COMMAND_RESULT(&current_command_result);
- return ret;
+ return 0;
}
diff --git a/test_commands.h b/test_commands.h
index e7498d0..8de3d3a 100644
--- a/test_commands.h
+++ b/test_commands.h
@@ -19,16 +19,12 @@
#define MAX_COMMAND_NAME_LENGTH (16)
#define MAX_SHELL_COMMAND_LINE_SIZE (100)
#define MAX_CONFIG_NAME_LENGTH (100)
+#define MAX_CHANNEL_NAME_LENGTH MAX_CONFIG_NAME_LENGTH
#define MAX_SIZE_STM_REQUEST (4096) /* maximum 4k for a read of <debugfs>/stm/request
* should be enough, and is double checked in code
* as well. */
-
-/* external functions */
-extern int stm_create_channel();
-extern int stm_create_channel_sync_verify();
-extern int stm_info();
-extern int stm_info_sync_verify();
-extern int search_file(const char* path, const char* name);
+ /* Note: this value is also used as maximum size for
+ * <debugfs>/stm/<channel_name>_config */
typedef struct command_list {
char command_name[MAX_COMMAND_NAME_LENGTH];
@@ -46,8 +42,18 @@ typedef struct command_result_type {
int sync_veri_result; /* this is result returned by sync verificaiton callback */
int async_veri_result; /* this is result returned by async verification callback */
void* private_data; /* this is private data, which is meaningful to specific command */
+ /* Two assumptions about private_data:
+ * 1). It is one single block allocated by malloc, can be free()'ed;
+ * 2). It is one NULL terminated string, can be printf("%s")'ed;
+ */
} command_result_type;
+/* private_data for send_msg */
+typedef struct private_send_msg {
+ int prev_tx_count; /* channel's tx byte count, before sending this message */
+ int new_tx_count; /* channel's tx byte count, after sending this message */
+} private_send_msg;
+
#define COMMAND_EXEC_SUCCESS (0)
#define COMMAND_EXEC_FAILURE (-1)
#define VERIFICATION_FAILURE (-100)
@@ -66,7 +72,33 @@ static inline void INIT_COMMAND_RESULT(command_result_type *ptr_command_result)
ptr_command_result->sync_veri_result = SYNC_VERIFICATION_FAILURE;
ptr_command_result->async_veri_result = ASYNC_VERIFICATION_FAILURE;
ptr_command_result->private_data = NULL;
+ return;
}
+static inline void FREE_COMMAND_RESULT(command_result_type *ptr_command_result)
+{
+ if (ptr_command_result->private_data != NULL) {
+ /* TODO: double check here. what if the private_data is not one single block
+ * allocated by malloc? should we define a command specific private_data freeing API?
+ */
+ free(ptr_command_result->private_data);
+ }
+ return;
+}
+
+/* external functions */
+extern int stm_create_channel(int param_num, char ** param_array, command_result_type* ptr_command_result);
+extern int stm_create_channel_sync_verify(int param_num, char ** param_array, command_result_type* ptr_command_result);
+extern int stm_info(int param_num, char ** param_array, command_result_type* ptr_command_result);
+extern int stm_info_sync_verify(int param_num, char ** param_array, command_result_type* ptr_command_result);
+extern int stm_channel_info(int param_num, char ** param_array, command_result_type* ptr_command_result);
+extern int stm_channel_info_sync_verify(int param_num, char ** param_array, command_result_type* ptr_command_result);
+extern int stm_send_msg(int param_num, char ** param_array, command_result_type* ptr_command_result);
+extern int stm_send_msg_sync_verify(int param_num, char ** param_array, command_result_type* ptr_command_result);
+extern int stm_remove_channel(int param_num, char ** param_array, command_result_type* ptr_command_result);
+extern int stm_remove_channel_sync_verify(int param_num, char ** param_array, command_result_type* ptr_command_result);
+extern int stm_config_channel(int param_num, char ** param_array, command_result_type* ptr_command_result);
+extern int search_file(const char* path, const char* name);
+extern int check_file_exist(const char* path);
#endif /* STM_TEST_COMMANDS_H */