diff options
author | Guodong Xu <guodong.xu@linaro.org> | 2012-06-12 10:26:41 +0800 |
---|---|---|
committer | Guodong Xu <guodong.xu@linaro.org> | 2012-06-12 10:26:41 +0800 |
commit | 8538b90627694bf4df9fca2350a28beee1f206a6 (patch) | |
tree | da02eee7c74713667410940323d8ff247c522cce | |
parent | 05488cad0e381dc10f54d6d9909ab7eab30f262e (diff) |
Add implementation of rm_chan send_msg config_chan
-rw-r--r-- | Makefile | 15 | ||||
-rw-r--r-- | fileop.c | 16 | ||||
-rw-r--r-- | main.c | 928 | ||||
-rw-r--r-- | test_commands.h | 46 |
4 files changed, 932 insertions, 73 deletions
@@ -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 @@ -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); +} @@ -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, ¤t_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, ¤t_command_result); + (* current_command->sync_verification_callback)(argc - 1, argv + 1, ¤t_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(¤t_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(¤t_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 */ |