/****************************************************************************** * File name : distributor.c * Title : REPORT PACKAGE - Message Distributor * Date created : 01 SEP, 1996 * Revision : 1.0 * Author : Zvika Zilberman * * Description : Report distributor provides the duplicating of * messages to the several destinations. * ****************************************************************************** * * Procedures: * * ReportFd - Add or remove file descriptor to/from the * list of destinations * ReportFunc - Add or remove funtion to/from the list of * destnations * ReportEnableAll - Resume the work of distributor * * Functions, internal for Report: * * distibutorInit - Initialize message distributor * reportDistribute - Send message to destibutor * * Local functions: * * messageDistribute - Forward message to all destinations. * reportService - Distibutor Task main function * ****************************************************************************** * * History: * 01.09.96 Ilia Maller - start of coding * 21.02.97 Ilia Maller - minor improvements * 17.09.97 Zvika Zilberman - porting to DCME SWINFRA * ******************************************************************************/ /*------------- Includes --------------------------------*/ #include "include.h" #include "report.h" #include "filter.h" #include "distributor.h" /*------------- Local Definitions -----------------------*/ #define SEVERITY_MASK(severity) ((severity) & 0x10) #define REPORT_ROOT_NAME "system" #define REPORT_TASK_STACK_SIZE 1024 typedef struct { FormatType format; char *message; char *FileName; int LineNumber; int errorCode; ErrorSeverity severity; int parameter1; int parameter2; }INPUT_MESSAGE; #define INPUT_MESSAGE_LEN sizeof(INPUT_MESSAGE) ReportFunction ReportFunc1 = NULL; ReportFunction ReportFunc2 = NULL; typedef struct { int fd; ReportFunction function; }DESTINATION; #define DESTINATION_SIZE sizeof(DESTINATION) #define NUM_OF_DESTINATIONS 2 typedef struct { char name[11]; bool IsActive; /* false - discard its messages. true - send them. */ bool IsAlive; /* false - if not in action, can not be used or seen */ DESTINATION dest[NUM_OF_DESTINATIONS]; } DistributorElement; static void messageDistribute(char *msg, int DistTableEntry, char *FileName, int LineNumber, int errorCode, int parameter1, int parameter2); /*static STATUS reportFormat(char *buffer, int *maxlen, const char *message, int errorCode, ErrorSeverity severity, int parameter1, int parameter2);*/ static int FindFreeDestinationElement(int DistTableEntry); /*------------- Local Data ------------------------------*/ static Mailbox_Handle inputQueue; /* Table where output of distributor (destinations) stored Every element of the table may be or file descriptor or function address. The destinations stored unsorted */ static DistributorElement *Dist_Table; static int DistCounter; /* number of current elements in the table */ static int NumOfDistributions; /*************************************************************************** * * Name : distibutorInit * * Function : Initialize message distributor * * Notes : Function uses malloc for memory allocation * * Parameters: priority - distributor task priority * maxMsgs - maximum number of messages stored in * destributor task queue * maxDstr - maximum number of distributors * * Return value: STATUS - OK or ERROR **************************************************************************/ STATUS distibutorInit( int priority, int maxMsgs, int maxDstr ) { static int initialized = false; int i, j; if (initialized) return OK; NumOfDistributions = maxDstr; /* create mailbox to recive messages */ inputQueue = Mailbox_create(INPUT_MESSAGE_LEN,maxMsgs, 0,0); if (inputQueue == NULL) return ERROR; /* create table for destionations. malloc takes care about allignment */ Dist_Table = (DistributorElement *)malloc(sizeof(DistributorElement)*(maxDstr+1)); if (Dist_Table == NULL) return ERROR; /* initialize table */ for (i=0; i<=maxDstr; i++) { for (j=0; j 0) { if (Dist_Table[Distributor].IsAlive == false) return OK; if (Dist_Table[Distributor].IsActive == false) return OK; } else if (Dist_Table[0].IsActive == false) return OK; /* truncate if message length greater than defined */ msg.format = format; msg.message = message; msg.FileName = FileName; msg.LineNumber = LineNumber; msg.errorCode = errorCode; msg.severity = severity; msg.parameter1 = parameter1; msg.parameter2 = parameter2; if (inputQueue != NULL) Mailbox_post(inputQueue , &msg, BIOS_NO_WAIT); return OK; } /*************************************************************************** * * Name : reportService * * Function : Distibutor Task main function * * Notes : * * Return value: void **************************************************************************/ Void reportService(UArg arg0, UArg arg1) { INPUT_MESSAGE msg; //static char buf[REPORT_MAX_MSG_LEN + REPORT_MSG_FORMAT_LEN]; int DistTableEntry;//,msgLen, errCode, par1, par2; ReportInitParams InitParams; InitParams.DistributorQueueMaxMsgs = 60; InitParams.DistributorTaskPriority = 6; InitParams.MaxNumOfFilterNames = 30; InitParams.MaxNumberOfPrivateDistributors = 2; ReportInit (InitParams); while(1) { Mailbox_pend(inputQueue , &msg, BIOS_WAIT_FOREVER); DistTableEntry = (SEVERITY_MASK(msg.severity) == RpPrivate) ? (msg.severity >> 5) : 0; // /* format received string */ // /*if (msg.format == REPORT_FORMAT) // { // msgLen = REPORT_MAX_MSG_LEN + REPORT_MSG_FORMAT_LEN; // reportFormat(buf, &msgLen, msg.message, msg.errorCode, // msg.severity, msg.parameter1, msg.parameter2); // errCode = msg.errorCode; // par1 = msg.parameter1; // par2 = msg.parameter2; // } // else /* MESSAGE_FORMAT - regular message */ // { // msgLen = strlen(msg.message); // if (msgLen > REPORT_MAX_MSG_LEN-1) // msgLen = REPORT_MAX_MSG_LEN-1; // strcpy(buf,msg.message); // errCode = 0; // par1 = 0; // par2 = 0; // }*/ /* send message to subscribers */ messageDistribute( msg.message, DistTableEntry,msg.FileName, msg.LineNumber,msg.errorCode,msg.severity,msg.parameter1); } } /*----------------------------------------------------------------------------*/ /*----------------------------- Private Severity -----------------------------*/ /*----------------------------------------------------------------------------*/ /*************************************************************************** * * Name : ReportDistributor * * Function : Add static distributor * * Notes : The name is given in order to note the severity name * during the report exception. * * Parameters: distributorName - The severity's name must be up to 10 * letters long. * SwitchAddRemove - REPORT_ADD to add the new static severity, * REPORT_REMOVE to remove it. * * Return value: the new distributor handle, or -1 and thus: * errno = REPORT_ERROR_NAME_TOO_LONG in case of long name, * errno = REPORT_ERROR_NAME_ALREADY_DISABLE if the distributor * was already removed, * errno = REPORT_ERROR_NAME_NOT_EXISTS if the distributorName * not exists, * errno = REPORT_ERROR_TABLE_FULL if there are already too * many distributors, * errno = REPORT_ERROR_NAME_EXISTS if the distributorName * already exists. **************************************************************************/ DistributorHandle ReportDistributor(const char *distributorName, uint32_t SwitchAddRemove) { int index; if ((DistCounter > NumOfDistributions) && (SwitchAddRemove == REPORT_ADD)) { errno = REPORT_ERROR_TABLE_FULL; return -1; } if (strlen(distributorName) > 10) { errno = REPORT_ERROR_NAME_TOO_LONG; return -1; } else if ((strcmp(distributorName,"system")==0) || ((strcmp(distributorName,"SYSTEM")==0))) { errno = REPORT_ERROR_NAME; return -1; } if (IsNameExistsInFiltersTable(distributorName)) { errno = REPORT_ERROR_NAME_EXISTS; return -1; } for (index=1; index DistCounter) || (Distributor < 0)) return ERROR; Dist_Table[Distributor].IsActive = (SwitchOnOff == REPORT_ON) ? true : false; return OK; } /*************************************************************************** * * Name : ReportGetDistributorHandleByName * * Function : Get the severity handle given the severity's name * * Notes : * * Return value: the handle; or -1 if no such name **************************************************************************/ DistributorHandle ReportGetDistributorHandleByName(const char *distributorName) { int index; for (index = 0; index <= DistCounter; index++) if (ReportStrCmp(distributorName,Dist_Table[index].name)) { if (Dist_Table[index].IsAlive) return index; else return -1; /* disable used */ } return -1; } /*************************************************************************** * * Name : GetDistributorParamsByHandle * * Function : Get the static severity details according to its handle * * Parameters : DistributorHandle - table entry * name - buffer to contain the static severity's name * IsActive - a reference to a boolean flag * * Notes : The name field must exceeds 10 bytes long * * Return value: OK or ERROR and then: * errno = REPORT_ERROR_ILLEGAL_PARAMETER if no such entry * errno = REPORT_ERROR_FILTER_NOT_ALIVE if the static * severity has already removed. **************************************************************************/ STATUS GetDistributorParamsByHandle(uint32_t DistributorHandle, char *name, bool *IsActive) { if (DistributorHandle >= DistCounter) { errno = REPORT_ERROR_ILLEGAL_PARAMETER; return ERROR; } if ((Dist_Table[DistributorHandle].IsAlive) == false) { errno = REPORT_ERROR_FILTER_NOT_ALIVE; return ERROR; } strcpy(name,Dist_Table[DistributorHandle].name); *IsActive = Dist_Table[DistributorHandle].IsActive; return OK; } /*************************************************************************** * * Name : ReportFd * * Function : Add or remove a file descriptor to/from the output distributor * * Notes : * * Parameters: fd - file descriptor. Supplied by the user * SwitchAddRemove - REPORT_ADD to add the fd * REPORT_REMOVE to remove it. * Distributor - 0 if not concerned with any static * severity, or the static severity's handle * to set with the given fd * * Return value: OK or ERROR with: * errno = REPORT_ERROR_NOT_ENOUGH_MEMORY if destination list * is full * errno = REPORT_ERROR_ILLEGAL_PARAMETER if (fd == -1) or * not found if asked to remove **************************************************************************/ STATUS ReportFd(int fd, uint32_t SwitchAddRemove, DistributorHandle Distributor) { int index = 0, i; if (SwitchAddRemove == REPORT_ADD) { index = FindFreeDestinationElement(Distributor); /* check for the table overflow */ if (index == -1) { errno = REPORT_ERROR_NOT_ENOUGH_MEMORY; return ERROR; } } /* consistency check: don't add illegal fd */ if (fd == -1) { errno = REPORT_ERROR_ILLEGAL_PARAMETER; return ERROR; } /* search for fd */ for( i = 0; i < NUM_OF_DESTINATIONS; i++ ) if ( Dist_Table[Distributor].dest[i].fd == fd ) break; if (i == NUM_OF_DESTINATIONS) { if (SwitchAddRemove == REPORT_REMOVE) { errno = REPORT_ERROR_CODE_NOT_FOUND; return ERROR; } /* Add fd */ /* add new destination to the end of the table */ Dist_Table[Distributor].dest[index].fd = fd; /* set the function to NULL to ensure that destination is nothing but fd */ Dist_Table[Distributor].dest[index].function = NULL; } else if (SwitchAddRemove == REPORT_ADD) return OK; /* this fd is already exists in the table */ else /* Remove fd */ Dist_Table[Distributor].dest[i].fd = -1; return OK; } /*************************************************************************** * * Name : ReportFunc * * Function : Add or remove an output routine to/from the distributor * * Notes : * * Parameters: func - hook to the routine. Supplied by the user . * SwitchAddRemove - REPORT_ADD to add the hook * REPORT_REMOVE to remove it. * Distributor - Set 0 if not concerned with any static * severity, or give the static severity's * handle to set with the given fd. * * Return value: OK or ERROR with: * errno = REPORT_ERROR_NOT_ENOUGH_MEMORY if destination list * is full * errno = REPORT_ERROR_ILLEGAL_PARAMETER if (func == NULL) **************************************************************************/ STATUS ReportFunc(ReportFunction func, uint32_t SwitchAddRemove, DistributorHandle Distributor) { //int index = 0, i; /* consistency check: don't add illegal pointer */ if( func == NULL ) { errno = REPORT_ERROR_ILLEGAL_PARAMETER; return ERROR; } if (SwitchAddRemove == REPORT_REMOVE) { if (ReportFunc1 == func) { ReportFunc1 = NULL; return OK; } if (ReportFunc2 == func) { ReportFunc2 = NULL; return OK; } errno = REPORT_ERROR_CODE_NOT_FOUND; return ERROR; } if (SwitchAddRemove == REPORT_ADD) { if ((func == ReportFunc1)||(func == ReportFunc2)) { REPORT_MSG (REPORT_ADD,"Report function already exist"); return OK; } if (ReportFunc1 == NULL) { ReportFunc1 = func; return OK; } if (ReportFunc2 == NULL) { ReportFunc2 = func; return OK; } errno = REPORT_ERROR_CODE_NOT_FOUND; return ERROR; } return OK; } /*************************************************************************** * * Name : ReportMessage2Dist * * Function : Report a message to the appropriate distributor * * Notes : The distributor handle should be passed using the macro * SET_PRIVATE_DISTRIBUTOR * * Return value: OK or ERROR if failed to send to distributor **************************************************************************/ STATUS ReportMessage2Dist(DistributorHandle distributor, const char *message) { return reportDistribute(MESSAGE_FORMAT, message,NULL, 0, 0, distributor, 0, 0); } /*************************************************************************** * * Name : ReportMonitorFunc * * Function : Add/remove an output routine that prints to the monitor * * Notes : Hiding Report messages from appearing on the monitor is * enable when the HALT> prompt is shown (by pressing ). * The filtering is done using an internal routine. * This routine can be added/removed using this call. * It can be added either to the regular distributor or to the * distributor of each of the static severities. * * Parameters: SwitchAddRemove - REPORT_ADD to add the routine * REPORT_REMOVE to remove it. * Distributor - Set 0 if not concerned with any static * severity, or give the static severity's * handle to set with it . * * Return value: void **************************************************************************/ /*void ReportMonitorFunc(uint32_t SwitchAddRemove, uint32_t Distributor) { switch (SwitchAddRemove) { case REPORT_ADD: ReportFunc(MonitorFuncRoutine, REPORT_ADD, Distributor); break; case REPORT_REMOVE: ReportFunc(MonitorFuncRoutine, REPORT_REMOVE, Distributor); break; } } */ /*------------- messageDistribute ------------------------*/ /* * Forward message to all destinations. * * Parameters: * void* msg - address of the message * int len - message length * * Returns: * None * */ char reportmsg[254]; static void messageDistribute(char *msg, int DistTableEntry, char *FileName, int LineNumber, int errorCode, int Severity, int parameter) { //int index; /* pass through the table and send message to destination. Assume for consistency: when the destination is fd, it should not be -1 and function must be NULL. If the destination is function, it's address must not be NULL and fd should be -1 */ /* for (index = 0; index < NUM_OF_DESTINATIONS; index++ ) { if (Dist_Table[DistTableEntry].dest[index].function != NULL) Dist_Table[DistTableEntry].dest[index].function(msg,FileName,LineNumber,errorCode,parameter1,parameter2); } */ strncpy (reportmsg,msg,250); reportmsg[251] = NULL; if (ReportFunc1 != NULL) ReportFunc1(reportmsg, FileName,LineNumber,errorCode,Severity, parameter); if (ReportFunc2 != NULL) ReportFunc2(reportmsg, FileName,LineNumber,errorCode,Severity, parameter); } /*------------- reportFormat --------------------------*/ /* * The function converts mesage with error type, code, etc. into string * with length using the following format (example): * "H/W Error #12,05,01: Bus error (0xffde,0x1234)" * * Parameters: * char* buffer - buffer to store the formatted message * int* maxlen - length of the buffer. If the estimated length * of the formatted message exceeds maxlen, * function returns ERROR, set errno to * REPORT_ERROR_NOT_ENOUGH_MEMORY and buffer left unchanged. * char* message - user message * UNIT16 extErrorType - error type and severity * ERRORCODE errorCode - error code * uint32_t32 parameter1 - user parameter 1 * uint32_t32 parameter2 - user parameter 2 * */ //STATUS reportFormat(char *buffer, // int *maxlen, // const char *message, // int errorCode, // ErrorSeverity severity, // int parameter1, // int parameter2) //{ // int DstrTableEntry; // char *name; // static char* severities[8] = {"Message","Warning","","Error","","","","Fatal error"}; // // /* Total message length w/o text is REPORT_MSG_FORMAT_LEN bytes */ // int msgLen = strlen(message) + REPORT_MSG_FORMAT_LEN; // // /* check if message fit the supplied buffer */ // if (*maxlen < msgLen) // { // errno = REPORT_ERROR_NOT_ENOUGH_MEMORY; // return ERROR; // } // /* Format message. // ATTENTION: DON'T forget to change REPORT_MSG_FORMAT_LEN // when changing the format string */ // if (SEVERITY_MASK(severity) == RpPrivate) // { // DstrTableEntry = (severity >> 5); // if (Dist_Table[DstrTableEntry].IsAlive == false) // { // errno = REPORT_ERROR_ILLEGAL_PARAMETER; // return ERROR; // } // name = Dist_Table[DstrTableEntry].name; // } // else // name = severities[severity-1]; // // *maxlen = sprintf(buffer,"%s: #%d: %s (0x%x,0x%x)\r\n",name,errorCode,message,parameter1,parameter2); // return OK; //} /*************************************************************************** * * Name : FindFreeDestinationElement * * Function : Find Free Destination Element. * * Notes : * * Return value: index if found , ERROR - otherwise **************************************************************************/ int FindFreeDestinationElement(int DistTableEntry) { int index; for (index=0; index