diff options
Diffstat (limited to 'Software/Embedded_SW/Embedded/Common')
22 files changed, 12149 insertions, 0 deletions
diff --git a/Software/Embedded_SW/Embedded/Common/Software_CRC/sw_crc.c b/Software/Embedded_SW/Embedded/Common/Software_CRC/sw_crc.c new file mode 100644 index 000000000..76f9c0398 --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/Software_CRC/sw_crc.c @@ -0,0 +1,723 @@ + +//***************************************************************************** +// +//! \addtogroup sw_crc_api +//! @{ +// +//***************************************************************************** +#include "Common/Software_CRC/sw_crc.h" + +//***************************************************************************** +// +// The CRC table for the polynomial C(x) = x^8 + x^2 + x + 1 (CRC-8-CCITT). +// +//***************************************************************************** +static const uint8_t g_pui8Crc8CCITT[256] = +{ + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, + 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, + 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, + 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, + 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, + 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, + 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, + 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, + 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, + 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, + 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, + 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, + 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, + 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, + 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, + 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, + 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, + 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, + 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, + 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, + 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, + 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, + 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 +}; + +//***************************************************************************** +// +// The CRC-16 table for the polynomial C(x) = x^16 + x^15 + x^2 + 1 (standard +// CRC-16, also known as CRC-16-IBM and CRC-16-ANSI). +// +//***************************************************************************** +static const uint16_t g_pui16Crc16[256] = +{ + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 +}; + +//***************************************************************************** +// +// The CRC-32 table for the polynomial C(x) = x^32 + x^26 + x^23 + x^22 + +// x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1 (standard +// CRC32 as used in Ethernet, MPEG-2, PNG, etc.). +// +//***************************************************************************** +static const uint32_t g_pui32Crc32[] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +}; + +//***************************************************************************** +// +// This macro executes one iteration of the CRC-8-CCITT. +// +//***************************************************************************** +#define CRC8_ITER(crc, data) g_pui8Crc8CCITT[(uint8_t)((crc) ^ (data))] + +//***************************************************************************** +// +// This macro executes one iteration of the CRC-16. +// +//***************************************************************************** +#define CRC16_ITER(crc, data) (((crc) >> 8) ^ \ + g_pui16Crc16[(uint8_t)((crc) ^ (data))]) + +//***************************************************************************** +// +// This macro executes one iteration of the CRC-32. +// +//***************************************************************************** +#define CRC32_ITER(crc, data) (((crc) >> 8) ^ \ + g_pui32Crc32[(uint8_t)((crc & 0xFF) ^ \ + (data))]) + +//***************************************************************************** +// +//! Calculates the CRC-8-CCITT of an array of bytes. +//! +//! \param ui8Crc is the starting CRC-8-CCITT value. +//! \param pui8Data is a pointer to the data buffer. +//! \param ui32Count is the number of bytes in the data buffer. +//! +//! This function is used to calculate the CRC-8-CCITT of the input buffer. +//! The CRC-8-CCITT is computed in a running fashion, meaning that the entire +//! data block that is to have its CRC-8-CCITT computed does not need to be +//! supplied all at once. If the input buffer contains the entire block of +//! data, then \b ui8Crc should be set to 0. If, however, the entire block of +//! data is not available, then \b ui8Crc should be set to 0 for the first +//! portion of the data, and then the returned value should be passed back in +//! as \b ui8Crc for the next portion of the data. +//! +//! For example, to compute the CRC-8-CCITT of a block that has been split into +//! three pieces, use the following: +//! +//! \verbatim +//! ui8Crc = Crc8CCITT(0, pui8Data1, ui32Len1); +//! ui8Crc = Crc8CCITT(ui8Crc, pui8Data2, ui32Len2); +//! ui8Crc = Crc8CCITT(ui8Crc, pui8Data3, ui32Len3); +//! \endverbatim +//! +//! Computing a CRC-8-CCITT in a running fashion is useful in cases where the +//! data is arriving via a serial link (for example) and is therefore not all +//! available at one time. +//! +//! \return The CRC-8-CCITT of the input data. +// +//***************************************************************************** +uint8_t +Crc8CCITT(uint8_t ui8Crc, const uint8_t *pui8Data, uint32_t ui32Count) +{ + uint32_t ui32Temp; + + // + // If the data buffer is not 16 bit-aligned, then perform a single step of + // the CRC to make it 16 bit-aligned. + // + if((uint32_t)pui8Data & 1) + { + // + // Perform the CRC on this input byte. + // + ui8Crc = CRC8_ITER(ui8Crc, *pui8Data); + + // + // Skip this input byte. + // + pui8Data++; + ui32Count--; + } + + // + // If the data buffer is not word-aligned and there are at least two bytes + // of data left, then perform two steps of the CRC to make it word-aligned. + // + if(((uint32_t)pui8Data & 2) && (ui32Count > 1)) + { + // + // Read the next 16 bits. + // + ui32Temp = *(uint16_t *)pui8Data; + + // + // Perform the CRC on these two bytes. + // + ui8Crc = CRC8_ITER(ui8Crc, ui32Temp); + ui8Crc = CRC8_ITER(ui8Crc, ui32Temp >> 8); + + // + // Skip these input bytes. + // + pui8Data += 2; + ui32Count -= 2; + } + + // + // While there is at least a word remaining in the data buffer, perform + // four steps of the CRC to consume a word. + // + while(ui32Count > 3) + { + // + // Read the next word. + // + ui32Temp = *(uint32_t *)pui8Data; + + // + // Perform the CRC on these four bytes. + // + ui8Crc = CRC8_ITER(ui8Crc, ui32Temp); + ui8Crc = CRC8_ITER(ui8Crc, ui32Temp >> 8); + ui8Crc = CRC8_ITER(ui8Crc, ui32Temp >> 16); + ui8Crc = CRC8_ITER(ui8Crc, ui32Temp >> 24); + + // + // Skip these input bytes. + // + pui8Data += 4; + ui32Count -= 4; + } + + // + // If there are 16 bits left in the input buffer, then perform two steps of + // the CRC. + // + if(ui32Count > 1) + { + // + // Read the 16 bits. + // + ui32Temp = *(uint16_t *)pui8Data; + + // + // Perform the CRC on these two bytes. + // + ui8Crc = CRC8_ITER(ui8Crc, ui32Temp); + ui8Crc = CRC8_ITER(ui8Crc, ui32Temp >> 8); + + // + // Skip these input bytes. + // + pui8Data += 2; + ui32Count -= 2; + } + + // + // If there is a final byte remaining in the input buffer, then perform a + // single step of the CRC. + // + if(ui32Count != 0) + { + ui8Crc = CRC8_ITER(ui8Crc, *pui8Data); + } + + // + // Return the resulting CRC-8-CCITT value. + // + return(ui8Crc); +} + +//***************************************************************************** +// +//! Calculates the CRC-16 of an array of bytes. +//! +//! \param ui16Crc is the starting CRC-16 value. +//! \param pui8Data is a pointer to the data buffer. +//! \param ui32Count is the number of bytes in the data buffer. +//! +//! This function is used to calculate the CRC-16 of the input buffer. The +//! CRC-16 is computed in a running fashion, meaning that the entire data block +//! that is to have its CRC-16 computed does not need to be supplied all at +//! once. If the input buffer contains the entire block of data, then +//! \b ui16Crc should be set to 0. If, however, the entire block of data is +//! not available, then \b ui16Crc should be set to 0 for the first portion of +//! the data, and then the returned value should be passed back in as +//! \b ui16Crc for the next portion of the data. +//! +//! For example, to compute the CRC-16 of a block that has been split into +//! three pieces, use the following: +//! +//! \verbatim +//! ui16Crc = Crc16(0, pui8Data1, ui32Len1); +//! ui16Crc = Crc16(ui16Crc, pui8Data2, ui32Len2); +//! ui16Crc = Crc16(ui16Crc, pui8Data3, ui32Len3); +//! \endverbatim +//! +//! Computing a CRC-16 in a running fashion is useful in cases where the data +//! is arriving via a serial link (for example) and is therefore not all +//! available at one time. +//! +//! \return The CRC-16 of the input data. +// +//***************************************************************************** +uint16_t +Crc16(uint16_t ui16Crc, const uint8_t *pui8Data, uint32_t ui32Count) +{ + uint32_t ui32Temp; + + // + // If the data buffer is not 16 bit-aligned, then perform a single step of + // the CRC to make it 16 bit-aligned. + // + if((uint32_t)pui8Data & 1) + { + // + // Perform the CRC on this input byte. + // + ui16Crc = CRC16_ITER(ui16Crc, *pui8Data); + + // + // Skip this input byte. + // + pui8Data++; + ui32Count--; + } + + // + // If the data buffer is not word-aligned and there are at least two bytes + // of data left, then perform two steps of the CRC to make it word-aligned. + // + if(((uint32_t)pui8Data & 2) && (ui32Count > 1)) + { + // + // Read the next 16 bits. + // + ui32Temp = *(uint16_t *)pui8Data; + + // + // Perform the CRC on these two bytes. + // + ui16Crc = CRC16_ITER(ui16Crc, ui32Temp); + ui16Crc = CRC16_ITER(ui16Crc, ui32Temp >> 8); + + // + // Skip these input bytes. + // + pui8Data += 2; + ui32Count -= 2; + } + + // + // While there is at least a word remaining in the data buffer, perform + // four steps of the CRC to consume a word. + // + while(ui32Count > 3) + { + // + // Read the next word. + // + ui32Temp = *(uint32_t *)pui8Data; + + // + // Perform the CRC on these four bytes. + // + ui16Crc = CRC16_ITER(ui16Crc, ui32Temp); + ui16Crc = CRC16_ITER(ui16Crc, ui32Temp >> 8); + ui16Crc = CRC16_ITER(ui16Crc, ui32Temp >> 16); + ui16Crc = CRC16_ITER(ui16Crc, ui32Temp >> 24); + + // + // Skip these input bytes. + // + pui8Data += 4; + ui32Count -= 4; + } + + // + // If there are two bytes left in the input buffer, then perform two steps + // of the CRC. + // + if(ui32Count > 1) + { + // + // Read the two bytes. + // + ui32Temp = *(uint16_t *)pui8Data; + + // + // Perform the CRC on these two bytes. + // + ui16Crc = CRC16_ITER(ui16Crc, ui32Temp); + ui16Crc = CRC16_ITER(ui16Crc, ui32Temp >> 8); + + // + // Skip these input bytes. + // + pui8Data += 2; + ui32Count -= 2; + } + + // + // If there is a final byte remaining in the input buffer, then perform a + // single step of the CRC. + // + if(ui32Count != 0) + { + ui16Crc = CRC16_ITER(ui16Crc, *pui8Data); + } + + // + // Return the resulting CRC-16 value. + // + return(ui16Crc); +} + +//***************************************************************************** +// +//! Calculates the CRC-16 of an array of words. +//! +//! \param ui32WordLen is the length of the array in words (the number of bytes +//! divided by 4). +//! \param pui32Data is a pointer to the data buffer. +//! +//! This function is a wrapper around the running CRC-16 function, providing +//! the CRC-16 for a single block of data. +//! +//! \return The CRC-16 of the input data. +// +//***************************************************************************** +uint16_t +Crc16Array(uint32_t ui32WordLen, const uint32_t *pui32Data) +{ + // + // Calculate and return the CRC-16 of this array of words. + // + return(Crc16(0, (const uint8_t *)pui32Data, ui32WordLen * 4)); +} + +//***************************************************************************** +// +//! Calculates three CRC-16s of an array of words. +//! +//! \param ui32WordLen is the length of the array in words (the number of bytes +//! divided by 4). +//! \param pui32Data is a pointer to the data buffer. +//! \param pui16Crc3 is a pointer to an array in which to place the three +//! CRC-16 values. +//! +//! This function is used to calculate three CRC-16s of the input buffer; the +//! first uses every byte from the array, the second uses only the even-index +//! bytes from the array (in other words, bytes 0, 2, 4, etc.), and the third +//! uses only the odd-index bytes from the array (in other words, bytes 1, 3, +//! 5, etc.). +//! +//! \return None +// +//***************************************************************************** +void +Crc16Array3(uint32_t ui32WordLen, const uint32_t *pui32Data, + uint16_t *pui16Crc3) +{ + uint16_t ui16Crc, ui16Cri8Odd, ui16Cri8Even; + + // + // Initialize the CRC values to zero. + // + ui16Crc = 0; + ui16Cri8Odd = 0; + ui16Cri8Even = 0; + + // + // Loop while there are more words in the data buffer. + // + while(ui32WordLen--) + { + // + // Read the next word. + // + uint32_t ui32Temp = *pui32Data++; + + // + // Perform the first CRC on all four data bytes. + // + ui16Crc = CRC16_ITER(ui16Crc, ui32Temp); + ui16Crc = CRC16_ITER(ui16Crc, ui32Temp >> 8); + ui16Crc = CRC16_ITER(ui16Crc, ui32Temp >> 16); + ui16Crc = CRC16_ITER(ui16Crc, ui32Temp >> 24); + + // + // Perform the second CRC on only the even-index data bytes. + // + ui16Cri8Even = CRC16_ITER(ui16Cri8Even, ui32Temp); + ui16Cri8Even = CRC16_ITER(ui16Cri8Even, ui32Temp >> 16); + + // + // Perform the third CRC on only the odd-index data bytes. + // + ui16Cri8Odd = CRC16_ITER(ui16Cri8Odd, ui32Temp >> 8); + ui16Cri8Odd = CRC16_ITER(ui16Cri8Odd, ui32Temp >> 24); + } + + // + // Return the resulting CRC-16 values. + // + pui16Crc3[0] = ui16Crc; + pui16Crc3[1] = ui16Cri8Even; + pui16Crc3[2] = ui16Cri8Odd; +} + +//***************************************************************************** +// +//! Calculates the CRC-32 of an array of bytes. +//! +//! \param ui32Crc is the starting CRC-32 value. +//! \param pui8Data is a pointer to the data buffer. +//! \param ui32Count is the number of bytes in the data buffer. +//! +//! This function is used to calculate the CRC-32 of the input buffer. The +//! CRC-32 is computed in a running fashion, meaning that the entire data block +//! that is to have its CRC-32 computed does not need to be supplied all at +//! once. If the input buffer contains the entire block of data, then +//! \b ui32Crc should be set to 0xFFFFFFFF. If, however, the entire block of +//! data is not available, then \b ui32Crc should be set to 0xFFFFFFFF for the +//! first portion of the data, and then the returned value should be passed +//! back in as \b ui32Crc for the next portion of the data. Once all data has +//! been passed to the function, the final CRC-32 can be obtained by inverting +//! the last returned value. +//! +//! For example, to compute the CRC-32 of a block that has been split into +//! three pieces, use the following: +//! +//! \verbatim +//! ui32Crc = Crc32(0xFFFFFFFF, pui8Data1, ui32Len1); +//! ui32Crc = Crc32(ui32Crc, pui8Data2, ui32Len2); +//! ui32Crc = Crc32(ui32Crc, pui8Data3, ui32Len3); +//! ui32Crc ^= 0xFFFFFFFF; +//! \endverbatim +//! +//! Computing a CRC-32 in a running fashion is useful in cases where the data +//! is arriving via a serial link (for example) and is therefore not all +//! available at one time. +//! +//! \return The accumulated CRC-32 of the input data. +// +//***************************************************************************** +uint32_t +Crc32(uint32_t ui32Crc, const uint8_t *pui8Data, uint32_t ui32Count) +{ + uint32_t ui32Temp; + + // + // If the data buffer is not 16 bit-aligned, then perform a single step + // of the CRC to make it 16 bit-aligned. + // + if((uint32_t)pui8Data & 1) + { + // + // Perform the CRC on this input byte. + // + ui32Crc = CRC32_ITER(ui32Crc, *pui8Data); + + // + // Skip this input byte. + // + pui8Data++; + ui32Count--; + } + + // + // If the data buffer is not word-aligned and there are at least two bytes + // of data left, then perform two steps of the CRC to make it word-aligned. + // + if(((uint32_t)pui8Data & 2) && (ui32Count > 1)) + { + // + // Read the next int16_t. + // + ui32Temp = *(uint16_t *)pui8Data; + + // + // Perform the CRC on these two bytes. + // + ui32Crc = CRC32_ITER(ui32Crc, ui32Temp); + ui32Crc = CRC32_ITER(ui32Crc, ui32Temp >> 8); + + // + // Skip these input bytes. + // + pui8Data += 2; + ui32Count -= 2; + } + + // + // While there is at least a word remaining in the data buffer, perform + // four steps of the CRC to consume a word. + // + while(ui32Count > 3) + { + // + // Read the next word. + // + ui32Temp = *(uint32_t *)pui8Data; + + // + // Perform the CRC on these four bytes. + // + ui32Crc = CRC32_ITER(ui32Crc, ui32Temp); + ui32Crc = CRC32_ITER(ui32Crc, ui32Temp >> 8); + ui32Crc = CRC32_ITER(ui32Crc, ui32Temp >> 16); + ui32Crc = CRC32_ITER(ui32Crc, ui32Temp >> 24); + + // + // Skip these input bytes. + // + pui8Data += 4; + ui32Count -= 4; + } + + // + // If there are 16 bits left in the input buffer, then perform two steps of + // the CRC. + // + if(ui32Count > 1) + { + // + // Read the two bytes. + // + ui32Temp = *(uint16_t *)pui8Data; + + // + // Perform the CRC on these two bytes. + // + ui32Crc = CRC32_ITER(ui32Crc, ui32Temp); + ui32Crc = CRC32_ITER(ui32Crc, ui32Temp >> 8); + + // + // Skip these input bytes. + // + pui8Data += 2; + ui32Count -= 2; + } + + // + // If there is a final byte remaining in the input buffer, then perform a + // single step of the CRC. + // + if(ui32Count != 0) + { + ui32Crc = CRC32_ITER(ui32Crc, *pui8Data); + } + + // + // Return the resulting CRC-32 value. + // + return(ui32Crc); +} + diff --git a/Software/Embedded_SW/Embedded/Common/Software_CRC/sw_crc.h b/Software/Embedded_SW/Embedded/Common/Software_CRC/sw_crc.h new file mode 100644 index 000000000..92f4c1ee7 --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/Software_CRC/sw_crc.h @@ -0,0 +1,40 @@ + +#ifndef COMMON_SW_CRC_H_ +#define COMMON_SW_CRC_H_ +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif +#include <stdint.h> + +//***************************************************************************** +// +// Prototypes for the functions. +// +//***************************************************************************** +extern uint8_t Crc8CCITT(uint8_t ui8Crc, const uint8_t *pui8Data, + uint32_t ui32Count); +extern uint16_t Crc16(uint16_t ui16Crc, const uint8_t *pui8Data, + uint32_t ui32Count); +extern uint16_t Crc16Array(uint32_t ui32WordLen, const uint32_t *pui32Data); +extern void Crc16Array3(uint32_t ui32WordLen, const uint32_t *pui32Data, + uint16_t *pui16Crc3); +extern uint32_t Crc32(uint32_t ui32Crc, const uint8_t *pui8Data, + uint32_t ui32Count); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif /* COMMON_SW_CRC_H_ */ diff --git a/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/MCU_MAIN_pinout.c b/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/MCU_MAIN_pinout.c new file mode 100644 index 000000000..2899a6a41 --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/MCU_MAIN_pinout.c @@ -0,0 +1,996 @@ +//***************************************************************************** +// +// Configure the device pins for different signals +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the +// distribution. +// +// Neither the name of Texas Instruments Incorporated nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//***************************************************************************** + +// This file was automatically generated on 25.2.2018 at 10:21:42 +// by TI PinMux version 4.0.1510 +// +//***************************************************************************** + +#include <stdbool.h> +#include <stdint.h> +#include "inc/hw_gpio.h" +#include "inc/hw_memmap.h" +#include "inc/hw_types.h" +#include "driverlib/gpio.h" +#include "driverlib/pin_map.h" +#include "driverlib/rom.h" +#include "driverlib/rom_map.h" +#include "driverlib/sysctl.h" +#include "pinout.h" + +//***************************************************************************** +// +//! \addtogroup pinout_api +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +//! Configures the device pins for the customer specific usage. +//! +//! \return None. +// +//***************************************************************************** +void +PinoutSet(void) +{ + // + // Enable Peripheral Clocks + // + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOG); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOH); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOM); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOR); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOS); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOT); + + // + // Configure the GPIO Pin Mux for PD1 + // for AIN14 + // + MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_1); + + // + // Configure the GPIO Pin Mux for PE3 + // for AIN0 + // + MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PK1 + // for AIN17 + // + MAP_GPIOPinTypeADC(GPIO_PORTK_BASE, GPIO_PIN_1); + + // + // Configure the GPIO Pin Mux for PE6 + // for AIN20 + // + MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_6); + + // + // Unlock the Port Pin and Set the Commit Bit + // + HWREG(GPIO_PORTD_BASE+GPIO_O_LOCK) = GPIO_LOCK_KEY; + HWREG(GPIO_PORTD_BASE+GPIO_O_CR) |= GPIO_PIN_7; + HWREG(GPIO_PORTD_BASE+GPIO_O_LOCK) = 0x0; + + // + // Configure the GPIO Pin Mux for PD7 + // for AIN4 + // + MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PD5 + // for AIN6 + // + MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PD0 + // for AIN15 + // + MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PD3 + // for AIN12 + // + MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PE1 + // for AIN2 + // + MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1); + + // + // Configure the GPIO Pin Mux for PB5 + // for AIN11 + // + MAP_GPIOPinTypeADC(GPIO_PORTB_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PK3 + // for AIN19 + // + MAP_GPIOPinTypeADC(GPIO_PORTK_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PK0 + // for AIN16 + // + MAP_GPIOPinTypeADC(GPIO_PORTK_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PD2 + // for AIN13 + // + MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PE4 + // for AIN9 + // + MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_4); + + // + // Unlock the Port Pin and Set the Commit Bit + // + HWREG(GPIO_PORTE_BASE+GPIO_O_LOCK) = GPIO_LOCK_KEY; + HWREG(GPIO_PORTE_BASE+GPIO_O_CR) |= GPIO_PIN_7; + HWREG(GPIO_PORTE_BASE+GPIO_O_LOCK) = 0x0; + + // + // Configure the GPIO Pin Mux for PE7 + // for AIN21 + // + MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PE5 + // for AIN8 + // + MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PE2 + // for AIN1 + // + MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PE0 + // for AIN3 + // + MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PK2 + // for AIN18 + // + MAP_GPIOPinTypeADC(GPIO_PORTK_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PB4 + // for AIN10 + // + MAP_GPIOPinTypeADC(GPIO_PORTB_BASE, GPIO_PIN_4); + + // + // Configure the GPIO Pin Mux for PD4 + // for AIN7 + // + MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_4); + + // + // Configure the GPIO Pin Mux for PD6 + // for AIN5 + // + MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_6); + + // + // Configure the GPIO Pin Mux for PT2 + // for CAN1RX + // + MAP_GPIOPinConfigure(GPIO_PT2_CAN1RX); + MAP_GPIOPinTypeCAN(GPIO_PORTT_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PT3 + // for CAN1TX + // + MAP_GPIOPinConfigure(GPIO_PT3_CAN1TX); + MAP_GPIOPinTypeCAN(GPIO_PORTT_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PK4 + // for EPI0S32 + // + MAP_GPIOPinConfigure(GPIO_PK4_EPI0S32); + GPIOPinTypeEPI(GPIO_PORTK_BASE, GPIO_PIN_4); + + // + // Configure the GPIO Pin Mux for PL4 + // for EPI0S26 + // + MAP_GPIOPinConfigure(GPIO_PL4_EPI0S26); + GPIOPinTypeEPI(GPIO_PORTL_BASE, GPIO_PIN_4); + + // + // Configure the GPIO Pin Mux for PK6 + // for EPI0S25 + // + MAP_GPIOPinConfigure(GPIO_PK6_EPI0S25); + GPIOPinTypeEPI(GPIO_PORTK_BASE, GPIO_PIN_6); + + // + // Configure the GPIO Pin Mux for PL0 + // for EPI0S16 + // + MAP_GPIOPinConfigure(GPIO_PL0_EPI0S16); + GPIOPinTypeEPI(GPIO_PORTL_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PG0 + // for EPI0S11 + // + MAP_GPIOPinConfigure(GPIO_PG0_EPI0S11); + GPIOPinTypeEPI(GPIO_PORTG_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PA6 + // for EPI0S8 + // + MAP_GPIOPinConfigure(GPIO_PA6_EPI0S8); + GPIOPinTypeEPI(GPIO_PORTA_BASE, GPIO_PIN_6); + + // + // Configure the GPIO Pin Mux for PH1 + // for EPI0S1 + // + MAP_GPIOPinConfigure(GPIO_PH1_EPI0S1); + GPIOPinTypeEPI(GPIO_PORTH_BASE, GPIO_PIN_1); + + // + // Configure the GPIO Pin Mux for PN3 + // for EPI0S30 + // + MAP_GPIOPinConfigure(GPIO_PN3_EPI0S30); + GPIOPinTypeEPI(GPIO_PORTN_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PB2 + // for EPI0S27 + // + MAP_GPIOPinConfigure(GPIO_PB2_EPI0S27); + GPIOPinTypeEPI(GPIO_PORTB_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PN4 + // for EPI0S34 + // + MAP_GPIOPinConfigure(GPIO_PN4_EPI0S34); + GPIOPinTypeEPI(GPIO_PORTN_BASE, GPIO_PIN_4); + + // + // Configure the GPIO Pin Mux for PQ1 + // for EPI0S21 + // + MAP_GPIOPinConfigure(GPIO_PQ1_EPI0S21); + GPIOPinTypeEPI(GPIO_PORTQ_BASE, GPIO_PIN_1); + + // + // Configure the GPIO Pin Mux for PL3 + // for EPI0S19 + // + MAP_GPIOPinConfigure(GPIO_PL3_EPI0S19); + GPIOPinTypeEPI(GPIO_PORTL_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PM0 + // for EPI0S15 + // + MAP_GPIOPinConfigure(GPIO_PM0_EPI0S15); + GPIOPinTypeEPI(GPIO_PORTM_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PM2 + // for EPI0S13 + // + MAP_GPIOPinConfigure(GPIO_PM2_EPI0S13); + GPIOPinTypeEPI(GPIO_PORTM_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PB3 + // for EPI0S28 + // + MAP_GPIOPinConfigure(GPIO_PB3_EPI0S28); + GPIOPinTypeEPI(GPIO_PORTB_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PQ3 + // for EPI0S23 + // + MAP_GPIOPinConfigure(GPIO_PQ3_EPI0S23); + GPIOPinTypeEPI(GPIO_PORTQ_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PG1 + // for EPI0S10 + // + MAP_GPIOPinConfigure(GPIO_PG1_EPI0S10); + GPIOPinTypeEPI(GPIO_PORTG_BASE, GPIO_PIN_1); + + // + // Configure the GPIO Pin Mux for PK5 + // for EPI0S31 + // + MAP_GPIOPinConfigure(GPIO_PK5_EPI0S31); + GPIOPinTypeEPI(GPIO_PORTK_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PN2 + // for EPI0S29 + // + MAP_GPIOPinConfigure(GPIO_PN2_EPI0S29); + GPIOPinTypeEPI(GPIO_PORTN_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PH3 + // for EPI0S3 + // + MAP_GPIOPinConfigure(GPIO_PH3_EPI0S3); + GPIOPinTypeEPI(GPIO_PORTH_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PC5 + // for EPI0S6 + // + MAP_GPIOPinConfigure(GPIO_PC5_EPI0S6); + GPIOPinTypeEPI(GPIO_PORTC_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PA7 + // for EPI0S9 + // + MAP_GPIOPinConfigure(GPIO_PA7_EPI0S9); + GPIOPinTypeEPI(GPIO_PORTA_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PH0 + // for EPI0S0 + // + MAP_GPIOPinConfigure(GPIO_PH0_EPI0S0); + GPIOPinTypeEPI(GPIO_PORTH_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PC4 + // for EPI0S7 + // + MAP_GPIOPinConfigure(GPIO_PC4_EPI0S7); + GPIOPinTypeEPI(GPIO_PORTC_BASE, GPIO_PIN_4); + + // + // Configure the GPIO Pin Mux for PL1 + // for EPI0S17 + // + MAP_GPIOPinConfigure(GPIO_PL1_EPI0S17); + GPIOPinTypeEPI(GPIO_PORTL_BASE, GPIO_PIN_1); + + // + // Configure the GPIO Pin Mux for PL5 + // for EPI0S33 + // + MAP_GPIOPinConfigure(GPIO_PL5_EPI0S33); + GPIOPinTypeEPI(GPIO_PORTL_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PN5 + // for EPI0S35 + // + MAP_GPIOPinConfigure(GPIO_PN5_EPI0S35); + GPIOPinTypeEPI(GPIO_PORTN_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PM1 + // for EPI0S14 + // + MAP_GPIOPinConfigure(GPIO_PM1_EPI0S14); + GPIOPinTypeEPI(GPIO_PORTM_BASE, GPIO_PIN_1); + + // + // Configure the GPIO Pin Mux for PK7 + // for EPI0S24 + // + MAP_GPIOPinConfigure(GPIO_PK7_EPI0S24); + GPIOPinTypeEPI(GPIO_PORTK_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PC7 + // for EPI0S4 + // + MAP_GPIOPinConfigure(GPIO_PC7_EPI0S4); + GPIOPinTypeEPI(GPIO_PORTC_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PL2 + // for EPI0S18 + // + MAP_GPIOPinConfigure(GPIO_PL2_EPI0S18); + GPIOPinTypeEPI(GPIO_PORTL_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PM3 + // for EPI0S12 + // + MAP_GPIOPinConfigure(GPIO_PM3_EPI0S12); + GPIOPinTypeEPI(GPIO_PORTM_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PQ0 + // for EPI0S20 + // + MAP_GPIOPinConfigure(GPIO_PQ0_EPI0S20); + GPIOPinTypeEPI(GPIO_PORTQ_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PQ2 + // for EPI0S22 + // + MAP_GPIOPinConfigure(GPIO_PQ2_EPI0S22); + GPIOPinTypeEPI(GPIO_PORTQ_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PC6 + // for EPI0S5 + // + MAP_GPIOPinConfigure(GPIO_PC6_EPI0S5); + GPIOPinTypeEPI(GPIO_PORTC_BASE, GPIO_PIN_6); + + // + // Configure the GPIO Pin Mux for PH2 + // for EPI0S2 + // + MAP_GPIOPinConfigure(GPIO_PH2_EPI0S2); + GPIOPinTypeEPI(GPIO_PORTH_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PB6 + // for GPIO_PB6 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_6); + + // + // Configure the GPIO Pin Mux for PB7 + // for GPIO_PB7 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PJ3 + // for GPIO_PJ3 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTJ_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PQ6 + // for GPIO_PQ6 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTQ_BASE, GPIO_PIN_6); + + // + // Configure the GPIO Pin Mux for PS5 + // for GPIO_PS5 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTS_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PS7 + // for GPIO_PS7 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTS_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PN7 + // for GPIO_PN7 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTN_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PS6 + // for GPIO_PS6 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTS_BASE, GPIO_PIN_6); + + // + // Configure the GPIO Pin Mux for PT1 + // for GPIO_PT1 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTT_BASE, GPIO_PIN_1); + + // + // Configure the GPIO Pin Mux for PT0 + // for GPIO_PT0 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTT_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PS4 + // for GPIO_PS4 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTS_BASE, GPIO_PIN_4); + + // + // Configure the GPIO Pin Mux for PN6 + // for GPIO_PN6 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_6); + + // + // Configure the GPIO Pin Mux for PF6 + // for GPIO_PF6 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_6); + + // + // Configure the GPIO Pin Mux for PM7 + // for GPIO_PM7 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTM_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PM6 + // for GPIO_PM6 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTM_BASE, GPIO_PIN_6); + + // + // Configure the GPIO Pin Mux for PF7 + // for GPIO_PF7 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PR3 + // for GPIO_PR3 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTR_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PM4 + // for GPIO_PM4 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTM_BASE, GPIO_PIN_4); + + // + // Configure the GPIO Pin Mux for PJ2 + // for GPIO_PJ2 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTJ_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PM5 + // for GPIO_PM5 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTM_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PH4 + // for GPIO_PH4 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTH_BASE, GPIO_PIN_4); + + // + // Configure the GPIO Pin Mux for PH7 + // for GPIO_PH7 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTH_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PH6 + // for GPIO_PH6 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTH_BASE, GPIO_PIN_6); + + // + // Configure the GPIO Pin Mux for PH5 + // for GPIO_PH5 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTH_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PQ7 + // for GPIO_PQ7 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTQ_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PJ4 + // for GPIO_PJ4 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTJ_BASE, GPIO_PIN_4); + + // + // Configure the GPIO Pin Mux for PJ5 + // for GPIO_PJ5 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTJ_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PS2 + // for GPIO_PS2 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTS_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PS3 + // for GPIO_PS3 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTS_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PJ7 + // for GPIO_PJ7 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTJ_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PS1 + // for GPIO_PS1 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTS_BASE, GPIO_PIN_1); + + // + // Configure the GPIO Pin Mux for PP5 + // for GPIO_PP5 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTP_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PP3 + // for GPIO_PP3 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTP_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PS0 + // for GPIO_PS0 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTS_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PN1 + // for GPIO_PN1 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_1); + + // + // Configure the GPIO Pin Mux for PN0 + // for GPIO_PN0 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PJ0 + // for GPIO_PJ0 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTJ_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PP4 + // for GPIO_PP4 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTP_BASE, GPIO_PIN_4); + + // + // Configure the GPIO Pin Mux for PJ1 + // for GPIO_PJ1 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTJ_BASE, GPIO_PIN_1); + + // + // Configure the GPIO Pin Mux for PP0 + // for GPIO_PP0 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTP_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PP1 + // for GPIO_PP1 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTP_BASE, GPIO_PIN_1); + + // + // Configure the GPIO Pin Mux for PP2 + // for GPIO_PP2 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTP_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PR2 + // for GPIO_PR2 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTR_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PJ6 + // for GPIO_PJ6 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTJ_BASE, GPIO_PIN_6); + + // + // Configure the GPIO Pin Mux for PP6 + // for GPIO_PP6 + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTP_BASE, GPIO_PIN_6); + + // + // Configure the GPIO Pin Mux for PP7 + // for GPIO_PP7 + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTP_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PR6 + // for I2C4SCL + // + MAP_GPIOPinConfigure(GPIO_PR6_I2C4SCL); + MAP_GPIOPinTypeI2CSCL(GPIO_PORTR_BASE, GPIO_PIN_6); + + // + // Configure the GPIO Pin Mux for PR7 + // for I2C4SDA + // + MAP_GPIOPinConfigure(GPIO_PR7_I2C4SDA); + MAP_GPIOPinTypeI2C(GPIO_PORTR_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PR4 + // for I2C3SCL + // + MAP_GPIOPinConfigure(GPIO_PR4_I2C3SCL); + MAP_GPIOPinTypeI2CSCL(GPIO_PORTR_BASE, GPIO_PIN_4); + + // + // Configure the GPIO Pin Mux for PR5 + // for I2C3SDA + // + MAP_GPIOPinConfigure(GPIO_PR5_I2C3SDA); + MAP_GPIOPinTypeI2C(GPIO_PORTR_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PG2 + // for I2C2SCL + // + MAP_GPIOPinConfigure(GPIO_PG2_I2C2SCL); + MAP_GPIOPinTypeI2CSCL(GPIO_PORTG_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PG3 + // for I2C2SDA + // + MAP_GPIOPinConfigure(GPIO_PG3_I2C2SDA); + MAP_GPIOPinTypeI2C(GPIO_PORTG_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PR0 + // for I2C1SCL + // + MAP_GPIOPinConfigure(GPIO_PR0_I2C1SCL); + MAP_GPIOPinTypeI2CSCL(GPIO_PORTR_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PR1 + // for I2C1SDA + // + MAP_GPIOPinConfigure(GPIO_PR1_I2C1SDA); + MAP_GPIOPinTypeI2C(GPIO_PORTR_BASE, GPIO_PIN_1); + + // + // Configure the GPIO Pin Mux for PF1 + // for SSI3XDAT0 + // + MAP_GPIOPinConfigure(GPIO_PF1_SSI3XDAT0); + MAP_GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_1); + + // + // Configure the GPIO Pin Mux for PF5 + // for SSI3XDAT3 + // + MAP_GPIOPinConfigure(GPIO_PF5_SSI3XDAT3); + MAP_GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PF0 + // for SSI3XDAT1 + // + MAP_GPIOPinConfigure(GPIO_PF0_SSI3XDAT1); + MAP_GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PF2 + // for SSI3FSS + // + MAP_GPIOPinConfigure(GPIO_PF2_SSI3FSS); + MAP_GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PF4 + // for SSI3XDAT2 + // + MAP_GPIOPinConfigure(GPIO_PF4_SSI3XDAT2); + MAP_GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_4); + + // + // Configure the GPIO Pin Mux for PF3 + // for SSI3CLK + // + MAP_GPIOPinConfigure(GPIO_PF3_SSI3CLK); + MAP_GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PG5 + // for SSI2XDAT0 + // + MAP_GPIOPinConfigure(GPIO_PG5_SSI2XDAT0); + MAP_GPIOPinTypeSSI(GPIO_PORTG_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PG4 + // for SSI2XDAT1 + // + MAP_GPIOPinConfigure(GPIO_PG4_SSI2XDAT1); + MAP_GPIOPinTypeSSI(GPIO_PORTG_BASE, GPIO_PIN_4); + + // + // Configure the GPIO Pin Mux for PG6 + // for SSI2FSS + // + MAP_GPIOPinConfigure(GPIO_PG6_SSI2FSS); + MAP_GPIOPinTypeSSI(GPIO_PORTG_BASE, GPIO_PIN_6); + + // + // Configure the GPIO Pin Mux for PG7 + // for SSI2CLK + // + MAP_GPIOPinConfigure(GPIO_PG7_SSI2CLK); + MAP_GPIOPinTypeSSI(GPIO_PORTG_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PA0 + // for U0RX + // + MAP_GPIOPinConfigure(GPIO_PA0_U0RX); + MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PA1 + // for U0TX + // + MAP_GPIOPinConfigure(GPIO_PA1_U0TX); + MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_1); + + // + // Configure the GPIO Pin Mux for PQ4 + // for U1RX + // + MAP_GPIOPinConfigure(GPIO_PQ4_U1RX); + MAP_GPIOPinTypeUART(GPIO_PORTQ_BASE, GPIO_PIN_4); + + // + // Configure the GPIO Pin Mux for PQ5 + // for U1TX + // + MAP_GPIOPinConfigure(GPIO_PQ5_U1TX); + MAP_GPIOPinTypeUART(GPIO_PORTQ_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PA4 + // for U3RX + // + MAP_GPIOPinConfigure(GPIO_PA4_U3RX); + MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_4); + + // + // Configure the GPIO Pin Mux for PA5 + // for U3TX + // + MAP_GPIOPinConfigure(GPIO_PA5_U3TX); + MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_5); + + // + // Configure the GPIO Pin Mux for PA2 + // for U4RX + // + MAP_GPIOPinConfigure(GPIO_PA2_U4RX); + MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_2); + + // + // Configure the GPIO Pin Mux for PA3 + // for U4TX + // + MAP_GPIOPinConfigure(GPIO_PA3_U4TX); + MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_3); + + // + // Configure the GPIO Pin Mux for PL6 + // for USB0DP + // + MAP_GPIOPinTypeUSBAnalog(GPIO_PORTL_BASE, GPIO_PIN_6); + + // + // Configure the GPIO Pin Mux for PL7 + // for USB0DM + // + MAP_GPIOPinTypeUSBAnalog(GPIO_PORTL_BASE, GPIO_PIN_7); + + // + // Configure the GPIO Pin Mux for PB0 + // for USB0ID + // + MAP_GPIOPinTypeUSBAnalog(GPIO_PORTB_BASE, GPIO_PIN_0); + + // + // Configure the GPIO Pin Mux for PB1 + // for USB0VBUS + // + MAP_GPIOPinTypeUSBAnalog(GPIO_PORTB_BASE, GPIO_PIN_1); + +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** + diff --git a/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/MCU_MAIN_pinout.h b/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/MCU_MAIN_pinout.h new file mode 100644 index 000000000..ebbe0b7d6 --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/MCU_MAIN_pinout.h @@ -0,0 +1,74 @@ +//***************************************************************************** +// pinout.h +// +// configure the device pins for different signals +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the +// distribution. +// +// Neither the name of Texas Instruments Incorporated nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//***************************************************************************** + +// This file was automatically generated on 25.2.2018 at 10:21:42 +// by TI PinMux version 4.0.1510 +// +//***************************************************************************** + +#ifndef __DRIVERS_PINOUT_H__ +#define __DRIVERS_PINOUT_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// Prototypes. +// +//***************************************************************************** +extern void PinoutSet(void); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // __DRIVERS_PINOUT_H__ diff --git a/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/Pin.c b/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/Pin.c new file mode 100644 index 000000000..1cb86ce4f --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/Pin.c @@ -0,0 +1,621 @@ +//***************************************************************************** +// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved. +// Software License Agreement +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the +// distribution. +// +// Neither the name of Texas Instruments Incorporated nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// This file was automatically generated by the Tiva C Series PinMux Utility +// Version: 1.0.4 +// +//***************************************************************************** + +#include <stdint.h> +#include <stdbool.h> + +#include <inc/hw_types.h> +#include <inc/hw_memmap.h> +#include <inc/hw_gpio.h> +#include <driverlib/sysctl.h> +#include <driverlib/pin_map.h> +#include <driverlib/rom_map.h> +#include <driverlib/gpio.h> + +#include "Common/Sys_PinOut_Config/Pin.h" + +#ifdef ROM_GPIOPinTypeEthernetLED +#define MAP_GPIOPinTypeEthernetLED \ + ROM_GPIOPinTypeEthernetLED +#else +#define MAP_GPIOPinTypeEthernetLED \ + GPIOPinTypeEthernetLED +#endif + +//***************************************************************************** +void +PortFunctionInit(void) +{ + // + // Enable Peripheral Clocks + // + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C4); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART7); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART5); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0); + + //hardware timers enabled manually because the pinout tool + //initialize automatically gpio per timer , deleting the gpio disables the timer + //manual initialization works well without gpios + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER3); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER4); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER5); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER6); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER7); + + + + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOG); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOH); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOM); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOR); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOS); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOT); + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_WDOG0); + // + // Enable pin PD2 for ADC AIN13 + // + //MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2); + + // + // Enable pin PE3 for ADC AIN0 + // + //MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3); + + // + // Enable pin PK0 for ADC AIN16 + // + MAP_GPIOPinTypeADC(GPIO_PORTK_BASE, GPIO_PIN_0); + + // + // Enable pin PE6 for ADC AIN20 + // + MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_6); + + // + // Enable pin PD3 for ADC AIN12 + // + MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_3); + + // + // Enable pin PE1 for ADC AIN2 + // + //MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1); + + // + // Enable pin PK1 for ADC AIN17 + // + MAP_GPIOPinTypeADC(GPIO_PORTK_BASE, GPIO_PIN_1); + + // + // Enable pin PK3 for ADC AIN19 + // + MAP_GPIOPinTypeADC(GPIO_PORTK_BASE, GPIO_PIN_3); + + // + // Enable pin PP6 for ADC AIN23 + // + MAP_GPIOPinTypeADC(GPIO_PORTP_BASE, GPIO_PIN_6); + + // + // Enable pin PE7 for ADC AIN21 + // First open the lock and select the bits we want to modify in the GPIO commit register. + // + HWREG(GPIO_PORTE_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY; + HWREG(GPIO_PORTE_BASE + GPIO_O_CR) = 0x80; + + // + // Now modify the configuration of the pins that we unlocked. + // + MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_7); + + // + // Enable pin PB4 for ADC AIN10 + // + MAP_GPIOPinTypeADC(GPIO_PORTB_BASE, GPIO_PIN_4); + + // + // Enable pin PD6 for ADC AIN5 + // + MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_6); + + // + // Enable pin PE2 for ADC AIN1 + // + MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2); + + // + // Enable pin PE0 for ADC AIN3 + // + MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0); + + // + // Enable pin PK2 for ADC AIN18 + // + MAP_GPIOPinTypeADC(GPIO_PORTK_BASE, GPIO_PIN_2); + + // + // Enable pin PP7 for ADC AIN22 + // + MAP_GPIOPinTypeADC(GPIO_PORTP_BASE, GPIO_PIN_7); + + // + // Enable pin PK4 for EPHY0 EN0LED0 + // + MAP_GPIOPinConfigure(GPIO_PK4_EN0LED0); + MAP_GPIOPinTypeEthernetLED(GPIO_PORTK_BASE, GPIO_PIN_4); + + // + // Enable pin PK5 for EPHY0 EN0LED2 + // + MAP_GPIOPinConfigure(GPIO_PK5_EN0LED2); + MAP_GPIOPinTypeEthernetLED(GPIO_PORTK_BASE, GPIO_PIN_5); + + // + // Enable pin PK6 for EPHY0 EN0LED1 + // + MAP_GPIOPinConfigure(GPIO_PK6_EN0LED1); + MAP_GPIOPinTypeEthernetLED(GPIO_PORTK_BASE, GPIO_PIN_6); + + // + // Enable pin PD0 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTD_BASE, GPIO_PIN_0); + + // + // Enable pin PD1 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTD_BASE, GPIO_PIN_1); + + // + // Enable pin PE4 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTE_BASE, GPIO_PIN_4); + + // + // Enable pin PF7 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_7); + + // + // Enable pin PF6 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_6); + + // + // Enable pin PG4 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTG_BASE, GPIO_PIN_4); + + // + // Enable pin PG5 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTG_BASE, GPIO_PIN_5); + + // + // Enable pin PG0 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTG_BASE, GPIO_PIN_0); + + // + // Enable pin PG1 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTG_BASE, GPIO_PIN_1); + + // + // Enable pin PH2 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTH_BASE, GPIO_PIN_2); + + // + // Enable pin PH0 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTH_BASE, GPIO_PIN_0); + + // + // Enable pin PH4 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTH_BASE, GPIO_PIN_4); + + // + // Enable pin PH6 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTH_BASE, GPIO_PIN_6); + + // + // Enable pin PH7 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTH_BASE, GPIO_PIN_7); + + // + // Enable pin PH5 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTH_BASE, GPIO_PIN_5); + + // + // Enable pin PH1 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTH_BASE, GPIO_PIN_1); + + // + // Enable pin PH3 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTH_BASE, GPIO_PIN_3); + + // + // Enable pin PJ7 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTJ_BASE, GPIO_PIN_7); + + // + // Enable pin PJ6 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTJ_BASE, GPIO_PIN_6); + + // + // Enable pin PJ2 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTJ_BASE, GPIO_PIN_2); + + // + // Enable pin PJ3 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTJ_BASE, GPIO_PIN_3); + + // + // Enable pin PL3 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTL_BASE, GPIO_PIN_3); + + // + // Enable pin PL0 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTL_BASE, GPIO_PIN_0); + + // + // Enable pin PL1 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTL_BASE, GPIO_PIN_1); + + // + // Enable pin PL4 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTL_BASE, GPIO_PIN_4); + + // + // Enable pin PL2 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTL_BASE, GPIO_PIN_2); + + // + // Enable pin PL5 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTL_BASE, GPIO_PIN_5); + + // + // Enable pin PM1 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTM_BASE, GPIO_PIN_1); + + // + // Enable pin PM0 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTM_BASE, GPIO_PIN_0); + + // + // Enable pin PM3 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTM_BASE, GPIO_PIN_3); + + // + // Enable pin PM5 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTM_BASE, GPIO_PIN_5); + + // + // Enable pin PM2 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTM_BASE, GPIO_PIN_2); + + // + // Enable pin PN7 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTN_BASE, GPIO_PIN_7); + + // + // Enable pin PN1 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_1); + + // + // Enable pin PN4 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_4); + + // + // Enable pin PN0 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTN_BASE, GPIO_PIN_0); + + // + // Enable pin PP2 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTP_BASE, GPIO_PIN_2); + + // + // Enable pin PP4 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTP_BASE, GPIO_PIN_4); + + // + // Enable pin PP3 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTP_BASE, GPIO_PIN_3); + + // + // Enable pin PP5 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTP_BASE, GPIO_PIN_5); + + // + // Enable pin PP0 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTP_BASE, GPIO_PIN_0); + + // + // Enable pin PQ5 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTQ_BASE, GPIO_PIN_5); + + // + // Enable pin PQ7 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTQ_BASE, GPIO_PIN_7); + + // + // Enable pin PR3 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTR_BASE, GPIO_PIN_3); + + // + // Enable pin PR1 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTR_BASE, GPIO_PIN_1); + + // + // Enable pin PS4 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTS_BASE, GPIO_PIN_4); + + // + // Enable pin PS0 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTS_BASE, GPIO_PIN_0); + + // + // Enable pin PS2 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTS_BASE, GPIO_PIN_2); + + // + // Enable pin PS5 for GPIOOutput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTS_BASE, GPIO_PIN_5); + + // + // Enable pin PS3 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTS_BASE, GPIO_PIN_3); + + // + // Enable pin PT2 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTT_BASE, GPIO_PIN_2); + + // + // Enable pin PT0 for GPIOInput + // + MAP_GPIOPinTypeGPIOInput(GPIO_PORTT_BASE, GPIO_PIN_0); + + // + // Enable pin PA7 for GPIOInput + // + MAP_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_7); + + // + // Enable pin PB3 for I2C0 I2C0SDA + // + MAP_GPIOPinConfigure(GPIO_PB3_I2C0SDA); + MAP_GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3); + + // + // Enable pin PB2 for I2C0 I2C0SCL + // + MAP_GPIOPinConfigure(GPIO_PB2_I2C0SCL); + MAP_GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2); + + // + // Enable pin PG6 for I2C4 I2C4SCL + // + MAP_GPIOPinConfigure(GPIO_PG6_I2C4SCL); + MAP_GPIOPinTypeI2CSCL(GPIO_PORTG_BASE, GPIO_PIN_6); + + // + // Enable pin PG7 for I2C4 I2C4SDA + // + MAP_GPIOPinConfigure(GPIO_PG7_I2C4SDA); + MAP_GPIOPinTypeI2C(GPIO_PORTG_BASE, GPIO_PIN_7); + + // + // Enable pin PR2 for PWM0 M0PWM2 + // + MAP_GPIOPinConfigure(GPIO_PR2_M0PWM2); + MAP_GPIOPinTypePWM(GPIO_PORTR_BASE, GPIO_PIN_2); + + // + // Enable pin PR7 for PWM0 M0PWM7 + // + MAP_GPIOPinConfigure(GPIO_PR7_M0PWM7); + MAP_GPIOPinTypePWM(GPIO_PORTR_BASE, GPIO_PIN_7); + + // + // Enable pin PR5 for PWM0 M0PWM5 + // + MAP_GPIOPinConfigure(GPIO_PR5_M0PWM5); + MAP_GPIOPinTypePWM(GPIO_PORTR_BASE, GPIO_PIN_5); + + // + // Enable pin PR0 for PWM0 M0PWM0 + // + MAP_GPIOPinConfigure(GPIO_PR0_M0PWM0); + MAP_GPIOPinTypePWM(GPIO_PORTR_BASE, GPIO_PIN_0); + + // + // Enable pin PA3 for SSI0 SSI0FSS + // + MAP_GPIOPinConfigure(GPIO_PA3_SSI0FSS); + MAP_GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_3); + + // + // Enable pin PA4 for SSI0 SSI0XDAT0 + // + MAP_GPIOPinConfigure(GPIO_PA4_SSI0XDAT0); + MAP_GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_4); + + // + // Enable pin PA5 for SSI0 SSI0XDAT1 + // + MAP_GPIOPinConfigure(GPIO_PA5_SSI0XDAT1); + MAP_GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5); + + // + // Enable pin PA2 for SSI0 SSI0CLK + // + MAP_GPIOPinConfigure(GPIO_PA2_SSI0CLK); + MAP_GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_2); + + // + // Enable pin PQ0 for SSI3 SSI3CLK + // + MAP_GPIOPinConfigure(GPIO_PQ0_SSI3CLK); + MAP_GPIOPinTypeSSI(GPIO_PORTQ_BASE, GPIO_PIN_0); + + // + // Enable pin PF1 for SSI3 SSI3XDAT0 + // + MAP_GPIOPinConfigure(GPIO_PF1_SSI3XDAT0); + MAP_GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_1); + + // + // Enable pin PQ1 for SSI3 SSI3FSS + // + MAP_GPIOPinConfigure(GPIO_PQ1_SSI3FSS); + MAP_GPIOPinTypeSSI(GPIO_PORTQ_BASE, GPIO_PIN_1); + + // + // Enable pin PF5 for SSI3 SSI3XDAT3 + // + MAP_GPIOPinConfigure(GPIO_PF5_SSI3XDAT3); + MAP_GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_5); + + // + // Enable pin PF0 for SSI3 SSI3XDAT1 + // + MAP_GPIOPinConfigure(GPIO_PF0_SSI3XDAT1); + MAP_GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_0); + + // + // Enable pin PC7 for UART5 U5TX + // + MAP_GPIOPinConfigure(GPIO_PC7_U5TX); + MAP_GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_7); + + // + // Enable pin PC6 for UART5 U5RX + // + MAP_GPIOPinConfigure(GPIO_PC6_U5RX); + MAP_GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_6); + + // + // Enable pin PC5 for UART7 U7TX + // + MAP_GPIOPinConfigure(GPIO_PC5_U7TX); + MAP_GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_5); + + // + // Enable pin PC4 for UART7 U7RX + // + MAP_GPIOPinConfigure(GPIO_PC4_U7RX); + MAP_GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_4); + + // + // Enable pin PL6 for USB0 USB0DP + // + MAP_GPIOPinTypeUSBAnalog(GPIO_PORTL_BASE, GPIO_PIN_6); + + // + // Enable pin PL7 for USB0 USB0DM + // + MAP_GPIOPinTypeUSBAnalog(GPIO_PORTL_BASE, GPIO_PIN_7); + + // + // Enable pin PB1 for USB0 USB0VBUS + // + MAP_GPIOPinTypeUSBAnalog(GPIO_PORTB_BASE, GPIO_PIN_1); +} diff --git a/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/Pin.h b/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/Pin.h new file mode 100644 index 000000000..d5e51f6b4 --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/Pin.h @@ -0,0 +1,43 @@ +//***************************************************************************** +// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved. +// Software License Agreement +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the +// distribution. +// +// Neither the name of Texas Instruments Incorporated nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// This file was automatically generated by the Tiva C Series PinMux Utility +// Version: 1.0.4 +// +//***************************************************************************** + +#ifndef __PIN_H__ +#define __PIN_H__ + +extern void PortFunctionInit(void); + +#endif // __PIN_H__ diff --git a/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/Pin_config.c b/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/Pin_config.c new file mode 100644 index 000000000..8e378309a --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/Pin_config.c @@ -0,0 +1,51 @@ +#include <stdbool.h> +#include <stdint.h> + +#include <driverlib/gpio.h> +#include <inc/hw_memmap.h> + +void InitPinOutPullUps(void) +{ + GPIOPadConfigSet(GPIO_PORTD_BASE, GPIO_INT_PIN_0,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + GPIOPadConfigSet(GPIO_PORTD_BASE, GPIO_INT_PIN_1,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + + GPIOPadConfigSet(GPIO_PORTD_BASE, GPIO_INT_PIN_2,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + GPIOPadConfigSet(GPIO_PORTD_BASE, GPIO_INT_PIN_3,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + GPIOPadConfigSet(GPIO_PORTE_BASE, GPIO_INT_PIN_1,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + + GPIOPadConfigSet(GPIO_PORTE_BASE, GPIO_INT_PIN_4,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + + GPIOPadConfigSet(GPIO_PORTG_BASE, GPIO_INT_PIN_0,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + GPIOPadConfigSet(GPIO_PORTG_BASE, GPIO_INT_PIN_1,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + + GPIOPadConfigSet(GPIO_PORTH_BASE, GPIO_INT_PIN_5,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + GPIOPadConfigSet(GPIO_PORTH_BASE, GPIO_INT_PIN_6,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + GPIOPadConfigSet(GPIO_PORTH_BASE, GPIO_INT_PIN_7,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + + GPIOPadConfigSet(GPIO_PORTJ_BASE, GPIO_INT_PIN_2,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + GPIOPadConfigSet(GPIO_PORTJ_BASE, GPIO_INT_PIN_3,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + GPIOPadConfigSet(GPIO_PORTJ_BASE, GPIO_INT_PIN_7,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + + GPIOPadConfigSet(GPIO_PORTM_BASE, GPIO_INT_PIN_5,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + + GPIOPadConfigSet(GPIO_PORTN_BASE, GPIO_INT_PIN_0,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + GPIOPadConfigSet(GPIO_PORTN_BASE, GPIO_INT_PIN_7,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + + GPIOPadConfigSet(GPIO_PORTP_BASE, GPIO_INT_PIN_0,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + GPIOPadConfigSet(GPIO_PORTP_BASE, GPIO_INT_PIN_4,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + GPIOPadConfigSet(GPIO_PORTP_BASE, GPIO_INT_PIN_5,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + + GPIOPadConfigSet(GPIO_PORTQ_BASE, GPIO_INT_PIN_5,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + GPIOPadConfigSet(GPIO_PORTQ_BASE, GPIO_INT_PIN_7,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + + GPIOPadConfigSet(GPIO_PORTS_BASE, GPIO_INT_PIN_0,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + GPIOPadConfigSet(GPIO_PORTS_BASE, GPIO_INT_PIN_3,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + + GPIOPadConfigSet(GPIO_PORTT_BASE, GPIO_INT_PIN_0,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + GPIOPadConfigSet(GPIO_PORTT_BASE, GPIO_INT_PIN_2,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); + +} + + + + diff --git a/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/Pin_config.h b/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/Pin_config.h new file mode 100644 index 000000000..c83281cd9 --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/Sys_PinOut_Config/Pin_config.h @@ -0,0 +1,14 @@ +/**************************************************************************************************** + * init ialization of pull up's over GPIO + * those pins must be configured as inputs in the pinmap file by using MAP_GPIOPinTypeGPIOInput func + * here is added onlu the pull up defenition + *****************************************************************************************************/ + +#ifndef PIN_CONFIG_H_ +#define PIN_CONFIG_H_ + + +void InitPinOutPullUps(void); + + +#endif /* PIN_CONFIG_H_ */ diff --git a/Software/Embedded_SW/Embedded/Common/Utilities/Update.c b/Software/Embedded_SW/Embedded/Common/Utilities/Update.c new file mode 100644 index 000000000..8eeee64cf --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/Utilities/Update.c @@ -0,0 +1,98 @@ + +#include "include.h" +//#include <stdbool.h> + +//#include "Drivers/USB_Communication/USBCDCD.h" + + +extern Semaphore_Handle updateSem; + + +void UpdateUsb(void) +{ + // + // Terminate the USB device and detach from the bus. + // + USBDCDTerm(0); + + // + // Disable all interrupts. + // + ROM_IntMasterDisable(); + + // + // Disable SysTick and its interrupt. + // + ROM_SysTickIntDisable(); + ROM_SysTickDisable(); + + // + // Disable all processor interrupts. Instead of disabling them one at a + // time, a direct write to NVIC is done to disable all peripheral + // interrupts. + // + HWREG(NVIC_DIS0) = 0xffffffff; + HWREG(NVIC_DIS1) = 0xffffffff; + HWREG(NVIC_DIS2) = 0xffffffff; + HWREG(NVIC_DIS3) = 0xffffffff; + HWREG(NVIC_DIS4) = 0xffffffff; + + // + // Enable and reset the USB peripheral. + // + ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0); + ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0); + ROM_USBClockEnable(USB0_BASE, 8, USB_CLOCK_INTERNAL); + + // + // Wait for about a second. + // + ROM_SysCtlDelay(SYS_CLK_FREQ / 3); + + // + // Re-enable interrupts at the NVIC level. + // + ROM_IntMasterEnable(); + + // + // Call the USB boot loader. + // + ROM_UpdateUSB(0); + + // + // Should never get here, but just in case. + // + while(1) + { + } +} + +Void updateTask(UArg arg0, UArg arg1) +{ + + // + // Wait until new updTE ARRIVED + // + Semaphore_pend(updateSem, BIOS_WAIT_FOREVER); + UpdateUsb(); +} +extern Semaphore_Handle ReconnectSem; + + +void ReconnectUsb(void) +{ + //USBCDC_close(); +} + +Void ReconnectTask(UArg arg0, UArg arg1) +{ + + // + // Wait until new updTE ARRIVED + // + while (1) + { + Semaphore_pend(ReconnectSem, BIOS_WAIT_FOREVER); + ReconnectUsb(); + } +} diff --git a/Software/Embedded_SW/Embedded/Common/Utilities/Utils.c b/Software/Embedded_SW/Embedded/Common/Utilities/Utils.c new file mode 100644 index 000000000..d792d9b5f --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/Utilities/Utils.c @@ -0,0 +1,245 @@ +/************************************************************ + * Utils.h + * general module of system utility functions + **************************************************************/ + +#include <inc/hw_ints.h> +#include <inc/hw_memmap.h> +#include <driverlib/rom.h> +#include <time.h> +#include "Common/Utilities/Utils.h" +//#include <driverlib/systick.h> +#include "driverlib/hibernate.h" + +static const float speedCoef = 5.3051647697298445256294587790838f;//(200 micro steping)/2*Pi*Radius - 200 micro steping + +//***************************************************************************** + +bool DanserCheckPosition(uint16_t position , Danser_t danser, bool test) +{ + if (test == false) return true; +#ifdef DEBUG_DANCER + ProfileType_t profileType = GetCurrentProfileType(); + if (position < DANSER_POS_MIN) + { + if(danser == Winder) + { + if(profileType == Manual) + { + JigStopAllWithError("Thread torn in winder danser");//for stoping the system operation + } + else if (profileType == User) + { + //notify the UI about an error and pause the system + SendMessageToHost(ERROR_IN_PROFILE_EXECUTION,"Thread torn in winder danser"); + JigPauseAll(); + } + } + else + { + if(profileType == Manual) + { + JigStopAllWithError("Thread torn in pooler danser");//for stoping the system operation + } + else if (profileType == User) + { + //notify the UI about an error and pause the system + SendMessageToHost(ERROR_IN_PROFILE_EXECUTION,"Thread torn in pooler danser"); + JigPauseAll(); + } + } + return false; + } + + if (position > DANSER_POS_MAX) + { + if(danser == Pooler) + { + if(profileType == Manual) + { + JigStopAllWithError("Thread stocked in pooler danser"); + } + else if (profileType == User) + { + SendMessageToHost(ERROR_IN_PROFILE_EXECUTION,"Thread stuck in pooler danser"); + JigPauseAll(); + } + } + else + { + if(profileType == Manual) + { + JigStopAllWithError("Thread stocked in winder danser"); + } + else if (profileType ==User) + { + SendMessageToHost(ERROR_IN_PROFILE_EXECUTION,"Thread stuck in winder danser"); + JigPauseAll(); + } + } + return false; + } +#endif + return true; +} + +//***************************************************************************** +//convert thread speed recieved in milimeters per second into motor steps of pps +//***************************************************************************** +uint16_t ConvertSpeed2Pps(uint16_t milimeterPerSecond) +{ + float res = speedCoef*(float)milimeterPerSecond; + return (uint16_t)res; +} +//***************************************************************************** + +uint16_t ConvertPpsToSpeed(uint16_t Pps) +{ + float res = (float)Pps/speedCoef; + return (uint16_t)res; + +} + +//***************************************************************************** +// +// Init WD timer +// +//***************************************************************************** +void InitWatchdog(uint32_t clock) +{ + // + // Enable the watchdog interrupt. + // + ROM_IntEnable(INT_WATCHDOG); + + // + // Set the period of the watchdog timer. + // + ROM_WatchdogReloadSet(WATCHDOG0_BASE, clock); + + // + // Enable reset generation from the watchdog timer. + // + ROM_WatchdogResetEnable(WATCHDOG0_BASE); + + // + // Enable the watchdog timer. + // + ROM_WatchdogEnable(WATCHDOG0_BASE); +} +void utilsInit(uint32_t ui32SysClock) +{ + + cb_init(); +// SysTickPeriodSet(120000); +// SysTickEnable(); + // Configure Hibernate module clock. + // + HibernateEnableExpClk(ui32SysClock); + + + // Enable RTC mode. + // + HibernateRTCEnable(); + + // + // Configure the hibernate module counter to 24-hour calendar mode. + // + // HibernateCounterMode(HIBERNATE_COUNTER_24HR); + // Configure the hibernate module counter to RTC counter mode. + HibernateCounterMode(HIBERNATE_COUNTER_RTC); + + +} + + +uint32_t UsersysTickGet (void) { + uint32_t tick = 0; +// tick = SysTickValueGet(); + tick = HibernateRTCSSGet()*10000/0x8000; + return tick; +} + +//***************************************************************************** +// +// The interrupt handler for the watchdog. This feeds the dog (so that the +// processor does not get reset) and winks the LED connected to GPIO B3. +// +//***************************************************************************** +void WatchdogIntHandler(void) +{ + // + // Clear the watchdog interrupt. + // + ROM_WatchdogIntClear(WATCHDOG0_BASE); +} + +bool sendDataToHost = false; +void UtilsSetCommunicationOk(void) +{ + sendDataToHost = true; +} + +typedef struct circular_buffer +{ + void *buffer; // data buffer + void *buffer_end; // end of data buffer + uint16_t capacity; // maximum number of items in the buffer + uint16_t count; // number of items in the buffer + uint16_t sz; // size of each item in the buffer + void *head; // pointer to head + void *tail; // pointer to tail +} circular_buffer; + +uint8_t LogBuffer[8002]; +circular_buffer cb; +void cb_init() +{ + //cb.buffer = malloc(capacity * sz); + //if(cb.buffer == NULL) + // handle error + cb.buffer = LogBuffer; + cb.buffer_end = &LogBuffer[3950]; + cb.capacity = 4000; + cb.count = 0; + cb.sz = 60; + cb.head = cb.buffer; + cb.tail = cb.buffer; +} + +void cb_free(circular_buffer *cb) +{ + //free(cb.buffer); + // clear out other fields too, just to be safe +} + +void cb_push_back(/*circular_buffer *cb,*/ const void *item, int size) +{ + if(cb.count == cb.capacity){ + return; + // handle error + } + if ((int)(cb.head) + size > (int)(cb.buffer_end)){ + size = (int)(cb.buffer_end) - (int)(cb.head); + } + + memcpy(cb.head, item, size); + cb.head = (char*)cb.head + size; + if(cb.head >= cb.buffer_end) + cb.head = cb.buffer; + cb.count++; +// if (sendDataToHost) +// SendMessageToHost(DEBUG_LOG,item); +} + +void cb_pop_front(/*circular_buffer *cb,*/ void *item) +{ + if(cb.count == 0){ + // handle error + } + memcpy(item, cb.tail, cb.sz); + cb.tail = (char*)cb.tail + cb.sz; + if(cb.tail == cb.buffer_end) + cb.tail = cb.buffer; + cb.count--; +} diff --git a/Software/Embedded_SW/Embedded/Common/Utilities/Utils.h b/Software/Embedded_SW/Embedded/Common/Utilities/Utils.h new file mode 100644 index 000000000..363cf6eec --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/Utilities/Utils.h @@ -0,0 +1,33 @@ +/************************************************************ + * Utils.h + * general module of system utility functions + **************************************************************/ + +#ifndef COMMON_UTILS_H_ +#define COMMON_UTILS_H_ + +#include <stdbool.h> +#include <stdint.h> + + +//digital read of the potentiometer limits +#define DANSER_POS_MIN 1300 +#define DANSER_POS_MAX 3500 + +typedef enum +{ + Winder = 0, + Pooler +}Danser_t; + + +void cb_init(); +void cb_push_back(/*void *cb,*/ const void *item, int size); +void utilsInit(uint32_t ui32SysClock); +uint32_t UsersysTickGet (void); +bool DanserCheckPosition(uint16_t position , Danser_t danser, bool test); +void InitWatchdog(uint32_t clock); +uint16_t ConvertSpeed2Pps(uint16_t milimeterPerSecond); +uint16_t ConvertPpsToSpeed(uint16_t Pps); +void UtilsSetCommunicationOk(void); +#endif /* COMMON_UTILS_H_ */ diff --git a/Software/Embedded_SW/Embedded/Common/Utilities/ustdlib.c b/Software/Embedded_SW/Embedded/Common/Utilities/ustdlib.c new file mode 100644 index 000000000..efee94611 --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/Utilities/ustdlib.c @@ -0,0 +1,1825 @@ +//***************************************************************************** +// +// ustdlib.c - Simple standard library functions. +// +// Copyright (c) 2007-2015 Texas Instruments Incorporated. All rights reserved. +// Software License Agreement +// +// Texas Instruments (TI) is supplying this software for use solely and +// exclusively on TI's microcontroller products. The software is owned by +// TI and/or its suppliers, and is protected under applicable copyright +// laws. You may not combine this software with "viral" open-source +// software in order to form a larger program. +// +// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. +// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT +// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY +// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL +// DAMAGES, FOR ANY REASON WHATSOEVER. +// +// This is part of revision 2.1.2.111 of the Tiva Utility Library. +// +//***************************************************************************** + +#include <stdint.h> +#include <driverlib/debug.h> +#include <utils/ustdlib.h> + +//***************************************************************************** +// +//! \addtogroup ustdlib_api +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// A mapping from an integer between 0 and 15 to its ASCII character +// equivalent. +// +//***************************************************************************** +static const char * const g_pcHex = "0123456789abcdef"; + +//***************************************************************************** +// +//! Copies a certain number of characters from one string to another. +//! +//! \param s1 is a pointer to the destination buffer into which characters +//! are to be copied. +//! \param s2 is a pointer to the string from which characters are to be +//! copied. +//! \param n is the number of characters to copy to the destination buffer. +//! +//! This function copies at most \e n characters from the string pointed to +//! by \e s2 into the buffer pointed to by \e s1. If the end of \e s2 is found +//! before \e n characters have been copied, remaining characters in \e s1 +//! will be padded with zeroes until \e n characters have been written. Note +//! that the destination string will only be NULL terminated if the number of +//! characters to be copied is greater than the length of \e s2. +//! +//! \return Returns \e s1. +// +//***************************************************************************** +char * +ustrncpy(char * restrict s1, const char * restrict s2, size_t n) +{ + size_t count; + + // + // Check the arguments. + // + ASSERT(s1); + ASSERT(s2); + + // + // Start at the beginning of the source string. + // + count = 0; + + // + // Copy the source string until we run out of source characters or + // destination space. + // + while(n && s2[count]) + { + s1[count] = s2[count]; + count++; + n--; + } + + // + // Pad the destination if we are not yet done. + // + while(n) + { + s1[count++] = (char)0; + n--; + } + + // + // Pass the destination pointer back to the caller. + // + return(s1); +} + +//***************************************************************************** +// +//! A simple vsnprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and +//! \%X. +//! +//! \param s points to the buffer where the converted string is stored. +//! \param n is the size of the buffer. +//! \param format is the format string. +//! \param arg is the list of optional arguments, which depend on the +//! contents of the format string. +//! +//! This function is very similar to the C library <tt>vsnprintf()</tt> +//! function. Only the following formatting characters are supported: +//! +//! - \%c to print a character +//! - \%d or \%i to print a decimal value +//! - \%s to print a string +//! - \%u to print an unsigned decimal value +//! - \%x to print a hexadecimal value using lower case letters +//! - \%X to print a hexadecimal value using lower case letters (not upper case +//! letters as would typically be used) +//! - \%p to print a pointer as a hexadecimal value +//! - \%\% to print out a \% character +//! +//! For \%d, \%i, \%p, \%s, \%u, \%x, and \%X, an optional number may reside +//! between the \% and the format character, which specifies the minimum number +//! of characters to use for that value; if preceded by a 0 then the extra +//! characters will be filled with zeros instead of spaces. For example, +//! ``\%8d'' will use eight characters to print the decimal value with spaces +//! added to reach eight; ``\%08d'' will use eight characters as well but will +//! add zeroes instead of spaces. +//! +//! The type of the arguments after \e format must match the requirements of +//! the format string. For example, if an integer was passed where a string +//! was expected, an error of some kind will most likely occur. +//! +//! The \e n parameter limits the number of characters that will be +//! stored in the buffer pointed to by \e s to prevent the possibility of +//! a buffer overflow. The buffer size should be large enough to hold the +//! expected converted output string, including the null termination character. +//! +//! The function will return the number of characters that would be converted +//! as if there were no limit on the buffer size. Therefore it is possible for +//! the function to return a count that is greater than the specified buffer +//! size. If this happens, it means that the output was truncated. +//! +//! \return Returns the number of characters that were to be stored, not +//! including the NULL termination character, regardless of space in the +//! buffer. +// +//***************************************************************************** +int +uvsnprintf(char * restrict s, size_t n, const char * restrict format, + va_list arg) +{ + unsigned long ulIdx, ulValue, ulCount, ulBase, ulNeg; + char *pcStr, cFill; + int iConvertCount = 0; + + // + // Check the arguments. + // + ASSERT(s); + ASSERT(n); + ASSERT(format); + + // + // Adjust buffer size limit to allow one space for null termination. + // + if(n) + { + n--; + } + + // + // Initialize the count of characters converted. + // + iConvertCount = 0; + + // + // Loop while there are more characters in the format string. + // + while(*format) + { + // + // Find the first non-% character, or the end of the string. + // + for(ulIdx = 0; (format[ulIdx] != '%') && (format[ulIdx] != '\0'); + ulIdx++) + { + } + + // + // Write this portion of the string to the output buffer. If there are + // more characters to write than there is space in the buffer, then + // only write as much as will fit in the buffer. + // + if(ulIdx > n) + { + ustrncpy(s, format, n); + s += n; + n = 0; + } + else + { + ustrncpy(s, format, ulIdx); + s += ulIdx; + n -= ulIdx; + } + + // + // Update the conversion count. This will be the number of characters + // that should have been written, even if there was not room in the + // buffer. + // + iConvertCount += ulIdx; + + // + // Skip the portion of the format string that was written. + // + format += ulIdx; + + // + // See if the next character is a %. + // + if(*format == '%') + { + // + // Skip the %. + // + format++; + + // + // Set the digit count to zero, and the fill character to space + // (that is, to the defaults). + // + ulCount = 0; + cFill = ' '; + + // + // It may be necessary to get back here to process more characters. + // Goto's aren't pretty, but effective. I feel extremely dirty for + // using not one but two of the beasts. + // +again: + + // + // Determine how to handle the next character. + // + switch(*format++) + { + // + // Handle the digit characters. + // + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + // + // If this is a zero, and it is the first digit, then the + // fill character is a zero instead of a space. + // + if((format[-1] == '0') && (ulCount == 0)) + { + cFill = '0'; + } + + // + // Update the digit count. + // + ulCount *= 10; + ulCount += format[-1] - '0'; + + // + // Get the next character. + // + goto again; + } + + // + // Handle the %c command. + // + case 'c': + { + // + // Get the value from the varargs. + // + ulValue = va_arg(arg, unsigned long); + + // + // Copy the character to the output buffer, if there is + // room. Update the buffer size remaining. + // + if(n != 0) + { + *s++ = (char)ulValue; + n--; + } + + // + // Update the conversion count. + // + iConvertCount++; + + // + // This command has been handled. + // + break; + } + + // + // Handle the %d and %i commands. + // + case 'd': + case 'i': + { + // + // Get the value from the varargs. + // + ulValue = va_arg(arg, unsigned long); + + // + // If the value is negative, make it positive and indicate + // that a minus sign is needed. + // + if((long)ulValue < 0) + { + // + // Make the value positive. + // + ulValue = -(long)ulValue; + + // + // Indicate that the value is negative. + // + ulNeg = 1; + } + else + { + // + // Indicate that the value is positive so that a + // negative sign isn't inserted. + // + ulNeg = 0; + } + + // + // Set the base to 10. + // + ulBase = 10; + + // + // Convert the value to ASCII. + // + goto convert; + } + + // + // Handle the %s command. + // + case 's': + { + // + // Get the string pointer from the varargs. + // + pcStr = va_arg(arg, char *); + + // + // Determine the length of the string. + // + for(ulIdx = 0; pcStr[ulIdx] != '\0'; ulIdx++) + { + } + + // + // Update the convert count to include any padding that + // should be necessary (regardless of whether we have space + // to write it or not). + // + if(ulCount > ulIdx) + { + iConvertCount += (ulCount - ulIdx); + } + + // + // Copy the string to the output buffer. Only copy as much + // as will fit in the buffer. Update the output buffer + // pointer and the space remaining. + // + if(ulIdx > n) + { + ustrncpy(s, pcStr, n); + s += n; + n = 0; + } + else + { + ustrncpy(s, pcStr, ulIdx); + s += ulIdx; + n -= ulIdx; + + // + // Write any required padding spaces assuming there is + // still space in the buffer. + // + if(ulCount > ulIdx) + { + ulCount -= ulIdx; + if(ulCount > n) + { + ulCount = n; + } + n = -ulCount; + + while(ulCount--) + { + *s++ = ' '; + } + } + } + + // + // Update the conversion count. This will be the number of + // characters that should have been written, even if there + // was not room in the buffer. + // + iConvertCount += ulIdx; + + // + // This command has been handled. + // + break; + } + + // + // Handle the %u command. + // + case 'u': + { + // + // Get the value from the varargs. + // + ulValue = va_arg(arg, unsigned long); + + // + // Set the base to 10. + // + ulBase = 10; + + // + // Indicate that the value is positive so that a minus sign + // isn't inserted. + // + ulNeg = 0; + + // + // Convert the value to ASCII. + // + goto convert; + } + + // + // Handle the %x and %X commands. Note that they are treated + // identically; that is, %X will use lower case letters for a-f + // instead of the upper case letters is should use. We also + // alias %p to %x. + // + case 'x': + case 'X': + case 'p': + { + // + // Get the value from the varargs. + // + ulValue = va_arg(arg, unsigned long); + + // + // Set the base to 16. + // + ulBase = 16; + + // + // Indicate that the value is positive so that a minus sign + // isn't inserted. + // + ulNeg = 0; + + // + // Determine the number of digits in the string version of + // the value. + // +convert: + for(ulIdx = 1; + (((ulIdx * ulBase) <= ulValue) && + (((ulIdx * ulBase) / ulBase) == ulIdx)); + ulIdx *= ulBase, ulCount--) + { + } + + // + // If the value is negative, reduce the count of padding + // characters needed. + // + if(ulNeg) + { + ulCount--; + } + + // + // If the value is negative and the value is padded with + // zeros, then place the minus sign before the padding. + // + if(ulNeg && (n != 0) && (cFill == '0')) + { + // + // Place the minus sign in the output buffer. + // + *s++ = '-'; + n--; + + // + // Update the conversion count. + // + iConvertCount++; + + // + // The minus sign has been placed, so turn off the + // negative flag. + // + ulNeg = 0; + } + + // + // See if there are more characters in the specified field + // width than there are in the conversion of this value. + // + if((ulCount > 1) && (ulCount < 65536)) + { + // + // Loop through the required padding characters. + // + for(ulCount--; ulCount; ulCount--) + { + // + // Copy the character to the output buffer if there + // is room. + // + if(n != 0) + { + *s++ = cFill; + n--; + } + + // + // Update the conversion count. + // + iConvertCount++; + } + } + + // + // If the value is negative, then place the minus sign + // before the number. + // + if(ulNeg && (n != 0)) + { + // + // Place the minus sign in the output buffer. + // + *s++ = '-'; + n--; + + // + // Update the conversion count. + // + iConvertCount++; + } + + // + // Convert the value into a string. + // + for(; ulIdx; ulIdx /= ulBase) + { + // + // Copy the character to the output buffer if there is + // room. + // + if(n != 0) + { + *s++ = g_pcHex[(ulValue / ulIdx) % ulBase]; + n--; + } + + // + // Update the conversion count. + // + iConvertCount++; + } + + // + // This command has been handled. + // + break; + } + + // + // Handle the %% command. + // + case '%': + { + // + // Simply write a single %. + // + if(n != 0) + { + *s++ = format[-1]; + n--; + } + + // + // Update the conversion count. + // + iConvertCount++; + + // + // This command has been handled. + // + break; + } + + // + // Handle all other commands. + // + default: + { + // + // Indicate an error. + // + if(n >= 5) + { + ustrncpy(s, "ERROR", 5); + s += 5; + n -= 5; + } + else + { + ustrncpy(s, "ERROR", n); + s += n; + n = 0; + } + + // + // Update the conversion count. + // + iConvertCount += 5; + + // + // This command has been handled. + // + break; + } + } + } + } + + // + // Null terminate the string in the buffer. + // + *s = 0; + + // + // Return the number of characters in the full converted string. + // + return(iConvertCount); +} + +//***************************************************************************** +// +//! A simple sprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and \%X. +//! +//! \param s is the buffer where the converted string is stored. +//! \param format is the format string. +//! \param ... are the optional arguments, which depend on the contents of the +//! format string. +//! +//! This function is very similar to the C library <tt>sprintf()</tt> function. +//! Only the following formatting characters are supported: +//! +//! - \%c to print a character +//! - \%d or \%i to print a decimal value +//! - \%s to print a string +//! - \%u to print an unsigned decimal value +//! - \%x to print a hexadecimal value using lower case letters +//! - \%X to print a hexadecimal value using lower case letters (not upper case +//! letters as would typically be used) +//! - \%p to print a pointer as a hexadecimal value +//! - \%\% to print out a \% character +//! +//! For \%d, \%i, \%p, \%s, \%u, \%x, and \%X, an optional number may reside +//! between the \% and the format character, which specifies the minimum number +//! of characters to use for that value; if preceded by a 0 then the extra +//! characters will be filled with zeros instead of spaces. For example, +//! ``\%8d'' will use eight characters to print the decimal value with spaces +//! added to reach eight; ``\%08d'' will use eight characters as well but will +//! add zeros instead of spaces. +//! +//! The type of the arguments after \e format must match the requirements of +//! the format string. For example, if an integer was passed where a string +//! was expected, an error of some kind will most likely occur. +//! +//! The caller must ensure that the buffer \e s is large enough to hold the +//! entire converted string, including the null termination character. +//! +//! \return Returns the count of characters that were written to the output +//! buffer, not including the NULL termination character. +// +//***************************************************************************** +int +usprintf(char * restrict s, const char *format, ...) +{ + va_list arg; + int ret; + + // + // Start the varargs processing. + // + va_start(arg, format); + + // + // Call vsnprintf to perform the conversion. Use a large number for the + // buffer size. + // + ret = uvsnprintf(s, 0xffff, format, arg); + + // + // End the varargs processing. + // + va_end(arg); + + // + // Return the conversion count. + // + return(ret); +} + +//***************************************************************************** +// +//! A simple snprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and +//! \%X. +//! +//! \param s is the buffer where the converted string is stored. +//! \param n is the size of the buffer. +//! \param format is the format string. +//! \param ... are the optional arguments, which depend on the contents of the +//! format string. +//! +//! This function is very similar to the C library <tt>sprintf()</tt> function. +//! Only the following formatting characters are supported: +//! +//! - \%c to print a character +//! - \%d or \%i to print a decimal value +//! - \%s to print a string +//! - \%u to print an unsigned decimal value +//! - \%x to print a hexadecimal value using lower case letters +//! - \%X to print a hexadecimal value using lower case letters (not upper case +//! letters as would typically be used) +//! - \%p to print a pointer as a hexadecimal value +//! - \%\% to print out a \% character +//! +//! For \%d, \%i, \%p, \%s, \%u, \%x, and \%X, an optional number may reside +//! between the \% and the format character, which specifies the minimum number +//! of characters to use for that value; if preceded by a 0 then the extra +//! characters will be filled with zeros instead of spaces. For example, +//! ``\%8d'' will use eight characters to print the decimal value with spaces +//! added to reach eight; ``\%08d'' will use eight characters as well but will +//! add zeros instead of spaces. +//! +//! The type of the arguments after \e format must match the requirements of +//! the format string. For example, if an integer was passed where a string +//! was expected, an error of some kind will most likely occur. +//! +//! The function will copy at most \e n - 1 characters into the buffer +//! \e s. One space is reserved in the buffer for the null termination +//! character. +//! +//! The function will return the number of characters that would be converted +//! as if there were no limit on the buffer size. Therefore it is possible for +//! the function to return a count that is greater than the specified buffer +//! size. If this happens, it means that the output was truncated. +//! +//! \return Returns the number of characters that were to be stored, not +//! including the NULL termination character, regardless of space in the +//! buffer. +// +//***************************************************************************** +int +usnprintf(char * restrict s, size_t n, const char * restrict format, ...) +{ + va_list arg; + int ret; + + // + // Start the varargs processing. + // + va_start(arg, format); + + // + // Call vsnprintf to perform the conversion. + // + ret = uvsnprintf(s, n, format, arg); + + // + // End the varargs processing. + // + va_end(arg); + + // + // Return the conversion count. + // + return(ret); +} + +//***************************************************************************** +// +// This array contains the number of days in a year at the beginning of each +// month of the year, in a non-leap year. +// +//***************************************************************************** +static const time_t g_psDaysToMonth[12] = +{ + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 +}; + +//***************************************************************************** +// +//! Converts from seconds to calendar date and time. +//! +//! \param timer is the number of seconds. +//! \param tm is a pointer to the time structure that is filled in with the +//! broken down date and time. +//! +//! This function converts a number of seconds since midnight GMT on January 1, +//! 1970 (traditional Unix epoch) into the equivalent month, day, year, hours, +//! minutes, and seconds representation. +//! +//! \return None. +// +//***************************************************************************** +void +ulocaltime(time_t timer, struct tm *tm) +{ + time_t temp, months; + + // + // Extract the number of seconds, converting time to the number of minutes. + // + temp = timer / 60; + tm->tm_sec = timer - (temp * 60); + timer = temp; + + // + // Extract the number of minutes, converting time to the number of hours. + // + temp = timer / 60; + tm->tm_min = timer - (temp * 60); + timer = temp; + + // + // Extract the number of hours, converting time to the number of days. + // + temp = timer / 24; + tm->tm_hour = timer - (temp * 24); + timer = temp; + + // + // Compute the day of the week. + // + tm->tm_wday = (timer + 4) % 7; + + // + // Compute the number of leap years that have occurred since 1968, the + // first leap year before 1970. For the beginning of a leap year, cut the + // month loop below at March so that the leap day is classified as February + // 29 followed by March 1, instead of March 1 followed by another March 1. + // + timer += 366 + 365; + temp = timer / ((4 * 365) + 1); + if((timer - (temp * ((4 * 365) + 1))) > (31 + 28)) + { + temp++; + months = 12; + } + else + { + months = 2; + } + + // + // Extract the year. + // + tm->tm_year = ((timer - temp) / 365) + 68; + timer -= ((tm->tm_year - 68) * 365) + temp; + + // + // Extract the month. + // + for(temp = 0; temp < months; temp++) + { + if(g_psDaysToMonth[temp] > timer) + { + break; + } + } + tm->tm_mon = temp - 1; + + // + // Extract the day of the month. + // + tm->tm_mday = timer - g_psDaysToMonth[temp - 1] + 1; +} + +//***************************************************************************** +// +//! Compares two time structures and determines if one is greater than, +//! less than, or equal to the other. +//! +//! \param t1 is the first time structure to compare. +//! \param t2 is the second time structure to compare. +//! +//! This function compares two time structures and returns a signed number +//! to indicate the result of the comparison. If the time represented by +//! \e t1 is greater than the time represented by \e t2 then a positive +//! number is returned. Likewise if \e t1 is less than \e t2 then a +//! negative number is returned. If the two times are equal then the function +//! returns 0. +//! +//! \return Returns 0 if the two times are equal, +1 if \e t1 is greater +//! than \e t2, and -1 if \e t1 is less than \e t2. +// +//***************************************************************************** +static int +ucmptime(struct tm *t1, struct tm *t2) +{ + // + // Compare each field in descending signficance to determine if + // greater than, less than, or equal. + // + if(t1->tm_year > t2->tm_year) + { + return(1); + } + else if(t1->tm_year < t2->tm_year) + { + return(-1); + } + else if(t1->tm_mon > t2->tm_mon) + { + return(1); + } + else if(t1->tm_mon < t2->tm_mon) + { + return(-1); + } + else if(t1->tm_mday > t2->tm_mday) + { + return(1); + } + else if(t1->tm_mday < t2->tm_mday) + { + return(-1); + } + else if(t1->tm_hour > t2->tm_hour) + { + return(1); + } + else if(t1->tm_hour < t2->tm_hour) + { + return(-1); + } + else if(t1->tm_min > t2->tm_min) + { + return(1); + } + else if(t1->tm_min < t2->tm_min) + { + return(-1); + } + else if(t1->tm_sec > t2->tm_sec) + { + return(1); + } + else if(t1->tm_sec < t2->tm_sec) + { + return(-1); + } + else + { + // + // Reaching this branch of the conditional means that all of the + // fields are equal, and thus the two times are equal. + // + return(0); + } +} + +//***************************************************************************** +// +//! Converts calendar date and time to seconds. +//! +//! \param timeptr is a pointer to the time structure that is filled in with +//! the broken down date and time. +//! +//! This function converts the date and time represented by the \e timeptr +//! structure pointer to the number of seconds since midnight GMT on January 1, +//! 1970 (traditional Unix epoch). +//! +//! \return Returns the calendar time and date as seconds. If the conversion +//! was not possible then the function returns (uint32_t)(-1). +// +//***************************************************************************** +time_t +umktime(struct tm *timeptr) +{ + struct tm sTimeGuess; + unsigned long ulTimeGuess = 0x80000000; + unsigned long ulAdjust = 0x40000000; + int iSign; + + // + // Seed the binary search with the first guess. + // + ulocaltime(ulTimeGuess, &sTimeGuess); + iSign = ucmptime(timeptr, &sTimeGuess); + + // + // While the time is not yet found, execute a binary search. + // + while(iSign && ulAdjust) + { + // + // Adjust the time guess up or down depending on the result of the + // last compare. + // + ulTimeGuess = ((iSign > 0) ? (ulTimeGuess + ulAdjust) : + (ulTimeGuess - ulAdjust)); + ulAdjust /= 2; + + // + // Compare the new time guess against the time pointed at by the + // function parameters. + // + ulocaltime(ulTimeGuess, &sTimeGuess); + iSign = ucmptime(timeptr, &sTimeGuess); + } + + // + // If the above loop was exited with iSign == 0, that means that the + // time in seconds was found, so return that value to the caller. + // + if(iSign == 0) + { + return(ulTimeGuess); + } + + // + // Otherwise the time could not be converted so return an error. + // + else + { + return((unsigned long)-1); + } +} + +//***************************************************************************** +// +//! Converts a string into its numeric equivalent. +//! +//! \param nptr is a pointer to the string containing the integer. +//! \param endptr is a pointer that will be set to the first character past +//! the integer in the string. +//! \param base is the radix to use for the conversion; can be zero to +//! auto-select the radix or between 2 and 16 to explicitly specify the radix. +//! +//! This function is very similar to the C library <tt>strtoul()</tt> function. +//! It scans a string for the first token (that is, non-white space) and +//! converts the value at that location in the string into an integer value. +//! +//! \return Returns the result of the conversion. +// +//***************************************************************************** +unsigned long +ustrtoul(const char * restrict nptr, const char ** restrict endptr, int base) +{ + unsigned long ulRet, ulDigit, ulNeg, ulValid; + const char *pcPtr; + + // + // Check the arguments. + // + ASSERT(nptr); + ASSERT((base == 0) || ((base > 1) && (base <= 16))); + + // + // Initially, the result is zero. + // + ulRet = 0; + ulNeg = 0; + ulValid = 0; + + // + // Skip past any leading white space. + // + pcPtr = nptr; + while((*pcPtr == ' ') || (*pcPtr == '\t')) + { + pcPtr++; + } + + // + // Take a leading + or - from the value. + // + if(*pcPtr == '-') + { + ulNeg = 1; + pcPtr++; + } + else if(*pcPtr == '+') + { + pcPtr++; + } + + // + // See if the radix was not specified, or is 16, and the value starts with + // "0x" or "0X" (to indicate a hex value). + // + if(((base == 0) || (base == 16)) && (*pcPtr == '0') && + ((pcPtr[1] == 'x') || (pcPtr[1] == 'X'))) + { + // + // Skip the leading "0x". + // + pcPtr += 2; + + // + // Set the radix to 16. + // + base = 16; + } + + // + // See if the radix was not specified. + // + if(base == 0) + { + // + // See if the value starts with "0". + // + if(*pcPtr == '0') + { + // + // Values that start with "0" are assumed to be radix 8. + // + base = 8; + } + else + { + // + // Otherwise, the values are assumed to be radix 10. + // + base = 10; + } + } + + // + // Loop while there are more valid digits to consume. + // + while(1) + { + // + // See if this character is a number. + // + if((*pcPtr >= '0') && (*pcPtr <= '9')) + { + // + // Convert the character to its integer equivalent. + // + ulDigit = *pcPtr++ - '0'; + } + + // + // Otherwise, see if this character is an upper case letter. + // + else if((*pcPtr >= 'A') && (*pcPtr <= 'Z')) + { + // + // Convert the character to its integer equivalent. + // + ulDigit = *pcPtr++ - 'A' + 10; + } + + // + // Otherwise, see if this character is a lower case letter. + // + else if((*pcPtr >= 'a') && (*pcPtr <= 'z')) + { + // + // Convert the character to its integer equivalent. + // + ulDigit = *pcPtr++ - 'a' + 10; + } + + // + // Otherwise, this is not a valid character. + // + else + { + // + // Stop converting this value. + // + break; + } + + // + // See if this digit is valid for the chosen radix. + // + if(ulDigit >= base) + { + // + // Since this was not a valid digit, move the pointer back to the + // character that therefore should not have been consumed. + // + pcPtr--; + + // + // Stop converting this value. + // + break; + } + + // + // Add this digit to the converted value. + // + ulRet *= base; + ulRet += ulDigit; + + // + // Since a digit has been added, this is now a valid result. + // + ulValid = 1; + } + + // + // Set the return string pointer to the first character not consumed. + // + if(endptr) + { + *endptr = ulValid ? pcPtr : nptr; + } + + // + // Return the converted value. + // + return(ulNeg ? (0 - ulRet) : ulRet); +} + +//***************************************************************************** +// +// An array of the value of ten raised to the power-of-two exponents. This is +// used for converting the decimal exponent into the floating-point value of +// 10^exp. +// +//***************************************************************************** +static const float g_pfExponents[] = +{ + 1.0e+01, + 1.0e+02, + 1.0e+04, + 1.0e+08, + 1.0e+16, + 1.0e+32, +}; + +//***************************************************************************** +// +//! Converts a string into its floating-point equivalent. +//! +//! \param nptr is a pointer to the string containing the floating-point +//! value. +//! \param endptr is a pointer that will be set to the first character past +//! the floating-point value in the string. +//! +//! This function is very similar to the C library <tt>strtof()</tt> function. +//! It scans a string for the first token (that is, non-white space) and +//! converts the value at that location in the string into a floating-point +//! value. +//! +//! \return Returns the result of the conversion. +// +//***************************************************************************** +float +ustrtof(const char *nptr, const char **endptr) +{ + unsigned long ulNeg, ulValid; + float fRet; + const char *pcPtr; + + // + // Check the arguments. + // + ASSERT(nptr); + + // + // Initially, the result is zero. + // + fRet = 0; + ulNeg = 0; + ulValid = 0; + + // + // Skip past any leading white space. + // + pcPtr = nptr; + while((*pcPtr == ' ') || (*pcPtr == '\t')) + { + pcPtr++; + } + + // + // Take a leading + or - from the value. + // + if(*pcPtr == '-') + { + ulNeg = 1; + pcPtr++; + } + else if(*pcPtr == '+') + { + pcPtr++; + } + + // + // Loop while there are valid digits to consume. + // + while((*pcPtr >= '0') && (*pcPtr <= '9')) + { + // + // Add this digit to the converted value. + // + fRet *= 10; + fRet += *pcPtr++ - '0'; + + // + // Since a digit has been added, this is now a valid result. + // + ulValid = 1; + } + + // + // See if the next character is a period and the character after that is a + // digit, indicating the start of the fractional portion of the value. + // + if((*pcPtr == '.') && (pcPtr[1] >= '0') && (pcPtr[1] <= '9')) + { + // + // Skip the period. + // + pcPtr++; + + // + // Loop while there are valid fractional digits to consume. + // + float fDigit = 0.1; + while((*pcPtr >= '0') && (*pcPtr <= '9')) + { + // + // Add this digit to the converted value. + // + fRet += (*pcPtr++ - '0') * fDigit; + fDigit /= (float)10.0; + + // + // Since a digit has been added, this is now a valid result. + // + ulValid = 1; + } + } + + // + // See if the next character is an "e" and a valid number has been + // converted, indicating the start of the exponent. + // + if(((pcPtr[0] == 'e') || (pcPtr[0] == 'E')) && (ulValid == 1) && + (((pcPtr[1] >= '0') && (pcPtr[1] <= '9')) || + (((pcPtr[1] == '+') || (pcPtr[1] == '-')) && + (pcPtr[2] >= '0') && (pcPtr[2] <= '9')))) + { + // + // Skip the "e". + // + pcPtr++; + + // + // Take a leading + or - from the exponenet. + // + unsigned long ulExpNeg = 0; + if(*pcPtr == '-') + { + ulExpNeg = 1; + pcPtr++; + } + else if(*pcPtr == '+') + { + pcPtr++; + } + + // + // Loop while there are valid digits in the exponent. + // + unsigned long ulExp = 0; + while((*pcPtr >= '0') && (*pcPtr <= '9')) + { + // + // Add this digit to the converted value. + // + ulExp *= 10; + ulExp += *pcPtr++ - '0'; + } + + // + // Raise ten to the power of the exponent. Do this via binary + // decomposition; for each binary bit set in the exponent, multiply the + // floating-point representation by ten raised to that binary value + // (extracted from the table above). + // + float fExp = 1; + unsigned long ulIdx = 0; + for(; ulIdx < 7; ulIdx++) + { + if(ulExp & (1 << ulIdx)) + { + fExp *= g_pfExponents[ulIdx]; + } + } + + // + // If the exponent is negative, then the exponent needs to be inverted. + // + if(ulExpNeg == 1) + { + fExp = 1 / fExp; + } + + // + // Multiply the result by the computed exponent value. + // + fRet *= fExp; + } + + // + // Set the return string pointer to the first character not consumed. + // + if(endptr) + { + *endptr = ulValid ? pcPtr : nptr; + } + + // + // Return the converted value. + // + return(ulNeg ? (0 - fRet) : fRet); +} + +//***************************************************************************** +// +//! Returns the length of a null-terminated string. +//! +//! \param s is a pointer to the string whose length is to be found. +//! +//! This function is very similar to the C library <tt>strlen()</tt> function. +//! It determines the length of the null-terminated string passed and returns +//! this to the caller. +//! +//! This implementation assumes that single byte character strings are passed +//! and will return incorrect values if passed some UTF-8 strings. +//! +//! \return Returns the length of the string pointed to by \e s. +// +//***************************************************************************** +size_t +ustrlen(const char *s) +{ + size_t len; + + // + // Check the arguments. + // + ASSERT(s); + + // + // Initialize the length. + // + len = 0; + + // + // Step throug the string looking for a zero character (marking its end). + // + while(s[len]) + { + // + // Zero not found so move on to the next character. + // + len++; + } + + return(len); +} + +//***************************************************************************** +// +//! Finds a substring within a string. +//! +//! \param s1 is a pointer to the string that will be searched. +//! \param s2 is a pointer to the substring that is to be found within +//! \e s1. +//! +//! This function is very similar to the C library <tt>strstr()</tt> function. +//! It scans a string for the first instance of a given substring and returns +//! a pointer to that substring. If the substring cannot be found, a NULL +//! pointer is returned. +//! +//! \return Returns a pointer to the first occurrence of \e s2 within +//! \e s1 or NULL if no match is found. +// +//***************************************************************************** +char * +ustrstr(const char *s1, const char *s2) +{ + size_t n; + + // + // Get the length of the string to be found. + // + n = ustrlen(s2); + + // + // Loop while we have not reached the end of the string. + // + while(*s1) + { + // + // Check to see if the substring appears at this position. + // + if(ustrncmp(s2, s1, n) == 0) + { + // + // It does so return the pointer. + // + return((char *)s1); + } + + // + // Move to the next position in the string being searched. + // + s1++; + } + + // + // We reached the end of the string without finding the substring so + // return NULL. + // + return((char *)0); +} + +//***************************************************************************** +// +//! Compares two strings without regard to case. +//! +//! \param s1 points to the first string to be compared. +//! \param s2 points to the second string to be compared. +//! \param n is the maximum number of characters to compare. +//! +//! This function is very similar to the C library <tt>strncasecmp()</tt> +//! function. It compares at most \e n characters of two strings without +//! regard to case. The comparison ends if a terminating NULL character is +//! found in either string before \e n characters are compared. In this case, +//! the shorter string is deemed the lesser. +//! +//! \return Returns 0 if the two strings are equal, -1 if \e s1 is less +//! than \e s2 and 1 if \e s1 is greater than \e s2. +// +//***************************************************************************** +int +ustrncasecmp(const char *s1, const char *s2, size_t n) +{ + // + // Loop while there are more characters to compare. + // + while(n) + { + // + // If we reached a NULL in both strings, they must be equal so + // we end the comparison and return 0 + // + if(!*s1 && !*s2) + { + return(0); + } + + // + // Lower case the characters at the current position before we compare. + // + char c1 = (((*s1 >= 'A') && (*s1 <= 'Z')) ? (*s1 + ('a' - 'A')) : *s1); + char c2 = (((*s2 >= 'A') && (*s2 <= 'Z')) ? (*s2 + ('a' - 'A')) : *s2); + + // + // Compare the two characters and, if different, return the relevant + // return code. + // + if(c2 < c1) + { + return(1); + } + if(c1 < c2) + { + return(-1); + } + + // + // Move on to the next character. + // + s1++; + s2++; + n--; + } + + // + // If we fall out, the strings must be equal for at least the first n + // characters so return 0 to indicate this. + // + return(0); +} + +//***************************************************************************** +// +//! Compares two strings without regard to case. +//! +//! \param s1 points to the first string to be compared. +//! \param s2 points to the second string to be compared. +//! +//! This function is very similar to the C library <tt>strcasecmp()</tt> +//! function. It compares two strings without regard to case. The comparison +//! ends if a terminating NULL character is found in either string. In this +//! case, the int16_ter string is deemed the lesser. +//! +//! \return Returns 0 if the two strings are equal, -1 if \e s1 is less +//! than \e s2 and 1 if \e s1 is greater than \e s2. +// +//***************************************************************************** +int +ustrcasecmp(const char *s1, const char *s2) +{ + // + // Just let ustrncasecmp() handle this. + // + return(ustrncasecmp(s1, s2, (size_t)-1)); +} + +//***************************************************************************** +// +//! Compares two strings. +//! +//! \param s1 points to the first string to be compared. +//! \param s2 points to the second string to be compared. +//! \param n is the maximum number of characters to compare. +//! +//! This function is very similar to the C library <tt>strncmp()</tt> function. +//! It compares at most \e n characters of two strings taking case into +//! account. The comparison ends if a terminating NULL character is found in +//! either string before \e n characters are compared. In this case, the +//! int16_ter string is deemed the lesser. +//! +//! \return Returns 0 if the two strings are equal, -1 if \e s1 is less +//! than \e s2 and 1 if \e s1 is greater than \e s2. +// +//***************************************************************************** +int +ustrncmp(const char *s1, const char *s2, size_t n) +{ + // + // Loop while there are more characters. + // + while(n) + { + // + // If we reached a NULL in both strings, they must be equal so we end + // the comparison and return 0 + // + if(!*s1 && !*s2) + { + return(0); + } + + // + // Compare the two characters and, if different, return the relevant + // return code. + // + if(*s2 < *s1) + { + return(1); + } + if(*s1 < *s2) + { + return(-1); + } + + // + // Move on to the next character. + // + s1++; + s2++; + n--; + } + + // + // If we fall out, the strings must be equal for at least the first n + // characters so return 0 to indicate this. + // + return(0); +} + +//***************************************************************************** +// +//! Compares two strings. +//! +//! \param s1 points to the first string to be compared. +//! \param s2 points to the second string to be compared. +//! +//! This function is very similar to the C library <tt>strcmp()</tt> +//! function. It compares two strings, taking case into account. The +//! comparison ends if a terminating NULL character is found in either string. +//! In this case, the int16_ter string is deemed the lesser. +//! +//! \return Returns 0 if the two strings are equal, -1 if \e s1 is less +//! than \e s2 and 1 if \e s1 is greater than \e s2. +// +//***************************************************************************** +int +ustrcmp(const char *s1, const char *s2) +{ + // + // Pass this on to ustrncmp. + // + return(ustrncmp(s1, s2, (size_t)-1)); +} + +//***************************************************************************** +// +// Random Number Generator Seed Value +// +//***************************************************************************** +static unsigned int g_iRandomSeed = 1; + +//***************************************************************************** +// +//! Set the random number generator seed. +//! +//! \param seed is the new seed value to use for the random number +//! generator. +//! +//! This function is very similar to the C library <tt>srand()</tt> function. +//! It will set the seed value used in the <tt>urand()</tt> function. +//! +//! \return None +// +//***************************************************************************** +void +usrand(unsigned int seed) +{ + g_iRandomSeed = seed; +} + +//***************************************************************************** +// +//! Generate a new (pseudo) random number +//! +//! This function is very similar to the C library <tt>rand()</tt> function. +//! It will generate a pseudo-random number sequence based on the seed value. +//! +//! \return A pseudo-random number will be returned. +// +//***************************************************************************** +int +urand(void) +{ + // + // Generate a new pseudo-random number with a linear congruence random + // number generator. This new random number becomes the seed for the next + // random number. + // + g_iRandomSeed = (g_iRandomSeed * 1664525) + 1013904223; + + // + // Return the new random number. + // + return((int)g_iRandomSeed); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/Software/Embedded_SW/Embedded/Common/protobuf-c/person-pb-c.c b/Software/Embedded_SW/Embedded/Common/protobuf-c/person-pb-c.c new file mode 100644 index 000000000..7493ef609 --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/protobuf-c/person-pb-c.c @@ -0,0 +1,227 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: person.proto */ + +/* Do not generate deprecated warnings for self */ +#ifndef PROTOBUF_C__NO_DEPRECATED +#define PROTOBUF_C__NO_DEPRECATED +#endif + +#include "person-pb-c.h" +void address__init + (Address *message) +{ + static const Address init_value = ADDRESS__INIT; + *message = init_value; +} +size_t address__get_packed_size + (const Address *message) +{ + assert(message->base.descriptor == &address__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t address__pack + (const Address *message, + uint8_t *out) +{ + assert(message->base.descriptor == &address__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t address__pack_to_buffer + (const Address *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &address__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +Address * + address__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (Address *) + protobuf_c_message_unpack (&address__descriptor, + allocator, len, data); +} +void address__free_unpacked + (Address *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &address__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void person__init + (Person *message) +{ + static const Person init_value = PERSON__INIT; + *message = init_value; +} +size_t person__get_packed_size + (const Person *message) +{ + assert(message->base.descriptor == &person__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t person__pack + (const Person *message, + uint8_t *out) +{ + assert(message->base.descriptor == &person__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t person__pack_to_buffer + (const Person *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &person__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +Person * + person__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (Person *) + protobuf_c_message_unpack (&person__descriptor, + allocator, len, data); +} +void person__free_unpacked + (Person *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &person__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +static const ProtobufCFieldDescriptor address__field_descriptors[2] = +{ + { + "street", + 1, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(Address, street), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "number", + 2, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_INT32, + offsetof(Address, has_number), + offsetof(Address, number), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned address__field_indices_by_name[] = { + 1, /* field[1] = number */ + 0, /* field[0] = street */ +}; +static const ProtobufCIntRange address__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor address__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "Address", + "Address", + "Address", + "", + sizeof(Address), + 2, + address__field_descriptors, + address__field_indices_by_name, + 1, address__number_ranges, + (ProtobufCMessageInit) address__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor person__field_descriptors[4] = +{ + { + "name", + 1, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(Person, name), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "age", + 2, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_INT32, + offsetof(Person, has_age), + offsetof(Person, age), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "email", + 3, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(Person, email), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "address", + 4, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(Person, n_address), + offsetof(Person, address), + &address__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned person__field_indices_by_name[] = { + 3, /* field[3] = address */ + 1, /* field[1] = age */ + 2, /* field[2] = email */ + 0, /* field[0] = name */ +}; +static const ProtobufCIntRange person__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 4 } +}; +const ProtobufCMessageDescriptor person__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "Person", + "Person", + "Person", + "", + sizeof(Person), + 4, + person__field_descriptors, + person__field_indices_by_name, + 1, person__number_ranges, + (ProtobufCMessageInit) person__init, + NULL,NULL,NULL /* reserved[123] */ +}; diff --git a/Software/Embedded_SW/Embedded/Common/protobuf-c/person-pb-c.h b/Software/Embedded_SW/Embedded/Common/protobuf-c/person-pb-c.h new file mode 100644 index 000000000..87b0007b1 --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/protobuf-c/person-pb-c.h @@ -0,0 +1,112 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: person.proto */ + +#ifndef PROTOBUF_C_person_2eproto__INCLUDED +#define PROTOBUF_C_person_2eproto__INCLUDED + +#include <protobuf-c.h> + +PROTOBUF_C__BEGIN_DECLS + +#if PROTOBUF_C_VERSION_NUMBER < 1003000 +# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. +#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION +# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. +#endif + + +typedef struct _Address Address; +typedef struct _Person Person; + + +/* --- enums --- */ + + +/* --- messages --- */ + +struct _Address +{ + ProtobufCMessage base; + char *street; + protobuf_c_boolean has_number; + int32_t number; +}; +#define ADDRESS__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&address__descriptor) \ + , NULL, 0, 0 } + + +struct _Person +{ + ProtobufCMessage base; + char *name; + protobuf_c_boolean has_age; + int32_t age; + char *email; + size_t n_address; + Address **address; +}; +#define PERSON__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&person__descriptor) \ + , NULL, 0, 0, NULL, 0,NULL } + + +/* Address methods */ +void address__init + (Address *message); +size_t address__get_packed_size + (const Address *message); +size_t address__pack + (const Address *message, + uint8_t *out); +size_t address__pack_to_buffer + (const Address *message, + ProtobufCBuffer *buffer); +Address * + address__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void address__free_unpacked + (Address *message, + ProtobufCAllocator *allocator); +/* Person methods */ +void person__init + (Person *message); +size_t person__get_packed_size + (const Person *message); +size_t person__pack + (const Person *message, + uint8_t *out); +size_t person__pack_to_buffer + (const Person *message, + ProtobufCBuffer *buffer); +Person * + person__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void person__free_unpacked + (Person *message, + ProtobufCAllocator *allocator); +/* --- per-message closures --- */ + +typedef void (*Address_Closure) + (const Address *message, + void *closure_data); +typedef void (*Person_Closure) + (const Person *message, + void *closure_data); + +/* --- services --- */ + + +/* --- descriptors --- */ + +extern const ProtobufCMessageDescriptor address__descriptor; +extern const ProtobufCMessageDescriptor person__descriptor; + +PROTOBUF_C__END_DECLS + + +#endif /* PROTOBUF_C_person_2eproto__INCLUDED */ diff --git a/Software/Embedded_SW/Embedded/Common/protobuf-c/protobuf-c.c b/Software/Embedded_SW/Embedded/Common/protobuf-c/protobuf-c.c new file mode 100644 index 000000000..5debac820 --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/protobuf-c/protobuf-c.c @@ -0,0 +1,3642 @@ +/* + * Copyright (c) 2008-2015, Dave Benson and the protobuf-c authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*! \file + * Support library for `protoc-c` generated code. + * + * This file implements the public API used by the code generated + * by `protoc-c`. + * + * \authors Dave Benson and the protobuf-c authors + * + * \copyright 2008-2014. Licensed under the terms of the [BSD-2-Clause] license. + */ + +/** + * \todo 64-BIT OPTIMIZATION: certain implementations use 32-bit math + * even on 64-bit platforms (uint64_size, uint64_pack, parse_uint64). + * + * \todo Use size_t consistently. + */ + +#include <stdlib.h> /* for malloc, free */ +#include <string.h> /* for strcmp, strlen, memcpy, memmove, memset */ + +#include "protobuf-c.h" + +#define TRUE 1 +#define FALSE 0 + +#define PROTOBUF_C__ASSERT_NOT_REACHED() assert(0) + +/* Workaround for Microsoft compilers. */ +#ifdef _MSC_VER +# define inline __inline +#endif + +/** + * \defgroup internal Internal functions and macros + * + * These are not exported by the library but are useful to developers working + * on `libprotobuf-c` itself. + */ + +/** + * \defgroup macros Utility macros for manipulating structures + * + * Macros and constants used to manipulate the base "classes" generated by + * `protobuf-c`. They also define limits and check correctness. + * + * \ingroup internal + * @{ + */ + +/** The maximum length of a 64-bit integer in varint encoding. */ +#define MAX_UINT64_ENCODED_SIZE 10 + +#ifndef PROTOBUF_C_UNPACK_ERROR +# define PROTOBUF_C_UNPACK_ERROR(...) +#endif + +const char protobuf_c_empty_string[] = ""; + +/** + * Internal `ProtobufCMessage` manipulation macro. + * + * Base macro for manipulating a `ProtobufCMessage`. Used by STRUCT_MEMBER() and + * STRUCT_MEMBER_PTR(). + */ +#define STRUCT_MEMBER_P(struct_p, struct_offset) \ + ((void *) ((uint8_t *) (struct_p) + (struct_offset))) + +/** + * Return field in a `ProtobufCMessage` based on offset. + * + * Take a pointer to a `ProtobufCMessage` and find the field at the offset. + * Cast it to the passed type. + */ +#define STRUCT_MEMBER(member_type, struct_p, struct_offset) \ + (*(member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset))) + +/** + * Return field in a `ProtobufCMessage` based on offset. + * + * Take a pointer to a `ProtobufCMessage` and find the field at the offset. Cast + * it to a pointer to the passed type. + */ +#define STRUCT_MEMBER_PTR(member_type, struct_p, struct_offset) \ + ((member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset))) + +/* Assertions for magic numbers. */ + +#define ASSERT_IS_ENUM_DESCRIPTOR(desc) \ + assert((desc)->magic == PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC) + +#define ASSERT_IS_MESSAGE_DESCRIPTOR(desc) \ + assert((desc)->magic == PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) + +#define ASSERT_IS_MESSAGE(message) \ + ASSERT_IS_MESSAGE_DESCRIPTOR((message)->descriptor) + +#define ASSERT_IS_SERVICE_DESCRIPTOR(desc) \ + assert((desc)->magic == PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC) + +/**@}*/ + +/* --- version --- */ + +const char * +protobuf_c_version(void) +{ + return PROTOBUF_C_VERSION; +} + +uint32_t +protobuf_c_version_number(void) +{ + return PROTOBUF_C_VERSION_NUMBER; +} + +/* --- allocator --- */ + +static void * +system_alloc(void *allocator_data, size_t size) +{ + return malloc(size); +} + +static void +system_free(void *allocator_data, void *data) +{ + free(data); +} + +static inline void * +do_alloc(ProtobufCAllocator *allocator, size_t size) +{ + return allocator->alloc(allocator->allocator_data, size); +} + +static inline void +do_free(ProtobufCAllocator *allocator, void *data) +{ + if (data != NULL) + allocator->free(allocator->allocator_data, data); +} + +/* + * This allocator uses the system's malloc() and free(). It is the default + * allocator used if NULL is passed as the ProtobufCAllocator to an exported + * function. + */ +static ProtobufCAllocator protobuf_c__allocator = { + .alloc = &system_alloc, + .free = &system_free, + .allocator_data = NULL, +}; + +/* === buffer-simple === */ + +void +protobuf_c_buffer_simple_append(ProtobufCBuffer *buffer, + size_t len, const uint8_t *data) +{ + ProtobufCBufferSimple *simp = (ProtobufCBufferSimple *) buffer; + size_t new_len = simp->len + len; + + if (new_len > simp->alloced) { + ProtobufCAllocator *allocator = simp->allocator; + size_t new_alloced = simp->alloced * 2; + uint8_t *new_data; + + if (allocator == NULL) + allocator = &protobuf_c__allocator; + while (new_alloced < new_len) + new_alloced += new_alloced; + new_data = do_alloc(allocator, new_alloced); + if (!new_data) + return; + memcpy(new_data, simp->data, simp->len); + if (simp->must_free_data) + do_free(allocator, simp->data); + else + simp->must_free_data = TRUE; + simp->data = new_data; + simp->alloced = new_alloced; + } + memcpy(simp->data + simp->len, data, len); + simp->len = new_len; +} + +/** + * \defgroup packedsz protobuf_c_message_get_packed_size() implementation + * + * Routines mainly used by protobuf_c_message_get_packed_size(). + * + * \ingroup internal + * @{ + */ + +/** + * Return the number of bytes required to store the tag for the field. Includes + * 3 bits for the wire-type, and a single bit that denotes the end-of-tag. + * + * \param number + * Field tag to encode. + * \return + * Number of bytes required. + */ +static inline size_t +get_tag_size(uint32_t number) +{ + if (number < (1UL << 4)) { + return 1; + } else if (number < (1UL << 11)) { + return 2; + } else if (number < (1UL << 18)) { + return 3; + } else if (number < (1UL << 25)) { + return 4; + } else { + return 5; + } +} + +/** + * Return the number of bytes required to store a variable-length unsigned + * 32-bit integer in base-128 varint encoding. + * + * \param v + * Value to encode. + * \return + * Number of bytes required. + */ +static inline size_t +uint32_size(uint32_t v) +{ + if (v < (1UL << 7)) { + return 1; + } else if (v < (1UL << 14)) { + return 2; + } else if (v < (1UL << 21)) { + return 3; + } else if (v < (1UL << 28)) { + return 4; + } else { + return 5; + } +} + +/** + * Return the number of bytes required to store a variable-length signed 32-bit + * integer in base-128 varint encoding. + * + * \param v + * Value to encode. + * \return + * Number of bytes required. + */ +static inline size_t +int32_size(int32_t v) +{ + if (v < 0) { + return 10; + } else if (v < (1L << 7)) { + return 1; + } else if (v < (1L << 14)) { + return 2; + } else if (v < (1L << 21)) { + return 3; + } else if (v < (1L << 28)) { + return 4; + } else { + return 5; + } +} + +/** + * Return the ZigZag-encoded 32-bit unsigned integer form of a 32-bit signed + * integer. + * + * \param v + * Value to encode. + * \return + * ZigZag encoded integer. + */ +static inline uint32_t +zigzag32(int32_t v) +{ + if (v < 0) + return (-(uint32_t)v) * 2 - 1; + else + return (uint32_t)(v) * 2; +} + +/** + * Return the number of bytes required to store a signed 32-bit integer, + * converted to an unsigned 32-bit integer with ZigZag encoding, using base-128 + * varint encoding. + * + * \param v + * Value to encode. + * \return + * Number of bytes required. + */ +static inline size_t +sint32_size(int32_t v) +{ + return uint32_size(zigzag32(v)); +} + +/** + * Return the number of bytes required to store a 64-bit unsigned integer in + * base-128 varint encoding. + * + * \param v + * Value to encode. + * \return + * Number of bytes required. + */ +static inline size_t +uint64_size(uint64_t v) +{ + uint32_t upper_v = (uint32_t) (v >> 32); + + if (upper_v == 0) { + return uint32_size((uint32_t) v); + } else if (upper_v < (1UL << 3)) { + return 5; + } else if (upper_v < (1UL << 10)) { + return 6; + } else if (upper_v < (1UL << 17)) { + return 7; + } else if (upper_v < (1UL << 24)) { + return 8; + } else if (upper_v < (1UL << 31)) { + return 9; + } else { + return 10; + } +} + +/** + * Return the ZigZag-encoded 64-bit unsigned integer form of a 64-bit signed + * integer. + * + * \param v + * Value to encode. + * \return + * ZigZag encoded integer. + */ +static inline uint64_t +zigzag64(int64_t v) +{ + if (v < 0) + return (-(uint64_t)v) * 2 - 1; + else + return (uint64_t)(v) * 2; +} + +/** + * Return the number of bytes required to store a signed 64-bit integer, + * converted to an unsigned 64-bit integer with ZigZag encoding, using base-128 + * varint encoding. + * + * \param v + * Value to encode. + * \return + * Number of bytes required. + */ +static inline size_t +sint64_size(int64_t v) +{ + return uint64_size(zigzag64(v)); +} + +/** + * Calculate the serialized size of a single required message field, including + * the space needed by the preceding tag. + * + * \param field + * Field descriptor for member. + * \param member + * Field to encode. + * \return + * Number of bytes required. + */ +static size_t +required_field_get_packed_size(const ProtobufCFieldDescriptor *field, + const void *member) +{ + size_t rv = get_tag_size(field->id); + + switch (field->type) { + case PROTOBUF_C_TYPE_SINT32: + return rv + sint32_size(*(const int32_t *) member); + case PROTOBUF_C_TYPE_ENUM: + case PROTOBUF_C_TYPE_INT32: + return rv + int32_size(*(const int32_t *) member); + case PROTOBUF_C_TYPE_UINT32: + return rv + uint32_size(*(const uint32_t *) member); + case PROTOBUF_C_TYPE_SINT64: + return rv + sint64_size(*(const int64_t *) member); + case PROTOBUF_C_TYPE_INT64: + case PROTOBUF_C_TYPE_UINT64: + return rv + uint64_size(*(const uint64_t *) member); + case PROTOBUF_C_TYPE_SFIXED32: + case PROTOBUF_C_TYPE_FIXED32: + return rv + 4; + case PROTOBUF_C_TYPE_SFIXED64: + case PROTOBUF_C_TYPE_FIXED64: + return rv + 8; + case PROTOBUF_C_TYPE_BOOL: + return rv + 1; + case PROTOBUF_C_TYPE_FLOAT: + return rv + 4; + case PROTOBUF_C_TYPE_DOUBLE: + return rv + 8; + case PROTOBUF_C_TYPE_STRING: { + const char *str = *(char * const *) member; + size_t len = str ? strlen(str) : 0; + return rv + uint32_size(len) + len; + } + case PROTOBUF_C_TYPE_BYTES: { + size_t len = ((const ProtobufCBinaryData *) member)->len; + return rv + uint32_size(len) + len; + } + case PROTOBUF_C_TYPE_MESSAGE: { + const ProtobufCMessage *msg = *(ProtobufCMessage * const *) member; + size_t subrv = msg ? protobuf_c_message_get_packed_size(msg) : 0; + return rv + uint32_size(subrv) + subrv; + } + } + PROTOBUF_C__ASSERT_NOT_REACHED(); + return 0; +} + +/** + * Calculate the serialized size of a single oneof message field, including + * the space needed by the preceding tag. Returns 0 if the oneof field isn't + * selected or is not set. + * + * \param field + * Field descriptor for member. + * \param oneof_case + * Enum value that selects the field in the oneof. + * \param member + * Field to encode. + * \return + * Number of bytes required. + */ +static size_t +oneof_field_get_packed_size(const ProtobufCFieldDescriptor *field, + uint32_t oneof_case, + const void *member) +{ + if (oneof_case != field->id) { + return 0; + } + if (field->type == PROTOBUF_C_TYPE_MESSAGE || + field->type == PROTOBUF_C_TYPE_STRING) + { + const void *ptr = *(const void * const *) member; + if (ptr == NULL || ptr == field->default_value) + return 0; + } + return required_field_get_packed_size(field, member); +} + +/** + * Calculate the serialized size of a single optional message field, including + * the space needed by the preceding tag. Returns 0 if the optional field isn't + * set. + * + * \param field + * Field descriptor for member. + * \param has + * True if the field exists, false if not. + * \param member + * Field to encode. + * \return + * Number of bytes required. + */ +static size_t +optional_field_get_packed_size(const ProtobufCFieldDescriptor *field, + const protobuf_c_boolean has, + const void *member) +{ + if (field->type == PROTOBUF_C_TYPE_MESSAGE || + field->type == PROTOBUF_C_TYPE_STRING) + { + const void *ptr = *(const void * const *) member; + if (ptr == NULL || ptr == field->default_value) + return 0; + } else { + if (!has) + return 0; + } + return required_field_get_packed_size(field, member); +} + +static protobuf_c_boolean +field_is_zeroish(const ProtobufCFieldDescriptor *field, + const void *member) +{ + protobuf_c_boolean ret = FALSE; + + switch (field->type) { + case PROTOBUF_C_TYPE_BOOL: + ret = (0 == *(const protobuf_c_boolean *) member); + break; + case PROTOBUF_C_TYPE_ENUM: + case PROTOBUF_C_TYPE_SINT32: + case PROTOBUF_C_TYPE_INT32: + case PROTOBUF_C_TYPE_UINT32: + case PROTOBUF_C_TYPE_SFIXED32: + case PROTOBUF_C_TYPE_FIXED32: + ret = (0 == *(const uint32_t *) member); + break; + case PROTOBUF_C_TYPE_SINT64: + case PROTOBUF_C_TYPE_INT64: + case PROTOBUF_C_TYPE_UINT64: + case PROTOBUF_C_TYPE_SFIXED64: + case PROTOBUF_C_TYPE_FIXED64: + ret = (0 == *(const uint64_t *) member); + break; + case PROTOBUF_C_TYPE_FLOAT: + ret = (0 == *(const float *) member); + break; + case PROTOBUF_C_TYPE_DOUBLE: + ret = (0 == *(const double *) member); + break; + case PROTOBUF_C_TYPE_STRING: + ret = (NULL == *(const char * const *) member) || + ('\0' == **(const char * const *) member); + break; + case PROTOBUF_C_TYPE_BYTES: + case PROTOBUF_C_TYPE_MESSAGE: + ret = (NULL == *(const void * const *) member); + break; + default: + ret = TRUE; + break; + } + + return ret; +} + +/** + * Calculate the serialized size of a single unlabeled message field, including + * the space needed by the preceding tag. Returns 0 if the field isn't set or + * if it is set to a "zeroish" value (null pointer or 0 for numerical values). + * Unlabeled fields are supported only in proto3. + * + * \param field + * Field descriptor for member. + * \param member + * Field to encode. + * \return + * Number of bytes required. + */ +static size_t +unlabeled_field_get_packed_size(const ProtobufCFieldDescriptor *field, + const void *member) +{ + if (field_is_zeroish(field, member)) + return 0; + return required_field_get_packed_size(field, member); +} + +/** + * Calculate the serialized size of repeated message fields, which may consist + * of any number of values (including 0). Includes the space needed by the + * preceding tags (as needed). + * + * \param field + * Field descriptor for member. + * \param count + * Number of repeated field members. + * \param member + * Field to encode. + * \return + * Number of bytes required. + */ +static size_t +repeated_field_get_packed_size(const ProtobufCFieldDescriptor *field, + size_t count, const void *member) +{ + size_t header_size; + size_t rv = 0; + unsigned i; + void *array = *(void * const *) member; + + if (count == 0) + return 0; + header_size = get_tag_size(field->id); + if (0 == (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) + header_size *= count; + + switch (field->type) { + case PROTOBUF_C_TYPE_SINT32: + for (i = 0; i < count; i++) + rv += sint32_size(((int32_t *) array)[i]); + break; + case PROTOBUF_C_TYPE_ENUM: + case PROTOBUF_C_TYPE_INT32: + for (i = 0; i < count; i++) + rv += int32_size(((int32_t *) array)[i]); + break; + case PROTOBUF_C_TYPE_UINT32: + for (i = 0; i < count; i++) + rv += uint32_size(((uint32_t *) array)[i]); + break; + case PROTOBUF_C_TYPE_SINT64: + for (i = 0; i < count; i++) + rv += sint64_size(((int64_t *) array)[i]); + break; + case PROTOBUF_C_TYPE_INT64: + case PROTOBUF_C_TYPE_UINT64: + for (i = 0; i < count; i++) + rv += uint64_size(((uint64_t *) array)[i]); + break; + case PROTOBUF_C_TYPE_SFIXED32: + case PROTOBUF_C_TYPE_FIXED32: + case PROTOBUF_C_TYPE_FLOAT: + rv += 4 * count; + break; + case PROTOBUF_C_TYPE_SFIXED64: + case PROTOBUF_C_TYPE_FIXED64: + case PROTOBUF_C_TYPE_DOUBLE: + rv += 8 * count; + break; + case PROTOBUF_C_TYPE_BOOL: + rv += count; + break; + case PROTOBUF_C_TYPE_STRING: + for (i = 0; i < count; i++) { + size_t len = strlen(((char **) array)[i]); + rv += uint32_size(len) + len; + } + break; + case PROTOBUF_C_TYPE_BYTES: + for (i = 0; i < count; i++) { + size_t len = ((ProtobufCBinaryData *) array)[i].len; + rv += uint32_size(len) + len; + } + break; + case PROTOBUF_C_TYPE_MESSAGE: + for (i = 0; i < count; i++) { + size_t len = protobuf_c_message_get_packed_size( + ((ProtobufCMessage **) array)[i]); + rv += uint32_size(len) + len; + } + break; + } + + if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) + header_size += uint32_size(rv); + return header_size + rv; +} + +/** + * Calculate the serialized size of an unknown field, i.e. one that is passed + * through mostly uninterpreted. This is required for forward compatibility if + * new fields are added to the message descriptor. + * + * \param field + * Unknown field type. + * \return + * Number of bytes required. + */ +static inline size_t +unknown_field_get_packed_size(const ProtobufCMessageUnknownField *field) +{ + return get_tag_size(field->tag) + field->len; +} + +/**@}*/ + +/* + * Calculate the serialized size of the message. + */ +size_t protobuf_c_message_get_packed_size(const ProtobufCMessage *message) +{ + unsigned i; + size_t rv = 0; + + ASSERT_IS_MESSAGE(message); + for (i = 0; i < message->descriptor->n_fields; i++) { + const ProtobufCFieldDescriptor *field = + message->descriptor->fields + i; + const void *member = + ((const char *) message) + field->offset; + const void *qmember = + ((const char *) message) + field->quantifier_offset; + + if (field->label == PROTOBUF_C_LABEL_REQUIRED) { + rv += required_field_get_packed_size(field, member); + } else if ((field->label == PROTOBUF_C_LABEL_OPTIONAL || + field->label == PROTOBUF_C_LABEL_NONE) && + (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF))) { + rv += oneof_field_get_packed_size( + field, + *(const uint32_t *) qmember, + member + ); + } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { + rv += optional_field_get_packed_size( + field, + *(protobuf_c_boolean *) qmember, + member + ); + } else if (field->label == PROTOBUF_C_LABEL_NONE) { + rv += unlabeled_field_get_packed_size( + field, + member + ); + } else { + rv += repeated_field_get_packed_size( + field, + *(const size_t *) qmember, + member + ); + } + } + for (i = 0; i < message->n_unknown_fields; i++) + rv += unknown_field_get_packed_size(&message->unknown_fields[i]); + return rv; +} + +/** + * \defgroup pack protobuf_c_message_pack() implementation + * + * Routines mainly used by protobuf_c_message_pack(). + * + * \ingroup internal + * @{ + */ + +/** + * Pack an unsigned 32-bit integer in base-128 varint encoding and return the + * number of bytes written, which must be 5 or less. + * + * \param value + * Value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ +static inline size_t +uint32_pack(uint32_t value, uint8_t *out) +{ + unsigned rv = 0; + + if (value >= 0x80) { + out[rv++] = value | 0x80; + value >>= 7; + if (value >= 0x80) { + out[rv++] = value | 0x80; + value >>= 7; + if (value >= 0x80) { + out[rv++] = value | 0x80; + value >>= 7; + if (value >= 0x80) { + out[rv++] = value | 0x80; + value >>= 7; + } + } + } + } + /* assert: value<128 */ + out[rv++] = value; + return rv; +} + +/** + * Pack a signed 32-bit integer and return the number of bytes written. + * Negative numbers are encoded as two's complement 64-bit integers. + * + * \param value + * Value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ +static inline size_t +int32_pack(int32_t value, uint8_t *out) +{ + if (value < 0) { + out[0] = value | 0x80; + out[1] = (value >> 7) | 0x80; + out[2] = (value >> 14) | 0x80; + out[3] = (value >> 21) | 0x80; + out[4] = (value >> 28) | 0x80; + out[5] = out[6] = out[7] = out[8] = 0xff; + out[9] = 0x01; + return 10; + } else { + return uint32_pack(value, out); + } +} + +/** + * Pack a signed 32-bit integer using ZigZag encoding and return the number of + * bytes written. + * + * \param value + * Value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ +static inline size_t +sint32_pack(int32_t value, uint8_t *out) +{ + return uint32_pack(zigzag32(value), out); +} + +/** + * Pack a 64-bit unsigned integer using base-128 varint encoding and return the + * number of bytes written. + * + * \param value + * Value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ +static size_t +uint64_pack(uint64_t value, uint8_t *out) +{ + uint32_t hi = (uint32_t) (value >> 32); + uint32_t lo = (uint32_t) value; + unsigned rv; + + if (hi == 0) + return uint32_pack((uint32_t) lo, out); + out[0] = (lo) | 0x80; + out[1] = (lo >> 7) | 0x80; + out[2] = (lo >> 14) | 0x80; + out[3] = (lo >> 21) | 0x80; + if (hi < 8) { + out[4] = (hi << 4) | (lo >> 28); + return 5; + } else { + out[4] = ((hi & 7) << 4) | (lo >> 28) | 0x80; + hi >>= 3; + } + rv = 5; + while (hi >= 128) { + out[rv++] = hi | 0x80; + hi >>= 7; + } + out[rv++] = hi; + return rv; +} + +/** + * Pack a 64-bit signed integer in ZigZag encoding and return the number of + * bytes written. + * + * \param value + * Value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ +static inline size_t +sint64_pack(int64_t value, uint8_t *out) +{ + return uint64_pack(zigzag64(value), out); +} + +/** + * Pack a 32-bit quantity in little-endian byte order. Used for protobuf wire + * types fixed32, sfixed32, float. Similar to "htole32". + * + * \param value + * Value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ +static inline size_t +fixed32_pack(uint32_t value, void *out) +{ +#if !defined(WORDS_BIGENDIAN) + memcpy(out, &value, 4); +#else + uint8_t *buf = out; + + buf[0] = value; + buf[1] = value >> 8; + buf[2] = value >> 16; + buf[3] = value >> 24; +#endif + return 4; +} + +/** + * Pack a 64-bit quantity in little-endian byte order. Used for protobuf wire + * types fixed64, sfixed64, double. Similar to "htole64". + * + * \todo The big-endian impl is really only good for 32-bit machines, a 64-bit + * version would be appreciated, plus a way to decide to use 64-bit math where + * convenient. + * + * \param value + * Value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ +static inline size_t +fixed64_pack(uint64_t value, void *out) +{ +#if !defined(WORDS_BIGENDIAN) + memcpy(out, &value, 8); +#else + fixed32_pack(value, out); + fixed32_pack(value >> 32, ((char *) out) + 4); +#endif + return 8; +} + +/** + * Pack a boolean value as an integer and return the number of bytes written. + * + * \todo Perhaps on some platforms *out = !!value would be a better impl, b/c + * that is idiomatic C++ in some STL implementations. + * + * \param value + * Value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ +static inline size_t +boolean_pack(protobuf_c_boolean value, uint8_t *out) +{ + *out = value ? TRUE : FALSE; + return 1; +} + +/** + * Pack a NUL-terminated C string and return the number of bytes written. The + * output includes a length delimiter. + * + * The NULL pointer is treated as an empty string. This isn't really necessary, + * but it allows people to leave required strings blank. (See Issue #13 in the + * bug tracker for a little more explanation). + * + * \param str + * String to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ +static inline size_t +string_pack(const char *str, uint8_t *out) +{ + if (str == NULL) { + out[0] = 0; + return 1; + } else { + size_t len = strlen(str); + size_t rv = uint32_pack(len, out); + memcpy(out + rv, str, len); + return rv + len; + } +} + +/** + * Pack a ProtobufCBinaryData and return the number of bytes written. The output + * includes a length delimiter. + * + * \param bd + * ProtobufCBinaryData to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ +static inline size_t +binary_data_pack(const ProtobufCBinaryData *bd, uint8_t *out) +{ + size_t len = bd->len; + size_t rv = uint32_pack(len, out); + memcpy(out + rv, bd->data, len); + return rv + len; +} + +/** + * Pack a ProtobufCMessage and return the number of bytes written. The output + * includes a length delimiter. + * + * \param message + * ProtobufCMessage object to pack. + * \param[out] out + * Packed message. + * \return + * Number of bytes written to `out`. + */ +static inline size_t +prefixed_message_pack(const ProtobufCMessage *message, uint8_t *out) +{ + if (message == NULL) { + out[0] = 0; + return 1; + } else { + size_t rv = protobuf_c_message_pack(message, out + 1); + uint32_t rv_packed_size = uint32_size(rv); + if (rv_packed_size != 1) + memmove(out + rv_packed_size, out + 1, rv); + return uint32_pack(rv, out) + rv; + } +} + +/** + * Pack a field tag. + * + * Wire-type will be added in required_field_pack(). + * + * \todo Just call uint64_pack on 64-bit platforms. + * + * \param id + * Tag value to encode. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ +static size_t +tag_pack(uint32_t id, uint8_t *out) +{ + if (id < (1UL << (32 - 3))) + return uint32_pack(id << 3, out); + else + return uint64_pack(((uint64_t) id) << 3, out); +} + +/** + * Pack a required field and return the number of bytes written. + * + * \param field + * Field descriptor. + * \param member + * The field member. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ +static size_t +required_field_pack(const ProtobufCFieldDescriptor *field, + const void *member, uint8_t *out) +{ + size_t rv = tag_pack(field->id, out); + + switch (field->type) { + case PROTOBUF_C_TYPE_SINT32: + out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; + return rv + sint32_pack(*(const int32_t *) member, out + rv); + case PROTOBUF_C_TYPE_ENUM: + case PROTOBUF_C_TYPE_INT32: + out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; + return rv + int32_pack(*(const int32_t *) member, out + rv); + case PROTOBUF_C_TYPE_UINT32: + out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; + return rv + uint32_pack(*(const uint32_t *) member, out + rv); + case PROTOBUF_C_TYPE_SINT64: + out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; + return rv + sint64_pack(*(const int64_t *) member, out + rv); + case PROTOBUF_C_TYPE_INT64: + case PROTOBUF_C_TYPE_UINT64: + out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; + return rv + uint64_pack(*(const uint64_t *) member, out + rv); + case PROTOBUF_C_TYPE_SFIXED32: + case PROTOBUF_C_TYPE_FIXED32: + case PROTOBUF_C_TYPE_FLOAT: + out[0] |= PROTOBUF_C_WIRE_TYPE_32BIT; + return rv + fixed32_pack(*(const uint32_t *) member, out + rv); + case PROTOBUF_C_TYPE_SFIXED64: + case PROTOBUF_C_TYPE_FIXED64: + case PROTOBUF_C_TYPE_DOUBLE: + out[0] |= PROTOBUF_C_WIRE_TYPE_64BIT; + return rv + fixed64_pack(*(const uint64_t *) member, out + rv); + case PROTOBUF_C_TYPE_BOOL: + out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; + return rv + boolean_pack(*(const protobuf_c_boolean *) member, out + rv); + case PROTOBUF_C_TYPE_STRING: + out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; + return rv + string_pack(*(char *const *) member, out + rv); + case PROTOBUF_C_TYPE_BYTES: + out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; + return rv + binary_data_pack((const ProtobufCBinaryData *) member, out + rv); + case PROTOBUF_C_TYPE_MESSAGE: + out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; + return rv + prefixed_message_pack(*(ProtobufCMessage * const *) member, out + rv); + } + PROTOBUF_C__ASSERT_NOT_REACHED(); + return 0; +} + +/** + * Pack a oneof field and return the number of bytes written. Only packs the + * field that is selected by the case enum. + * + * \param field + * Field descriptor. + * \param oneof_case + * Enum value that selects the field in the oneof. + * \param member + * The field member. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ +static size_t +oneof_field_pack(const ProtobufCFieldDescriptor *field, + uint32_t oneof_case, + const void *member, uint8_t *out) +{ + if (oneof_case != field->id) { + return 0; + } + if (field->type == PROTOBUF_C_TYPE_MESSAGE || + field->type == PROTOBUF_C_TYPE_STRING) + { + const void *ptr = *(const void * const *) member; + if (ptr == NULL || ptr == field->default_value) + return 0; + } + return required_field_pack(field, member, out); +} + +/** + * Pack an optional field and return the number of bytes written. + * + * \param field + * Field descriptor. + * \param has + * Whether the field is set. + * \param member + * The field member. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ +static size_t +optional_field_pack(const ProtobufCFieldDescriptor *field, + const protobuf_c_boolean has, + const void *member, uint8_t *out) +{ + if (field->type == PROTOBUF_C_TYPE_MESSAGE || + field->type == PROTOBUF_C_TYPE_STRING) + { + const void *ptr = *(const void * const *) member; + if (ptr == NULL || ptr == field->default_value) + return 0; + } else { + if (!has) + return 0; + } + return required_field_pack(field, member, out); +} + +/** + * Pack an unlabeled field and return the number of bytes written. + * + * \param field + * Field descriptor. + * \param member + * The field member. + * \param[out] out + * Packed value. + * \return + * Number of bytes written to `out`. + */ +static size_t +unlabeled_field_pack(const ProtobufCFieldDescriptor *field, + const void *member, uint8_t *out) +{ + if (field_is_zeroish(field, member)) + return 0; + return required_field_pack(field, member, out); +} + +/** + * Given a field type, return the in-memory size. + * + * \todo Implement as a table lookup. + * + * \param type + * Field type. + * \return + * Size of the field. + */ +static inline size_t +sizeof_elt_in_repeated_array(ProtobufCType type) +{ + switch (type) { + case PROTOBUF_C_TYPE_SINT32: + case PROTOBUF_C_TYPE_INT32: + case PROTOBUF_C_TYPE_UINT32: + case PROTOBUF_C_TYPE_SFIXED32: + case PROTOBUF_C_TYPE_FIXED32: + case PROTOBUF_C_TYPE_FLOAT: + case PROTOBUF_C_TYPE_ENUM: + return 4; + case PROTOBUF_C_TYPE_SINT64: + case PROTOBUF_C_TYPE_INT64: + case PROTOBUF_C_TYPE_UINT64: + case PROTOBUF_C_TYPE_SFIXED64: + case PROTOBUF_C_TYPE_FIXED64: + case PROTOBUF_C_TYPE_DOUBLE: + return 8; + case PROTOBUF_C_TYPE_BOOL: + return sizeof(protobuf_c_boolean); + case PROTOBUF_C_TYPE_STRING: + case PROTOBUF_C_TYPE_MESSAGE: + return sizeof(void *); + case PROTOBUF_C_TYPE_BYTES: + return sizeof(ProtobufCBinaryData); + } + PROTOBUF_C__ASSERT_NOT_REACHED(); + return 0; +} + +/** + * Pack an array of 32-bit quantities. + * + * \param[out] out + * Destination. + * \param[in] in + * Source. + * \param[in] n + * Number of elements in the source array. + */ +static void +copy_to_little_endian_32(void *out, const void *in, const unsigned n) +{ +#if !defined(WORDS_BIGENDIAN) + memcpy(out, in, n * 4); +#else + unsigned i; + const uint32_t *ini = in; + for (i = 0; i < n; i++) + fixed32_pack(ini[i], (uint32_t *) out + i); +#endif +} + +/** + * Pack an array of 64-bit quantities. + * + * \param[out] out + * Destination. + * \param[in] in + * Source. + * \param[in] n + * Number of elements in the source array. + */ +static void +copy_to_little_endian_64(void *out, const void *in, const unsigned n) +{ +#if !defined(WORDS_BIGENDIAN) + memcpy(out, in, n * 8); +#else + unsigned i; + const uint64_t *ini = in; + for (i = 0; i < n; i++) + fixed64_pack(ini[i], (uint64_t *) out + i); +#endif +} + +/** + * Get the minimum number of bytes required to pack a field value of a + * particular type. + * + * \param type + * Field type. + * \return + * Number of bytes. + */ +static unsigned +get_type_min_size(ProtobufCType type) +{ + if (type == PROTOBUF_C_TYPE_SFIXED32 || + type == PROTOBUF_C_TYPE_FIXED32 || + type == PROTOBUF_C_TYPE_FLOAT) + { + return 4; + } + if (type == PROTOBUF_C_TYPE_SFIXED64 || + type == PROTOBUF_C_TYPE_FIXED64 || + type == PROTOBUF_C_TYPE_DOUBLE) + { + return 8; + } + return 1; +} + +/** + * Packs the elements of a repeated field and returns the serialised field and + * its length. + * + * \param field + * Field descriptor. + * \param count + * Number of elements in the repeated field array. + * \param member + * Pointer to the elements for this repeated field. + * \param[out] out + * Serialised representation of the repeated field. + * \return + * Number of bytes serialised to `out`. + */ +static size_t +repeated_field_pack(const ProtobufCFieldDescriptor *field, + size_t count, const void *member, uint8_t *out) +{ + void *array = *(void * const *) member; + unsigned i; + + if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) { + unsigned header_len; + unsigned len_start; + unsigned min_length; + unsigned payload_len; + unsigned length_size_min; + unsigned actual_length_size; + uint8_t *payload_at; + + if (count == 0) + return 0; + header_len = tag_pack(field->id, out); + out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; + len_start = header_len; + min_length = get_type_min_size(field->type) * count; + length_size_min = uint32_size(min_length); + header_len += length_size_min; + payload_at = out + header_len; + + switch (field->type) { + case PROTOBUF_C_TYPE_SFIXED32: + case PROTOBUF_C_TYPE_FIXED32: + case PROTOBUF_C_TYPE_FLOAT: + copy_to_little_endian_32(payload_at, array, count); + payload_at += count * 4; + break; + case PROTOBUF_C_TYPE_SFIXED64: + case PROTOBUF_C_TYPE_FIXED64: + case PROTOBUF_C_TYPE_DOUBLE: + copy_to_little_endian_64(payload_at, array, count); + payload_at += count * 8; + break; + case PROTOBUF_C_TYPE_ENUM: + case PROTOBUF_C_TYPE_INT32: { + const int32_t *arr = (const int32_t *) array; + for (i = 0; i < count; i++) + payload_at += int32_pack(arr[i], payload_at); + break; + } + case PROTOBUF_C_TYPE_SINT32: { + const int32_t *arr = (const int32_t *) array; + for (i = 0; i < count; i++) + payload_at += sint32_pack(arr[i], payload_at); + break; + } + case PROTOBUF_C_TYPE_SINT64: { + const int64_t *arr = (const int64_t *) array; + for (i = 0; i < count; i++) + payload_at += sint64_pack(arr[i], payload_at); + break; + } + case PROTOBUF_C_TYPE_UINT32: { + const uint32_t *arr = (const uint32_t *) array; + for (i = 0; i < count; i++) + payload_at += uint32_pack(arr[i], payload_at); + break; + } + case PROTOBUF_C_TYPE_INT64: + case PROTOBUF_C_TYPE_UINT64: { + const uint64_t *arr = (const uint64_t *) array; + for (i = 0; i < count; i++) + payload_at += uint64_pack(arr[i], payload_at); + break; + } + case PROTOBUF_C_TYPE_BOOL: { + const protobuf_c_boolean *arr = (const protobuf_c_boolean *) array; + for (i = 0; i < count; i++) + payload_at += boolean_pack(arr[i], payload_at); + break; + } + default: + PROTOBUF_C__ASSERT_NOT_REACHED(); + } + + payload_len = payload_at - (out + header_len); + actual_length_size = uint32_size(payload_len); + if (length_size_min != actual_length_size) { + assert(actual_length_size == length_size_min + 1); + memmove(out + header_len + 1, out + header_len, + payload_len); + header_len++; + } + uint32_pack(payload_len, out + len_start); + return header_len + payload_len; + } else { + /* not "packed" cased */ + /* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */ + size_t rv = 0; + unsigned siz = sizeof_elt_in_repeated_array(field->type); + + for (i = 0; i < count; i++) { + rv += required_field_pack(field, array, out + rv); + array = (char *)array + siz; + } + return rv; + } +} + +static size_t +unknown_field_pack(const ProtobufCMessageUnknownField *field, uint8_t *out) +{ + size_t rv = tag_pack(field->tag, out); + out[0] |= field->wire_type; + memcpy(out + rv, field->data, field->len); + return rv + field->len; +} + +/**@}*/ + +size_t +protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out) +{ + unsigned i; + size_t rv = 0; + + ASSERT_IS_MESSAGE(message); + for (i = 0; i < message->descriptor->n_fields; i++) { + const ProtobufCFieldDescriptor *field = + message->descriptor->fields + i; + const void *member = ((const char *) message) + field->offset; + + /* + * It doesn't hurt to compute qmember (a pointer to the + * quantifier field of the structure), but the pointer is only + * valid if the field is: + * - a repeated field, or + * - a field that is part of a oneof + * - an optional field that isn't a pointer type + * (Meaning: not a message or a string). + */ + const void *qmember = + ((const char *) message) + field->quantifier_offset; + + if (field->label == PROTOBUF_C_LABEL_REQUIRED) { + rv += required_field_pack(field, member, out + rv); + } else if ((field->label == PROTOBUF_C_LABEL_OPTIONAL || + field->label == PROTOBUF_C_LABEL_NONE) && + (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF))) { + rv += oneof_field_pack( + field, + *(const uint32_t *) qmember, + member, + out + rv + ); + } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { + rv += optional_field_pack( + field, + *(const protobuf_c_boolean *) qmember, + member, + out + rv + ); + } else if (field->label == PROTOBUF_C_LABEL_NONE) { + rv += unlabeled_field_pack(field, member, out + rv); + } else { + rv += repeated_field_pack(field, *(const size_t *) qmember, + member, out + rv); + } + } + for (i = 0; i < message->n_unknown_fields; i++) + rv += unknown_field_pack(&message->unknown_fields[i], out + rv); + return rv; +} + +/** + * \defgroup packbuf protobuf_c_message_pack_to_buffer() implementation + * + * Routines mainly used by protobuf_c_message_pack_to_buffer(). + * + * \ingroup internal + * @{ + */ + +/** + * Pack a required field to a virtual buffer. + * + * \param field + * Field descriptor. + * \param member + * The element to be packed. + * \param[out] buffer + * Virtual buffer to append data to. + * \return + * Number of bytes packed. + */ +static size_t +required_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, + const void *member, ProtobufCBuffer *buffer) +{ + size_t rv; + uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2]; + + rv = tag_pack(field->id, scratch); + switch (field->type) { + case PROTOBUF_C_TYPE_SINT32: + scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; + rv += sint32_pack(*(const int32_t *) member, scratch + rv); + buffer->append(buffer, rv, scratch); + break; + case PROTOBUF_C_TYPE_ENUM: + case PROTOBUF_C_TYPE_INT32: + scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; + rv += int32_pack(*(const int32_t *) member, scratch + rv); + buffer->append(buffer, rv, scratch); + break; + case PROTOBUF_C_TYPE_UINT32: + scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; + rv += uint32_pack(*(const uint32_t *) member, scratch + rv); + buffer->append(buffer, rv, scratch); + break; + case PROTOBUF_C_TYPE_SINT64: + scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; + rv += sint64_pack(*(const int64_t *) member, scratch + rv); + buffer->append(buffer, rv, scratch); + break; + case PROTOBUF_C_TYPE_INT64: + case PROTOBUF_C_TYPE_UINT64: + scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; + rv += uint64_pack(*(const uint64_t *) member, scratch + rv); + buffer->append(buffer, rv, scratch); + break; + case PROTOBUF_C_TYPE_SFIXED32: + case PROTOBUF_C_TYPE_FIXED32: + case PROTOBUF_C_TYPE_FLOAT: + scratch[0] |= PROTOBUF_C_WIRE_TYPE_32BIT; + rv += fixed32_pack(*(const uint32_t *) member, scratch + rv); + buffer->append(buffer, rv, scratch); + break; + case PROTOBUF_C_TYPE_SFIXED64: + case PROTOBUF_C_TYPE_FIXED64: + case PROTOBUF_C_TYPE_DOUBLE: + scratch[0] |= PROTOBUF_C_WIRE_TYPE_64BIT; + rv += fixed64_pack(*(const uint64_t *) member, scratch + rv); + buffer->append(buffer, rv, scratch); + break; + case PROTOBUF_C_TYPE_BOOL: + scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; + rv += boolean_pack(*(const protobuf_c_boolean *) member, scratch + rv); + buffer->append(buffer, rv, scratch); + break; + case PROTOBUF_C_TYPE_STRING: { + const char *str = *(char *const *) member; + size_t sublen = str ? strlen(str) : 0; + + scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; + rv += uint32_pack(sublen, scratch + rv); + buffer->append(buffer, rv, scratch); + buffer->append(buffer, sublen, (const uint8_t *) str); + rv += sublen; + break; + } + case PROTOBUF_C_TYPE_BYTES: { + const ProtobufCBinaryData *bd = ((const ProtobufCBinaryData *) member); + size_t sublen = bd->len; + + scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; + rv += uint32_pack(sublen, scratch + rv); + buffer->append(buffer, rv, scratch); + buffer->append(buffer, sublen, bd->data); + rv += sublen; + break; + } + case PROTOBUF_C_TYPE_MESSAGE: { + uint8_t simple_buffer_scratch[256]; + size_t sublen; + const ProtobufCMessage *msg = *(ProtobufCMessage * const *) member; + ProtobufCBufferSimple simple_buffer = + PROTOBUF_C_BUFFER_SIMPLE_INIT(simple_buffer_scratch); + + scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; + if (msg == NULL) + sublen = 0; + else + sublen = protobuf_c_message_pack_to_buffer(msg, &simple_buffer.base); + rv += uint32_pack(sublen, scratch + rv); + buffer->append(buffer, rv, scratch); + buffer->append(buffer, sublen, simple_buffer.data); + rv += sublen; + PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple_buffer); + break; + } + default: + PROTOBUF_C__ASSERT_NOT_REACHED(); + } + return rv; +} + +/** + * Pack a oneof field to a buffer. Only packs the field that is selected by the case enum. + * + * \param field + * Field descriptor. + * \param oneof_case + * Enum value that selects the field in the oneof. + * \param member + * The element to be packed. + * \param[out] buffer + * Virtual buffer to append data to. + * \return + * Number of bytes serialised to `buffer`. + */ +static size_t +oneof_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, + uint32_t oneof_case, + const void *member, ProtobufCBuffer *buffer) +{ + if (oneof_case != field->id) { + return 0; + } + if (field->type == PROTOBUF_C_TYPE_MESSAGE || + field->type == PROTOBUF_C_TYPE_STRING) + { + const void *ptr = *(const void *const *) member; + if (ptr == NULL || ptr == field->default_value) + return 0; + } + return required_field_pack_to_buffer(field, member, buffer); +} + +/** + * Pack an optional field to a buffer. + * + * \param field + * Field descriptor. + * \param has + * Whether the field is set. + * \param member + * The element to be packed. + * \param[out] buffer + * Virtual buffer to append data to. + * \return + * Number of bytes serialised to `buffer`. + */ +static size_t +optional_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, + const protobuf_c_boolean has, + const void *member, ProtobufCBuffer *buffer) +{ + if (field->type == PROTOBUF_C_TYPE_MESSAGE || + field->type == PROTOBUF_C_TYPE_STRING) + { + const void *ptr = *(const void *const *) member; + if (ptr == NULL || ptr == field->default_value) + return 0; + } else { + if (!has) + return 0; + } + return required_field_pack_to_buffer(field, member, buffer); +} + +/** + * Pack an unlabeled field to a buffer. + * + * \param field + * Field descriptor. + * \param member + * The element to be packed. + * \param[out] buffer + * Virtual buffer to append data to. + * \return + * Number of bytes serialised to `buffer`. + */ +static size_t +unlabeled_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, + const void *member, ProtobufCBuffer *buffer) +{ + if (field_is_zeroish(field, member)) + return 0; + return required_field_pack_to_buffer(field, member, buffer); +} + +/** + * Get the packed size of an array of same field type. + * + * \param field + * Field descriptor. + * \param count + * Number of elements of this type. + * \param array + * The elements to get the size of. + * \return + * Number of bytes required. + */ +static size_t +get_packed_payload_length(const ProtobufCFieldDescriptor *field, + unsigned count, const void *array) +{ + unsigned rv = 0; + unsigned i; + + switch (field->type) { + case PROTOBUF_C_TYPE_SFIXED32: + case PROTOBUF_C_TYPE_FIXED32: + case PROTOBUF_C_TYPE_FLOAT: + return count * 4; + case PROTOBUF_C_TYPE_SFIXED64: + case PROTOBUF_C_TYPE_FIXED64: + case PROTOBUF_C_TYPE_DOUBLE: + return count * 8; + case PROTOBUF_C_TYPE_ENUM: + case PROTOBUF_C_TYPE_INT32: { + const int32_t *arr = (const int32_t *) array; + for (i = 0; i < count; i++) + rv += int32_size(arr[i]); + break; + } + case PROTOBUF_C_TYPE_SINT32: { + const int32_t *arr = (const int32_t *) array; + for (i = 0; i < count; i++) + rv += sint32_size(arr[i]); + break; + } + case PROTOBUF_C_TYPE_UINT32: { + const uint32_t *arr = (const uint32_t *) array; + for (i = 0; i < count; i++) + rv += uint32_size(arr[i]); + break; + } + case PROTOBUF_C_TYPE_SINT64: { + const int64_t *arr = (const int64_t *) array; + for (i = 0; i < count; i++) + rv += sint64_size(arr[i]); + break; + } + case PROTOBUF_C_TYPE_INT64: + case PROTOBUF_C_TYPE_UINT64: { + const uint64_t *arr = (const uint64_t *) array; + for (i = 0; i < count; i++) + rv += uint64_size(arr[i]); + break; + } + case PROTOBUF_C_TYPE_BOOL: + return count; + default: + PROTOBUF_C__ASSERT_NOT_REACHED(); + } + return rv; +} + +/** + * Pack an array of same field type to a virtual buffer. + * + * \param field + * Field descriptor. + * \param count + * Number of elements of this type. + * \param array + * The elements to get the size of. + * \param[out] buffer + * Virtual buffer to append data to. + * \return + * Number of bytes packed. + */ +static size_t +pack_buffer_packed_payload(const ProtobufCFieldDescriptor *field, + unsigned count, const void *array, + ProtobufCBuffer *buffer) +{ + uint8_t scratch[16]; + size_t rv = 0; + unsigned i; + + switch (field->type) { + case PROTOBUF_C_TYPE_SFIXED32: + case PROTOBUF_C_TYPE_FIXED32: + case PROTOBUF_C_TYPE_FLOAT: +#if !defined(WORDS_BIGENDIAN) + rv = count * 4; + goto no_packing_needed; +#else + for (i = 0; i < count; i++) { + unsigned len = fixed32_pack(((uint32_t *) array)[i], scratch); + buffer->append(buffer, len, scratch); + rv += len; + } + break; +#endif + case PROTOBUF_C_TYPE_SFIXED64: + case PROTOBUF_C_TYPE_FIXED64: + case PROTOBUF_C_TYPE_DOUBLE: +#if !defined(WORDS_BIGENDIAN) + rv = count * 8; + goto no_packing_needed; +#else + for (i = 0; i < count; i++) { + unsigned len = fixed64_pack(((uint64_t *) array)[i], scratch); + buffer->append(buffer, len, scratch); + rv += len; + } + break; +#endif + case PROTOBUF_C_TYPE_ENUM: + case PROTOBUF_C_TYPE_INT32: + for (i = 0; i < count; i++) { + unsigned len = int32_pack(((int32_t *) array)[i], scratch); + buffer->append(buffer, len, scratch); + rv += len; + } + break; + case PROTOBUF_C_TYPE_SINT32: + for (i = 0; i < count; i++) { + unsigned len = sint32_pack(((int32_t *) array)[i], scratch); + buffer->append(buffer, len, scratch); + rv += len; + } + break; + case PROTOBUF_C_TYPE_UINT32: + for (i = 0; i < count; i++) { + unsigned len = uint32_pack(((uint32_t *) array)[i], scratch); + buffer->append(buffer, len, scratch); + rv += len; + } + break; + case PROTOBUF_C_TYPE_SINT64: + for (i = 0; i < count; i++) { + unsigned len = sint64_pack(((int64_t *) array)[i], scratch); + buffer->append(buffer, len, scratch); + rv += len; + } + break; + case PROTOBUF_C_TYPE_INT64: + case PROTOBUF_C_TYPE_UINT64: + for (i = 0; i < count; i++) { + unsigned len = uint64_pack(((uint64_t *) array)[i], scratch); + buffer->append(buffer, len, scratch); + rv += len; + } + break; + case PROTOBUF_C_TYPE_BOOL: + for (i = 0; i < count; i++) { + unsigned len = boolean_pack(((protobuf_c_boolean *) array)[i], scratch); + buffer->append(buffer, len, scratch); + rv += len; + } + return count; + default: + PROTOBUF_C__ASSERT_NOT_REACHED(); + } + return rv; + +#if !defined(WORDS_BIGENDIAN) +no_packing_needed: + buffer->append(buffer, rv, array); + return rv; +#endif +} + +static size_t +repeated_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, + unsigned count, const void *member, + ProtobufCBuffer *buffer) +{ + char *array = *(char * const *) member; + + if (count == 0) + return 0; + if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) { + uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2]; + size_t rv = tag_pack(field->id, scratch); + size_t payload_len = get_packed_payload_length(field, count, array); + size_t tmp; + + scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; + rv += uint32_pack(payload_len, scratch + rv); + buffer->append(buffer, rv, scratch); + tmp = pack_buffer_packed_payload(field, count, array, buffer); + assert(tmp == payload_len); + return rv + payload_len; + } else { + size_t siz; + unsigned i; + /* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */ + unsigned rv = 0; + + siz = sizeof_elt_in_repeated_array(field->type); + for (i = 0; i < count; i++) { + rv += required_field_pack_to_buffer(field, array, buffer); + array += siz; + } + return rv; + } +} + +static size_t +unknown_field_pack_to_buffer(const ProtobufCMessageUnknownField *field, + ProtobufCBuffer *buffer) +{ + uint8_t header[MAX_UINT64_ENCODED_SIZE]; + size_t rv = tag_pack(field->tag, header); + + header[0] |= field->wire_type; + buffer->append(buffer, rv, header); + buffer->append(buffer, field->len, field->data); + return rv + field->len; +} + +/**@}*/ + +size_t +protobuf_c_message_pack_to_buffer(const ProtobufCMessage *message, + ProtobufCBuffer *buffer) +{ + unsigned i; + size_t rv = 0; + + ASSERT_IS_MESSAGE(message); + for (i = 0; i < message->descriptor->n_fields; i++) { + const ProtobufCFieldDescriptor *field = + message->descriptor->fields + i; + const void *member = + ((const char *) message) + field->offset; + const void *qmember = + ((const char *) message) + field->quantifier_offset; + + if (field->label == PROTOBUF_C_LABEL_REQUIRED) { + rv += required_field_pack_to_buffer(field, member, buffer); + } else if ((field->label == PROTOBUF_C_LABEL_OPTIONAL || + field->label == PROTOBUF_C_LABEL_NONE) && + (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF))) { + rv += oneof_field_pack_to_buffer( + field, + *(const uint32_t *) qmember, + member, + buffer + ); + } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { + rv += optional_field_pack_to_buffer( + field, + *(const protobuf_c_boolean *) qmember, + member, + buffer + ); + } else if (field->label == PROTOBUF_C_LABEL_NONE) { + rv += unlabeled_field_pack_to_buffer( + field, + member, + buffer + ); + } else { + rv += repeated_field_pack_to_buffer( + field, + *(const size_t *) qmember, + member, + buffer + ); + } + } + for (i = 0; i < message->n_unknown_fields; i++) + rv += unknown_field_pack_to_buffer(&message->unknown_fields[i], buffer); + + return rv; +} + +/** + * \defgroup unpack unpacking implementation + * + * Routines mainly used by the unpacking functions. + * + * \ingroup internal + * @{ + */ + +static inline int +int_range_lookup(unsigned n_ranges, const ProtobufCIntRange *ranges, int value) +{ + unsigned n; + unsigned start; + + if (n_ranges == 0) + return -1; + start = 0; + n = n_ranges; + while (n > 1) { + unsigned mid = start + n / 2; + + if (value < ranges[mid].start_value) { + n = mid - start; + } else if (value >= ranges[mid].start_value + + (int) (ranges[mid + 1].orig_index - + ranges[mid].orig_index)) + { + unsigned new_start = mid + 1; + n = start + n - new_start; + start = new_start; + } else + return (value - ranges[mid].start_value) + + ranges[mid].orig_index; + } + if (n > 0) { + unsigned start_orig_index = ranges[start].orig_index; + unsigned range_size = + ranges[start + 1].orig_index - start_orig_index; + + if (ranges[start].start_value <= value && + value < (int) (ranges[start].start_value + range_size)) + { + return (value - ranges[start].start_value) + + start_orig_index; + } + } + return -1; +} + +static size_t +parse_tag_and_wiretype(size_t len, + const uint8_t *data, + uint32_t *tag_out, + ProtobufCWireType *wiretype_out) +{ + unsigned max_rv = len > 5 ? 5 : len; + uint32_t tag = (data[0] & 0x7f) >> 3; + unsigned shift = 4; + unsigned rv; + + *wiretype_out = data[0] & 7; + if ((data[0] & 0x80) == 0) { + *tag_out = tag; + return 1; + } + for (rv = 1; rv < max_rv; rv++) { + if (data[rv] & 0x80) { + tag |= (data[rv] & 0x7f) << shift; + shift += 7; + } else { + tag |= data[rv] << shift; + *tag_out = tag; + return rv + 1; + } + } + return 0; /* error: bad header */ +} + +/* sizeof(ScannedMember) must be <= (1UL<<BOUND_SIZEOF_SCANNED_MEMBER_LOG2) */ +#define BOUND_SIZEOF_SCANNED_MEMBER_LOG2 5 +typedef struct _ScannedMember ScannedMember; +/** Field as it's being read. */ +struct _ScannedMember { + uint32_t tag; /**< Field tag. */ + uint8_t wire_type; /**< Field type. */ + uint8_t length_prefix_len; /**< Prefix length. */ + const ProtobufCFieldDescriptor *field; /**< Field descriptor. */ + size_t len; /**< Field length. */ + const uint8_t *data; /**< Pointer to field data. */ +}; + +static inline uint32_t +scan_length_prefixed_data(size_t len, const uint8_t *data, + size_t *prefix_len_out) +{ + unsigned hdr_max = len < 5 ? len : 5; + unsigned hdr_len; + uint32_t val = 0; + unsigned i; + unsigned shift = 0; + + for (i = 0; i < hdr_max; i++) { + val |= (data[i] & 0x7f) << shift; + shift += 7; + if ((data[i] & 0x80) == 0) + break; + } + if (i == hdr_max) { + PROTOBUF_C_UNPACK_ERROR("error parsing length for length-prefixed data"); + return 0; + } + hdr_len = i + 1; + *prefix_len_out = hdr_len; + if (hdr_len + val > len) { + PROTOBUF_C_UNPACK_ERROR("data too short after length-prefix of %u", val); + return 0; + } + return hdr_len + val; +} + +static size_t +max_b128_numbers(size_t len, const uint8_t *data) +{ + size_t rv = 0; + while (len--) + if ((*data++ & 0x80) == 0) + ++rv; + return rv; +} + +/**@}*/ + +/** + * Merge earlier message into a latter message. + * + * For numeric types and strings, if the same value appears multiple + * times, the parser accepts the last value it sees. For embedded + * message fields, the parser merges multiple instances of the same + * field. That is, all singular scalar fields in the latter instance + * replace those in the former, singular embedded messages are merged, + * and repeated fields are concatenated. + * + * The earlier message should be freed after calling this function, as + * some of its fields may have been reused and changed to their default + * values during the merge. + */ +static protobuf_c_boolean +merge_messages(ProtobufCMessage *earlier_msg, + ProtobufCMessage *latter_msg, + ProtobufCAllocator *allocator) +{ + unsigned i; + const ProtobufCFieldDescriptor *fields = + latter_msg->descriptor->fields; + for (i = 0; i < latter_msg->descriptor->n_fields; i++) { + if (fields[i].label == PROTOBUF_C_LABEL_REPEATED) { + size_t *n_earlier = + STRUCT_MEMBER_PTR(size_t, earlier_msg, + fields[i].quantifier_offset); + uint8_t **p_earlier = + STRUCT_MEMBER_PTR(uint8_t *, earlier_msg, + fields[i].offset); + size_t *n_latter = + STRUCT_MEMBER_PTR(size_t, latter_msg, + fields[i].quantifier_offset); + uint8_t **p_latter = + STRUCT_MEMBER_PTR(uint8_t *, latter_msg, + fields[i].offset); + + if (*n_earlier > 0) { + if (*n_latter > 0) { + /* Concatenate the repeated field */ + size_t el_size = + sizeof_elt_in_repeated_array(fields[i].type); + uint8_t *new_field; + + new_field = do_alloc(allocator, + (*n_earlier + *n_latter) * el_size); + if (!new_field) + return FALSE; + + memcpy(new_field, *p_earlier, + *n_earlier * el_size); + memcpy(new_field + + *n_earlier * el_size, + *p_latter, + *n_latter * el_size); + + do_free(allocator, *p_latter); + do_free(allocator, *p_earlier); + *p_latter = new_field; + *n_latter = *n_earlier + *n_latter; + } else { + /* Zero copy the repeated field from the earlier message */ + *n_latter = *n_earlier; + *p_latter = *p_earlier; + } + /* Make sure the field does not get double freed */ + *n_earlier = 0; + *p_earlier = 0; + } + } else if (fields[i].label == PROTOBUF_C_LABEL_OPTIONAL || + fields[i].label == PROTOBUF_C_LABEL_NONE) { + const ProtobufCFieldDescriptor *field; + uint32_t *earlier_case_p = STRUCT_MEMBER_PTR(uint32_t, + earlier_msg, + fields[i]. + quantifier_offset); + uint32_t *latter_case_p = STRUCT_MEMBER_PTR(uint32_t, + latter_msg, + fields[i]. + quantifier_offset); + protobuf_c_boolean need_to_merge = FALSE; + void *earlier_elem; + void *latter_elem; + const void *def_val; + + if (fields[i].flags & PROTOBUF_C_FIELD_FLAG_ONEOF) { + if (*latter_case_p == 0) { + /* lookup correct oneof field */ + int field_index = + int_range_lookup( + latter_msg->descriptor + ->n_field_ranges, + latter_msg->descriptor + ->field_ranges, + *earlier_case_p); + field = latter_msg->descriptor->fields + + field_index; + } else { + /* Oneof is present in the latter message, move on */ + continue; + } + } else { + field = &fields[i]; + } + + earlier_elem = STRUCT_MEMBER_P(earlier_msg, field->offset); + latter_elem = STRUCT_MEMBER_P(latter_msg, field->offset); + def_val = field->default_value; + + switch (field->type) { + case PROTOBUF_C_TYPE_MESSAGE: { + ProtobufCMessage *em = *(ProtobufCMessage **) earlier_elem; + ProtobufCMessage *lm = *(ProtobufCMessage **) latter_elem; + if (em != NULL) { + if (lm != NULL) { + if (!merge_messages(em, lm, allocator)) + return FALSE; + /* Already merged */ + need_to_merge = FALSE; + } else { + /* Zero copy the message */ + need_to_merge = TRUE; + } + } + break; + } + case PROTOBUF_C_TYPE_BYTES: { + uint8_t *e_data = + ((ProtobufCBinaryData *) earlier_elem)->data; + uint8_t *l_data = + ((ProtobufCBinaryData *) latter_elem)->data; + const ProtobufCBinaryData *d_bd = + (ProtobufCBinaryData *) def_val; + + need_to_merge = + (e_data != NULL && + (d_bd == NULL || + e_data != d_bd->data)) && + (l_data == NULL || + (d_bd != NULL && + l_data == d_bd->data)); + break; + } + case PROTOBUF_C_TYPE_STRING: { + char *e_str = *(char **) earlier_elem; + char *l_str = *(char **) latter_elem; + const char *d_str = def_val; + + need_to_merge = e_str != d_str && l_str == d_str; + break; + } + default: { + /* Could be has field or case enum, the logic is + * equivalent, since 0 (FALSE) means not set for + * oneof */ + need_to_merge = (*earlier_case_p != 0) && + (*latter_case_p == 0); + break; + } + } + + if (need_to_merge) { + size_t el_size = + sizeof_elt_in_repeated_array(field->type); + memcpy(latter_elem, earlier_elem, el_size); + /* + * Reset the element from the old message to 0 + * to make sure earlier message deallocation + * doesn't corrupt zero-copied data in the new + * message, earlier message will be freed after + * this function is called anyway + */ + memset(earlier_elem, 0, el_size); + + if (field->quantifier_offset != 0) { + /* Set the has field or the case enum, + * if applicable */ + *latter_case_p = *earlier_case_p; + *earlier_case_p = 0; + } + } + } + } + return TRUE; +} + +/** + * Count packed elements. + * + * Given a raw slab of packed-repeated values, determine the number of + * elements. This function detects certain kinds of errors but not + * others; the remaining error checking is done by + * parse_packed_repeated_member(). + */ +static protobuf_c_boolean +count_packed_elements(ProtobufCType type, + size_t len, const uint8_t *data, size_t *count_out) +{ + switch (type) { + case PROTOBUF_C_TYPE_SFIXED32: + case PROTOBUF_C_TYPE_FIXED32: + case PROTOBUF_C_TYPE_FLOAT: + if (len % 4 != 0) { + PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 4 for fixed-length 32-bit types"); + return FALSE; + } + *count_out = len / 4; + return TRUE; + case PROTOBUF_C_TYPE_SFIXED64: + case PROTOBUF_C_TYPE_FIXED64: + case PROTOBUF_C_TYPE_DOUBLE: + if (len % 8 != 0) { + PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 8 for fixed-length 64-bit types"); + return FALSE; + } + *count_out = len / 8; + return TRUE; + case PROTOBUF_C_TYPE_ENUM: + case PROTOBUF_C_TYPE_INT32: + case PROTOBUF_C_TYPE_SINT32: + case PROTOBUF_C_TYPE_UINT32: + case PROTOBUF_C_TYPE_INT64: + case PROTOBUF_C_TYPE_SINT64: + case PROTOBUF_C_TYPE_UINT64: + *count_out = max_b128_numbers(len, data); + return TRUE; + case PROTOBUF_C_TYPE_BOOL: + *count_out = len; + return TRUE; + case PROTOBUF_C_TYPE_STRING: + case PROTOBUF_C_TYPE_BYTES: + case PROTOBUF_C_TYPE_MESSAGE: + default: + PROTOBUF_C_UNPACK_ERROR("bad protobuf-c type %u for packed-repeated", type); + return FALSE; + } +} + +static inline uint32_t +parse_uint32(unsigned len, const uint8_t *data) +{ + uint32_t rv = data[0] & 0x7f; + if (len > 1) { + rv |= ((uint32_t) (data[1] & 0x7f) << 7); + if (len > 2) { + rv |= ((uint32_t) (data[2] & 0x7f) << 14); + if (len > 3) { + rv |= ((uint32_t) (data[3] & 0x7f) << 21); + if (len > 4) + rv |= ((uint32_t) (data[4]) << 28); + } + } + } + return rv; +} + +static inline uint32_t +parse_int32(unsigned len, const uint8_t *data) +{ + return parse_uint32(len, data); +} + +static inline int32_t +unzigzag32(uint32_t v) +{ + if (v & 1) + return -(v >> 1) - 1; + else + return v >> 1; +} + +static inline uint32_t +parse_fixed_uint32(const uint8_t *data) +{ +#if !defined(WORDS_BIGENDIAN) + uint32_t t; + memcpy(&t, data, 4); + return t; +#else + return data[0] | + ((uint32_t) (data[1]) << 8) | + ((uint32_t) (data[2]) << 16) | + ((uint32_t) (data[3]) << 24); +#endif +} + +static uint64_t +parse_uint64(unsigned len, const uint8_t *data) +{ + unsigned shift, i; + uint64_t rv; + + if (len < 5) + return parse_uint32(len, data); + rv = ((uint64_t) (data[0] & 0x7f)) | + ((uint64_t) (data[1] & 0x7f) << 7) | + ((uint64_t) (data[2] & 0x7f) << 14) | + ((uint64_t) (data[3] & 0x7f) << 21); + shift = 28; + for (i = 4; i < len; i++) { + rv |= (((uint64_t) (data[i] & 0x7f)) << shift); + shift += 7; + } + return rv; +} + +static inline int64_t +unzigzag64(uint64_t v) +{ + if (v & 1) + return -(v >> 1) - 1; + else + return v >> 1; +} + +static inline uint64_t +parse_fixed_uint64(const uint8_t *data) +{ +#if !defined(WORDS_BIGENDIAN) + uint64_t t; + memcpy(&t, data, 8); + return t; +#else + return (uint64_t) parse_fixed_uint32(data) | + (((uint64_t) parse_fixed_uint32(data + 4)) << 32); +#endif +} + +static protobuf_c_boolean +parse_boolean(unsigned len, const uint8_t *data) +{ + unsigned i; + for (i = 0; i < len; i++) + if (data[i] & 0x7f) + return TRUE; + return FALSE; +} + +static protobuf_c_boolean +parse_required_member(ScannedMember *scanned_member, + void *member, + ProtobufCAllocator *allocator, + protobuf_c_boolean maybe_clear) +{ + unsigned len = scanned_member->len; + const uint8_t *data = scanned_member->data; + ProtobufCWireType wire_type = scanned_member->wire_type; + + switch (scanned_member->field->type) { + case PROTOBUF_C_TYPE_ENUM: + case PROTOBUF_C_TYPE_INT32: + if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) + return FALSE; + *(int32_t *) member = parse_int32(len, data); + return TRUE; + case PROTOBUF_C_TYPE_UINT32: + if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) + return FALSE; + *(uint32_t *) member = parse_uint32(len, data); + return TRUE; + case PROTOBUF_C_TYPE_SINT32: + if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) + return FALSE; + *(int32_t *) member = unzigzag32(parse_uint32(len, data)); + return TRUE; + case PROTOBUF_C_TYPE_SFIXED32: + case PROTOBUF_C_TYPE_FIXED32: + case PROTOBUF_C_TYPE_FLOAT: + if (wire_type != PROTOBUF_C_WIRE_TYPE_32BIT) + return FALSE; + *(uint32_t *) member = parse_fixed_uint32(data); + return TRUE; + case PROTOBUF_C_TYPE_INT64: + case PROTOBUF_C_TYPE_UINT64: + if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) + return FALSE; + *(uint64_t *) member = parse_uint64(len, data); + return TRUE; + case PROTOBUF_C_TYPE_SINT64: + if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) + return FALSE; + *(int64_t *) member = unzigzag64(parse_uint64(len, data)); + return TRUE; + case PROTOBUF_C_TYPE_SFIXED64: + case PROTOBUF_C_TYPE_FIXED64: + case PROTOBUF_C_TYPE_DOUBLE: + if (wire_type != PROTOBUF_C_WIRE_TYPE_64BIT) + return FALSE; + *(uint64_t *) member = parse_fixed_uint64(data); + return TRUE; + case PROTOBUF_C_TYPE_BOOL: + *(protobuf_c_boolean *) member = parse_boolean(len, data); + return TRUE; + case PROTOBUF_C_TYPE_STRING: { + char **pstr = member; + unsigned pref_len = scanned_member->length_prefix_len; + + if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) + return FALSE; + + if (maybe_clear && *pstr != NULL) { + const char *def = scanned_member->field->default_value; + if (*pstr != NULL && *pstr != def) + do_free(allocator, *pstr); + } + *pstr = do_alloc(allocator, len - pref_len + 1); + if (*pstr == NULL) + return FALSE; + memcpy(*pstr, data + pref_len, len - pref_len); + (*pstr)[len - pref_len] = 0; + return TRUE; + } + case PROTOBUF_C_TYPE_BYTES: { + ProtobufCBinaryData *bd = member; + const ProtobufCBinaryData *def_bd; + unsigned pref_len = scanned_member->length_prefix_len; + + if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) + return FALSE; + + def_bd = scanned_member->field->default_value; + if (maybe_clear && + bd->data != NULL && + (def_bd == NULL || bd->data != def_bd->data)) + { + do_free(allocator, bd->data); + } + if (len - pref_len > 0) { + bd->data = do_alloc(allocator, len - pref_len); + if (bd->data == NULL) + return FALSE; + memcpy(bd->data, data + pref_len, len - pref_len); + } else { + bd->data = NULL; + } + bd->len = len - pref_len; + return TRUE; + } + case PROTOBUF_C_TYPE_MESSAGE: { + ProtobufCMessage **pmessage = member; + ProtobufCMessage *subm; + const ProtobufCMessage *def_mess; + protobuf_c_boolean merge_successful = TRUE; + unsigned pref_len = scanned_member->length_prefix_len; + + if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) + return FALSE; + + def_mess = scanned_member->field->default_value; + subm = protobuf_c_message_unpack(scanned_member->field->descriptor, + allocator, + len - pref_len, + data + pref_len); + + if (maybe_clear && + *pmessage != NULL && + *pmessage != def_mess) + { + if (subm != NULL) + merge_successful = merge_messages(*pmessage, subm, allocator); + /* Delete the previous message */ + protobuf_c_message_free_unpacked(*pmessage, allocator); + } + *pmessage = subm; + if (subm == NULL || !merge_successful) + return FALSE; + return TRUE; + } + } + return FALSE; +} + +static protobuf_c_boolean +parse_oneof_member (ScannedMember *scanned_member, + void *member, + ProtobufCMessage *message, + ProtobufCAllocator *allocator) +{ + uint32_t *oneof_case = STRUCT_MEMBER_PTR(uint32_t, message, + scanned_member->field->quantifier_offset); + + /* If we have already parsed a member of this oneof, free it. */ + if (*oneof_case != 0) { + /* lookup field */ + int field_index = + int_range_lookup(message->descriptor->n_field_ranges, + message->descriptor->field_ranges, + *oneof_case); + const ProtobufCFieldDescriptor *old_field = + message->descriptor->fields + field_index; + size_t el_size = sizeof_elt_in_repeated_array(old_field->type); + + switch (old_field->type) { + case PROTOBUF_C_TYPE_STRING: { + char **pstr = member; + const char *def = old_field->default_value; + if (*pstr != NULL && *pstr != def) + do_free(allocator, *pstr); + break; + } + case PROTOBUF_C_TYPE_BYTES: { + ProtobufCBinaryData *bd = member; + const ProtobufCBinaryData *def_bd = old_field->default_value; + if (bd->data != NULL && + (def_bd == NULL || bd->data != def_bd->data)) + { + do_free(allocator, bd->data); + } + break; + } + case PROTOBUF_C_TYPE_MESSAGE: { + ProtobufCMessage **pmessage = member; + const ProtobufCMessage *def_mess = old_field->default_value; + if (*pmessage != NULL && *pmessage != def_mess) + protobuf_c_message_free_unpacked(*pmessage, allocator); + break; + } + default: + break; + } + + memset (member, 0, el_size); + } + if (!parse_required_member (scanned_member, member, allocator, TRUE)) + return FALSE; + + *oneof_case = scanned_member->tag; + return TRUE; +} + + +static protobuf_c_boolean +parse_optional_member(ScannedMember *scanned_member, + void *member, + ProtobufCMessage *message, + ProtobufCAllocator *allocator) +{ + if (!parse_required_member(scanned_member, member, allocator, TRUE)) + return FALSE; + if (scanned_member->field->quantifier_offset != 0) + STRUCT_MEMBER(protobuf_c_boolean, + message, + scanned_member->field->quantifier_offset) = TRUE; + return TRUE; +} + +static protobuf_c_boolean +parse_repeated_member(ScannedMember *scanned_member, + void *member, + ProtobufCMessage *message, + ProtobufCAllocator *allocator) +{ + const ProtobufCFieldDescriptor *field = scanned_member->field; + size_t *p_n = STRUCT_MEMBER_PTR(size_t, message, field->quantifier_offset); + size_t siz = sizeof_elt_in_repeated_array(field->type); + char *array = *(char **) member; + + if (!parse_required_member(scanned_member, array + siz * (*p_n), + allocator, FALSE)) + { + return FALSE; + } + *p_n += 1; + return TRUE; +} + +static unsigned +scan_varint(unsigned len, const uint8_t *data) +{ + unsigned i; + if (len > 10) + len = 10; + for (i = 0; i < len; i++) + if ((data[i] & 0x80) == 0) + break; + if (i == len) + return 0; + return i + 1; +} + +static protobuf_c_boolean +parse_packed_repeated_member(ScannedMember *scanned_member, + void *member, + ProtobufCMessage *message) +{ + const ProtobufCFieldDescriptor *field = scanned_member->field; + size_t *p_n = STRUCT_MEMBER_PTR(size_t, message, field->quantifier_offset); + size_t siz = sizeof_elt_in_repeated_array(field->type); + void *array = *(char **) member + siz * (*p_n); + const uint8_t *at = scanned_member->data + scanned_member->length_prefix_len; + size_t rem = scanned_member->len - scanned_member->length_prefix_len; + size_t count = 0; + unsigned i; + + switch (field->type) { + case PROTOBUF_C_TYPE_SFIXED32: + case PROTOBUF_C_TYPE_FIXED32: + case PROTOBUF_C_TYPE_FLOAT: + count = (scanned_member->len - scanned_member->length_prefix_len) / 4; +#if !defined(WORDS_BIGENDIAN) + goto no_unpacking_needed; +#else + for (i = 0; i < count; i++) { + ((uint32_t *) array)[i] = parse_fixed_uint32(at); + at += 4; + } + break; +#endif + case PROTOBUF_C_TYPE_SFIXED64: + case PROTOBUF_C_TYPE_FIXED64: + case PROTOBUF_C_TYPE_DOUBLE: + count = (scanned_member->len - scanned_member->length_prefix_len) / 8; +#if !defined(WORDS_BIGENDIAN) + goto no_unpacking_needed; +#else + for (i = 0; i < count; i++) { + ((uint64_t *) array)[i] = parse_fixed_uint64(at); + at += 8; + } + break; +#endif + case PROTOBUF_C_TYPE_ENUM: + case PROTOBUF_C_TYPE_INT32: + while (rem > 0) { + unsigned s = scan_varint(rem, at); + if (s == 0) { + PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int32 value"); + return FALSE; + } + ((int32_t *) array)[count++] = parse_int32(s, at); + at += s; + rem -= s; + } + break; + case PROTOBUF_C_TYPE_SINT32: + while (rem > 0) { + unsigned s = scan_varint(rem, at); + if (s == 0) { + PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint32 value"); + return FALSE; + } + ((int32_t *) array)[count++] = unzigzag32(parse_uint32(s, at)); + at += s; + rem -= s; + } + break; + case PROTOBUF_C_TYPE_UINT32: + while (rem > 0) { + unsigned s = scan_varint(rem, at); + if (s == 0) { + PROTOBUF_C_UNPACK_ERROR("bad packed-repeated enum or uint32 value"); + return FALSE; + } + ((uint32_t *) array)[count++] = parse_uint32(s, at); + at += s; + rem -= s; + } + break; + + case PROTOBUF_C_TYPE_SINT64: + while (rem > 0) { + unsigned s = scan_varint(rem, at); + if (s == 0) { + PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint64 value"); + return FALSE; + } + ((int64_t *) array)[count++] = unzigzag64(parse_uint64(s, at)); + at += s; + rem -= s; + } + break; + case PROTOBUF_C_TYPE_INT64: + case PROTOBUF_C_TYPE_UINT64: + while (rem > 0) { + unsigned s = scan_varint(rem, at); + if (s == 0) { + PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int64/uint64 value"); + return FALSE; + } + ((int64_t *) array)[count++] = parse_uint64(s, at); + at += s; + rem -= s; + } + break; + case PROTOBUF_C_TYPE_BOOL: + count = rem; + for (i = 0; i < count; i++) { + if (at[i] > 1) { + PROTOBUF_C_UNPACK_ERROR("bad packed-repeated boolean value"); + return FALSE; + } + ((protobuf_c_boolean *) array)[i] = at[i]; + } + break; + default: + PROTOBUF_C__ASSERT_NOT_REACHED(); + } + *p_n += count; + return TRUE; + +#if !defined(WORDS_BIGENDIAN) +no_unpacking_needed: + memcpy(array, at, count * siz); + *p_n += count; + return TRUE; +#endif +} + +static protobuf_c_boolean +is_packable_type(ProtobufCType type) +{ + return + type != PROTOBUF_C_TYPE_STRING && + type != PROTOBUF_C_TYPE_BYTES && + type != PROTOBUF_C_TYPE_MESSAGE; +} + +static protobuf_c_boolean +parse_member(ScannedMember *scanned_member, + ProtobufCMessage *message, + ProtobufCAllocator *allocator) +{ + const ProtobufCFieldDescriptor *field = scanned_member->field; + void *member; + + if (field == NULL) { + ProtobufCMessageUnknownField *ufield = + message->unknown_fields + + (message->n_unknown_fields++); + ufield->tag = scanned_member->tag; + ufield->wire_type = scanned_member->wire_type; + ufield->len = scanned_member->len; + ufield->data = do_alloc(allocator, scanned_member->len); + if (ufield->data == NULL) + return FALSE; + memcpy(ufield->data, scanned_member->data, ufield->len); + return TRUE; + } + member = (char *) message + field->offset; + switch (field->label) { + case PROTOBUF_C_LABEL_REQUIRED: + return parse_required_member(scanned_member, member, + allocator, TRUE); + case PROTOBUF_C_LABEL_OPTIONAL: + case PROTOBUF_C_LABEL_NONE: + if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF)) { + return parse_oneof_member(scanned_member, member, + message, allocator); + } else { + return parse_optional_member(scanned_member, member, + message, allocator); + } + case PROTOBUF_C_LABEL_REPEATED: + if (scanned_member->wire_type == + PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED && + (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) || + is_packable_type(field->type))) + { + return parse_packed_repeated_member(scanned_member, + member, message); + } else { + return parse_repeated_member(scanned_member, + member, message, + allocator); + } + } + PROTOBUF_C__ASSERT_NOT_REACHED(); + return 0; +} + +/** + * Initialise messages generated by old code. + * + * This function is used if desc->message_init == NULL (which occurs + * for old code, and which would be useful to support allocating + * descriptors dynamically). + */ +static void +message_init_generic(const ProtobufCMessageDescriptor *desc, + ProtobufCMessage *message) +{ + unsigned i; + + memset(message, 0, desc->sizeof_message); + message->descriptor = desc; + for (i = 0; i < desc->n_fields; i++) { + if (desc->fields[i].default_value != NULL && + desc->fields[i].label != PROTOBUF_C_LABEL_REPEATED) + { + void *field = + STRUCT_MEMBER_P(message, desc->fields[i].offset); + const void *dv = desc->fields[i].default_value; + + switch (desc->fields[i].type) { + case PROTOBUF_C_TYPE_INT32: + case PROTOBUF_C_TYPE_SINT32: + case PROTOBUF_C_TYPE_SFIXED32: + case PROTOBUF_C_TYPE_UINT32: + case PROTOBUF_C_TYPE_FIXED32: + case PROTOBUF_C_TYPE_FLOAT: + case PROTOBUF_C_TYPE_ENUM: + memcpy(field, dv, 4); + break; + case PROTOBUF_C_TYPE_INT64: + case PROTOBUF_C_TYPE_SINT64: + case PROTOBUF_C_TYPE_SFIXED64: + case PROTOBUF_C_TYPE_UINT64: + case PROTOBUF_C_TYPE_FIXED64: + case PROTOBUF_C_TYPE_DOUBLE: + memcpy(field, dv, 8); + break; + case PROTOBUF_C_TYPE_BOOL: + memcpy(field, dv, sizeof(protobuf_c_boolean)); + break; + case PROTOBUF_C_TYPE_BYTES: + memcpy(field, dv, sizeof(ProtobufCBinaryData)); + break; + + case PROTOBUF_C_TYPE_STRING: + case PROTOBUF_C_TYPE_MESSAGE: + /* + * The next line essentially implements a cast + * from const, which is totally unavoidable. + */ + *(const void **) field = dv; + break; + } + } + } +} + +/**@}*/ + +/* + * ScannedMember slabs (an unpacking implementation detail). Before doing real + * unpacking, we first scan through the elements to see how many there are (for + * repeated fields), and which field to use (for non-repeated fields given + * twice). + * + * In order to avoid allocations for small messages, we keep a stack-allocated + * slab of ScannedMembers of size FIRST_SCANNED_MEMBER_SLAB_SIZE (16). After we + * fill that up, we allocate each slab twice as large as the previous one. + */ +#define FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2 4 + +/* + * The number of slabs, including the stack-allocated ones; choose the number so + * that we would overflow if we needed a slab larger than provided. + */ +#define MAX_SCANNED_MEMBER_SLAB \ + (sizeof(unsigned int)*8 - 1 \ + - BOUND_SIZEOF_SCANNED_MEMBER_LOG2 \ + - FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2) + +#define REQUIRED_FIELD_BITMAP_SET(index) \ + (required_fields_bitmap[(index)/8] |= (1UL<<((index)%8))) + +#define REQUIRED_FIELD_BITMAP_IS_SET(index) \ + (required_fields_bitmap[(index)/8] & (1UL<<((index)%8))) + +ProtobufCMessage * +protobuf_c_message_unpack(const ProtobufCMessageDescriptor *desc, + ProtobufCAllocator *allocator, + size_t len, const uint8_t *data) +{ + ProtobufCMessage *rv; + size_t rem = len; + const uint8_t *at = data; + const ProtobufCFieldDescriptor *last_field = desc->fields + 0; + ScannedMember first_member_slab[1UL << + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2]; + + /* + * scanned_member_slabs[i] is an array of arrays of ScannedMember. + * The first slab (scanned_member_slabs[0] is just a pointer to + * first_member_slab), above. All subsequent slabs will be allocated + * using the allocator. + */ + ScannedMember *scanned_member_slabs[MAX_SCANNED_MEMBER_SLAB + 1]; + unsigned which_slab = 0; /* the slab we are currently populating */ + unsigned in_slab_index = 0; /* number of members in the slab */ + size_t n_unknown = 0; + unsigned f; + unsigned j; + unsigned i_slab; + unsigned last_field_index = 0; + unsigned required_fields_bitmap_len; + unsigned char required_fields_bitmap_stack[16]; + unsigned char *required_fields_bitmap = required_fields_bitmap_stack; + protobuf_c_boolean required_fields_bitmap_alloced = FALSE; + + ASSERT_IS_MESSAGE_DESCRIPTOR(desc); + + if (allocator == NULL) + allocator = &protobuf_c__allocator; + + rv = do_alloc(allocator, desc->sizeof_message); + if (!rv) + return (NULL); + scanned_member_slabs[0] = first_member_slab; + + required_fields_bitmap_len = (desc->n_fields + 7) / 8; + if (required_fields_bitmap_len > sizeof(required_fields_bitmap_stack)) { + required_fields_bitmap = do_alloc(allocator, required_fields_bitmap_len); + if (!required_fields_bitmap) { + do_free(allocator, rv); + return (NULL); + } + required_fields_bitmap_alloced = TRUE; + } + memset(required_fields_bitmap, 0, required_fields_bitmap_len); + + /* + * Generated code always defines "message_init". However, we provide a + * fallback for (1) users of old protobuf-c generated-code that do not + * provide the function, and (2) descriptors constructed from some other + * source (most likely, direct construction from the .proto file). + */ + if (desc->message_init != NULL) + protobuf_c_message_init(desc, rv); + else + message_init_generic(desc, rv); + + while (rem > 0) { + uint32_t tag; + ProtobufCWireType wire_type; + size_t used = parse_tag_and_wiretype(rem, at, &tag, &wire_type); + const ProtobufCFieldDescriptor *field; + ScannedMember tmp; + + if (used == 0) { + PROTOBUF_C_UNPACK_ERROR("error parsing tag/wiretype at offset %u", + (unsigned) (at - data)); + goto error_cleanup_during_scan; + } + /* + * \todo Consider optimizing for field[1].id == tag, if field[1] + * exists! + */ + if (last_field == NULL || last_field->id != tag) { + /* lookup field */ + int field_index = + int_range_lookup(desc->n_field_ranges, + desc->field_ranges, + tag); + if (field_index < 0) { + field = NULL; + n_unknown++; + } else { + field = desc->fields + field_index; + last_field = field; + last_field_index = field_index; + } + } else { + field = last_field; + } + + if (field != NULL && field->label == PROTOBUF_C_LABEL_REQUIRED) + REQUIRED_FIELD_BITMAP_SET(last_field_index); + + at += used; + rem -= used; + tmp.tag = tag; + tmp.wire_type = wire_type; + tmp.field = field; + tmp.data = at; + tmp.length_prefix_len = 0; + + switch (wire_type) { + case PROTOBUF_C_WIRE_TYPE_VARINT: { + unsigned max_len = rem < 10 ? rem : 10; + unsigned i; + + for (i = 0; i < max_len; i++) + if ((at[i] & 0x80) == 0) + break; + if (i == max_len) { + PROTOBUF_C_UNPACK_ERROR("unterminated varint at offset %u", + (unsigned) (at - data)); + goto error_cleanup_during_scan; + } + tmp.len = i + 1; + break; + } + case PROTOBUF_C_WIRE_TYPE_64BIT: + if (rem < 8) { + PROTOBUF_C_UNPACK_ERROR("too short after 64bit wiretype at offset %u", + (unsigned) (at - data)); + goto error_cleanup_during_scan; + } + tmp.len = 8; + break; + case PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED: { + size_t pref_len; + + tmp.len = scan_length_prefixed_data(rem, at, &pref_len); + if (tmp.len == 0) { + /* NOTE: scan_length_prefixed_data calls UNPACK_ERROR */ + goto error_cleanup_during_scan; + } + tmp.length_prefix_len = pref_len; + break; + } + case PROTOBUF_C_WIRE_TYPE_32BIT: + if (rem < 4) { + PROTOBUF_C_UNPACK_ERROR("too short after 32bit wiretype at offset %u", + (unsigned) (at - data)); + goto error_cleanup_during_scan; + } + tmp.len = 4; + break; + default: + PROTOBUF_C_UNPACK_ERROR("unsupported tag %u at offset %u", + wire_type, (unsigned) (at - data)); + goto error_cleanup_during_scan; + } + + if (in_slab_index == (1UL << + (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2))) + { + size_t size; + + in_slab_index = 0; + if (which_slab == MAX_SCANNED_MEMBER_SLAB) { + PROTOBUF_C_UNPACK_ERROR("too many fields"); + goto error_cleanup_during_scan; + } + which_slab++; + size = sizeof(ScannedMember) + << (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2); + scanned_member_slabs[which_slab] = do_alloc(allocator, size); + if (scanned_member_slabs[which_slab] == NULL) + goto error_cleanup_during_scan; + } + scanned_member_slabs[which_slab][in_slab_index++] = tmp; + + if (field != NULL && field->label == PROTOBUF_C_LABEL_REPEATED) { + size_t *n = STRUCT_MEMBER_PTR(size_t, rv, + field->quantifier_offset); + if (wire_type == PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED && + (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) || + is_packable_type(field->type))) + { + size_t count; + if (!count_packed_elements(field->type, + tmp.len - + tmp.length_prefix_len, + tmp.data + + tmp.length_prefix_len, + &count)) + { + PROTOBUF_C_UNPACK_ERROR("counting packed elements"); + goto error_cleanup_during_scan; + } + *n += count; + } else { + *n += 1; + } + } + + at += tmp.len; + rem -= tmp.len; + } + + /* allocate space for repeated fields, also check that all required fields have been set */ + for (f = 0; f < desc->n_fields; f++) { + const ProtobufCFieldDescriptor *field = desc->fields + f; + if (field->label == PROTOBUF_C_LABEL_REPEATED) { + size_t siz = + sizeof_elt_in_repeated_array(field->type); + size_t *n_ptr = + STRUCT_MEMBER_PTR(size_t, rv, + field->quantifier_offset); + if (*n_ptr != 0) { + unsigned n = *n_ptr; + void *a; + *n_ptr = 0; + assert(rv->descriptor != NULL); +#define CLEAR_REMAINING_N_PTRS() \ + for(f++;f < desc->n_fields; f++) \ + { \ + field = desc->fields + f; \ + if (field->label == PROTOBUF_C_LABEL_REPEATED) \ + STRUCT_MEMBER (size_t, rv, field->quantifier_offset) = 0; \ + } + a = do_alloc(allocator, siz * n); + if (!a) { + CLEAR_REMAINING_N_PTRS(); + goto error_cleanup; + } + STRUCT_MEMBER(void *, rv, field->offset) = a; + } + } else if (field->label == PROTOBUF_C_LABEL_REQUIRED) { + if (field->default_value == NULL && + !REQUIRED_FIELD_BITMAP_IS_SET(f)) + { + CLEAR_REMAINING_N_PTRS(); + PROTOBUF_C_UNPACK_ERROR("message '%s': missing required field '%s'", + desc->name, field->name); + goto error_cleanup; + } + } + } +#undef CLEAR_REMAINING_N_PTRS + + /* allocate space for unknown fields */ + if (n_unknown) { + rv->unknown_fields = do_alloc(allocator, + n_unknown * sizeof(ProtobufCMessageUnknownField)); + if (rv->unknown_fields == NULL) + goto error_cleanup; + } + + /* do real parsing */ + for (i_slab = 0; i_slab <= which_slab; i_slab++) { + unsigned max = (i_slab == which_slab) ? + in_slab_index : (1UL << (i_slab + 4)); + ScannedMember *slab = scanned_member_slabs[i_slab]; + + for (j = 0; j < max; j++) { + if (!parse_member(slab + j, rv, allocator)) { + PROTOBUF_C_UNPACK_ERROR("error parsing member %s of %s", + slab->field ? slab->field->name : "*unknown-field*", + desc->name); + goto error_cleanup; + } + } + } + + /* cleanup */ + for (j = 1; j <= which_slab; j++) + do_free(allocator, scanned_member_slabs[j]); + if (required_fields_bitmap_alloced) + do_free(allocator, required_fields_bitmap); + return rv; + +error_cleanup: + protobuf_c_message_free_unpacked(rv, allocator); + for (j = 1; j <= which_slab; j++) + do_free(allocator, scanned_member_slabs[j]); + if (required_fields_bitmap_alloced) + do_free(allocator, required_fields_bitmap); + return NULL; + +error_cleanup_during_scan: + do_free(allocator, rv); + for (j = 1; j <= which_slab; j++) + do_free(allocator, scanned_member_slabs[j]); + if (required_fields_bitmap_alloced) + do_free(allocator, required_fields_bitmap); + return NULL; +} + +void +protobuf_c_message_free_unpacked(ProtobufCMessage *message, + ProtobufCAllocator *allocator) +{ + const ProtobufCMessageDescriptor *desc; + unsigned f; + + if (message == NULL) + return; + + desc = message->descriptor; + + ASSERT_IS_MESSAGE(message); + + if (allocator == NULL) + allocator = &protobuf_c__allocator; + message->descriptor = NULL; + for (f = 0; f < desc->n_fields; f++) { + if (0 != (desc->fields[f].flags & PROTOBUF_C_FIELD_FLAG_ONEOF) && + desc->fields[f].id != + STRUCT_MEMBER(uint32_t, message, desc->fields[f].quantifier_offset)) + { + /* This is not the selected oneof, skip it */ + continue; + } + + if (desc->fields[f].label == PROTOBUF_C_LABEL_REPEATED) { + size_t n = STRUCT_MEMBER(size_t, + message, + desc->fields[f].quantifier_offset); + void *arr = STRUCT_MEMBER(void *, + message, + desc->fields[f].offset); + + if (arr != NULL) { + if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) { + unsigned i; + for (i = 0; i < n; i++) + do_free(allocator, ((char **) arr)[i]); + } else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) { + unsigned i; + for (i = 0; i < n; i++) + do_free(allocator, ((ProtobufCBinaryData *) arr)[i].data); + } else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) { + unsigned i; + for (i = 0; i < n; i++) + protobuf_c_message_free_unpacked( + ((ProtobufCMessage **) arr)[i], + allocator + ); + } + do_free(allocator, arr); + } + } else if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) { + char *str = STRUCT_MEMBER(char *, message, + desc->fields[f].offset); + + if (str && str != desc->fields[f].default_value) + do_free(allocator, str); + } else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) { + void *data = STRUCT_MEMBER(ProtobufCBinaryData, message, + desc->fields[f].offset).data; + const ProtobufCBinaryData *default_bd; + + default_bd = desc->fields[f].default_value; + if (data != NULL && + (default_bd == NULL || + default_bd->data != data)) + { + do_free(allocator, data); + } + } else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) { + ProtobufCMessage *sm; + + sm = STRUCT_MEMBER(ProtobufCMessage *, message, + desc->fields[f].offset); + if (sm && sm != desc->fields[f].default_value) + protobuf_c_message_free_unpacked(sm, allocator); + } + } + + for (f = 0; f < message->n_unknown_fields; f++) + do_free(allocator, message->unknown_fields[f].data); + if (message->unknown_fields != NULL) + do_free(allocator, message->unknown_fields); + + do_free(allocator, message); +} + +void +protobuf_c_message_init(const ProtobufCMessageDescriptor * descriptor, + void *message) +{ + descriptor->message_init((ProtobufCMessage *) (message)); +} + +protobuf_c_boolean +protobuf_c_message_check(const ProtobufCMessage *message) +{ + unsigned i; + + if (!message || + !message->descriptor || + message->descriptor->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) + { + return FALSE; + } + + for (i = 0; i < message->descriptor->n_fields; i++) { + const ProtobufCFieldDescriptor *f = message->descriptor->fields + i; + ProtobufCType type = f->type; + ProtobufCLabel label = f->label; + void *field = STRUCT_MEMBER_P (message, f->offset); + + if (label == PROTOBUF_C_LABEL_REPEATED) { + size_t *quantity = STRUCT_MEMBER_P (message, f->quantifier_offset); + + if (*quantity > 0 && *(void **) field == NULL) { + return FALSE; + } + + if (type == PROTOBUF_C_TYPE_MESSAGE) { + ProtobufCMessage **submessage = *(ProtobufCMessage ***) field; + unsigned j; + for (j = 0; j < *quantity; j++) { + if (!protobuf_c_message_check(submessage[j])) + return FALSE; + } + } else if (type == PROTOBUF_C_TYPE_STRING) { + char **string = *(char ***) field; + unsigned j; + for (j = 0; j < *quantity; j++) { + if (!string[j]) + return FALSE; + } + } else if (type == PROTOBUF_C_TYPE_BYTES) { + ProtobufCBinaryData *bd = *(ProtobufCBinaryData **) field; + unsigned j; + for (j = 0; j < *quantity; j++) { + if (bd[j].len > 0 && bd[j].data == NULL) + return FALSE; + } + } + + } else { /* PROTOBUF_C_LABEL_REQUIRED or PROTOBUF_C_LABEL_OPTIONAL */ + + if (type == PROTOBUF_C_TYPE_MESSAGE) { + ProtobufCMessage *submessage = *(ProtobufCMessage **) field; + if (label == PROTOBUF_C_LABEL_REQUIRED || submessage != NULL) { + if (!protobuf_c_message_check(submessage)) + return FALSE; + } + } else if (type == PROTOBUF_C_TYPE_STRING) { + char *string = *(char **) field; + if (label == PROTOBUF_C_LABEL_REQUIRED && string == NULL) + return FALSE; + } else if (type == PROTOBUF_C_TYPE_BYTES) { + protobuf_c_boolean *has = STRUCT_MEMBER_P (message, f->quantifier_offset); + ProtobufCBinaryData *bd = field; + if (label == PROTOBUF_C_LABEL_REQUIRED || *has == TRUE) { + if (bd->len > 0 && bd->data == NULL) + return FALSE; + } + } + } + } + + return TRUE; +} + +/* === services === */ + +typedef void (*GenericHandler) (void *service, + const ProtobufCMessage *input, + ProtobufCClosure closure, + void *closure_data); +void +protobuf_c_service_invoke_internal(ProtobufCService *service, + unsigned method_index, + const ProtobufCMessage *input, + ProtobufCClosure closure, + void *closure_data) +{ + GenericHandler *handlers; + GenericHandler handler; + + /* + * Verify that method_index is within range. If this fails, you are + * likely invoking a newly added method on an old service. (Although + * other memory corruption bugs can cause this assertion too.) + */ + assert(method_index < service->descriptor->n_methods); + + /* + * Get the array of virtual methods (which are enumerated by the + * generated code). + */ + handlers = (GenericHandler *) (service + 1); + + /* + * Get our method and invoke it. + * \todo Seems like handler == NULL is a situation that needs handling. + */ + handler = handlers[method_index]; + (*handler)(service, input, closure, closure_data); +} + +void +protobuf_c_service_generated_init(ProtobufCService *service, + const ProtobufCServiceDescriptor *descriptor, + ProtobufCServiceDestroy destroy) +{ + ASSERT_IS_SERVICE_DESCRIPTOR(descriptor); + service->descriptor = descriptor; + service->destroy = destroy; + service->invoke = protobuf_c_service_invoke_internal; + memset(service + 1, 0, descriptor->n_methods * sizeof(GenericHandler)); +} + +void protobuf_c_service_destroy(ProtobufCService *service) +{ + service->destroy(service); +} + +/* --- querying the descriptors --- */ + +const ProtobufCEnumValue * +protobuf_c_enum_descriptor_get_value_by_name(const ProtobufCEnumDescriptor *desc, + const char *name) +{ + unsigned start = 0; + unsigned count; + + if (desc == NULL || desc->values_by_name == NULL) + return NULL; + + count = desc->n_value_names; + + while (count > 1) { + unsigned mid = start + count / 2; + int rv = strcmp(desc->values_by_name[mid].name, name); + if (rv == 0) + return desc->values + desc->values_by_name[mid].index; + else if (rv < 0) { + count = start + count - (mid + 1); + start = mid + 1; + } else + count = mid - start; + } + if (count == 0) + return NULL; + if (strcmp(desc->values_by_name[start].name, name) == 0) + return desc->values + desc->values_by_name[start].index; + return NULL; +} + +const ProtobufCEnumValue * +protobuf_c_enum_descriptor_get_value(const ProtobufCEnumDescriptor *desc, + int value) +{ + int rv = int_range_lookup(desc->n_value_ranges, desc->value_ranges, value); + if (rv < 0) + return NULL; + return desc->values + rv; +} + +const ProtobufCFieldDescriptor * +protobuf_c_message_descriptor_get_field_by_name(const ProtobufCMessageDescriptor *desc, + const char *name) +{ + unsigned start = 0; + unsigned count; + const ProtobufCFieldDescriptor *field; + + if (desc == NULL || desc->fields_sorted_by_name == NULL) + return NULL; + + count = desc->n_fields; + + while (count > 1) { + unsigned mid = start + count / 2; + int rv; + field = desc->fields + desc->fields_sorted_by_name[mid]; + rv = strcmp(field->name, name); + if (rv == 0) + return field; + else if (rv < 0) { + count = start + count - (mid + 1); + start = mid + 1; + } else + count = mid - start; + } + if (count == 0) + return NULL; + field = desc->fields + desc->fields_sorted_by_name[start]; + if (strcmp(field->name, name) == 0) + return field; + return NULL; +} + +const ProtobufCFieldDescriptor * +protobuf_c_message_descriptor_get_field(const ProtobufCMessageDescriptor *desc, + unsigned value) +{ + int rv = int_range_lookup(desc->n_field_ranges,desc->field_ranges, value); + if (rv < 0) + return NULL; + return desc->fields + rv; +} + +const ProtobufCMethodDescriptor * +protobuf_c_service_descriptor_get_method_by_name(const ProtobufCServiceDescriptor *desc, + const char *name) +{ + unsigned start = 0; + unsigned count; + + if (desc == NULL || desc->method_indices_by_name == NULL) + return NULL; + + count = desc->n_methods; + + while (count > 1) { + unsigned mid = start + count / 2; + unsigned mid_index = desc->method_indices_by_name[mid]; + const char *mid_name = desc->methods[mid_index].name; + int rv = strcmp(mid_name, name); + + if (rv == 0) + return desc->methods + desc->method_indices_by_name[mid]; + if (rv < 0) { + count = start + count - (mid + 1); + start = mid + 1; + } else { + count = mid - start; + } + } + if (count == 0) + return NULL; + if (strcmp(desc->methods[desc->method_indices_by_name[start]].name, name) == 0) + return desc->methods + desc->method_indices_by_name[start]; + return NULL; +} diff --git a/Software/Embedded_SW/Embedded/Common/protobuf-c/protobuf-c.h b/Software/Embedded_SW/Embedded/Common/protobuf-c/protobuf-c.h new file mode 100644 index 000000000..c8fa4fc2a --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/protobuf-c/protobuf-c.h @@ -0,0 +1,1106 @@ +/* + * Copyright (c) 2008-2017, Dave Benson and the protobuf-c authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*! \file + * \mainpage Introduction + * + * This is [protobuf-c], a C implementation of [Protocol Buffers]. + * + * This file defines the public API for the `libprotobuf-c` support library. + * This API includes interfaces that can be used directly by client code as well + * as the interfaces used by the code generated by the `protoc-c` compiler. + * + * The `libprotobuf-c` support library performs the actual serialization and + * deserialization of Protocol Buffers messages. It interacts with structures, + * definitions, and metadata generated by the `protoc-c` compiler from .proto + * files. + * + * \authors Dave Benson and the `protobuf-c` authors. + * + * \copyright 2008-2014. Licensed under the terms of the [BSD-2-Clause] license. + * + * [protobuf-c]: https://github.com/protobuf-c/protobuf-c + * [Protocol Buffers]: https://developers.google.com/protocol-buffers/ + * [BSD-2-Clause]: http://opensource.org/licenses/BSD-2-Clause + * + * \page gencode Generated Code + * + * For each enum, we generate a C enum. For each message, we generate a C + * structure which can be cast to a `ProtobufCMessage`. + * + * For each enum and message, we generate a descriptor object that allows us to + * implement a kind of reflection on the structures. + * + * First, some naming conventions: + * + * - The name of the type for enums and messages and services is camel case + * (meaning WordsAreCrammedTogether) except that double underscores are used + * to delimit scopes. For example, the following `.proto` file: + * +~~~{.proto} + package foo.bar; + message BazBah { + optional int32 val = 1; + } +~~~ + * + * would generate a C type `Foo__Bar__BazBah`. + * + * - Identifiers for functions and globals are all lowercase, with camel case + * words separated by single underscores. For example, one of the function + * prototypes generated by `protoc-c` for the above example: + * +~~~{.c} +Foo__Bar__BazBah * + foo__bar__baz_bah__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +~~~ + * + * - Identifiers for enum values contain an uppercase prefix which embeds the + * package name and the enum type name. + * + * - A double underscore is used to separate further components of identifier + * names. + * + * For example, in the name of the unpack function above, the package name + * `foo.bar` has become `foo__bar`, the message name BazBah has become + * `baz_bah`, and the method name is `unpack`. These are all joined with double + * underscores to form the C identifier `foo__bar__baz_bah__unpack`. + * + * We also generate descriptor objects for messages and enums. These are + * declared in the `.pb-c.h` files: + * +~~~{.c} +extern const ProtobufCMessageDescriptor foo__bar__baz_bah__descriptor; +~~~ + * + * The message structures all begin with `ProtobufCMessageDescriptor *` which is + * sufficient to allow them to be cast to `ProtobufCMessage`. + * + * For each message defined in a `.proto` file, we generate a number of + * functions and macros. Each function name contains a prefix based on the + * package name and message name in order to make it a unique C identifier. + * + * - `INIT`. Statically initializes a message object, initializing its + * descriptor and setting its fields to default values. Uninitialized + * messages cannot be processed by the protobuf-c library. + * +~~~{.c} +#define FOO__BAR__BAZ_BAH__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&foo__bar__baz_bah__descriptor), 0 } +~~~ + * - `init()`. Initializes a message object, initializing its descriptor and + * setting its fields to default values. Uninitialized messages cannot be + * processed by the protobuf-c library. + * +~~~{.c} +void foo__bar__baz_bah__init + (Foo__Bar__BazBah *message); +~~~ + * - `unpack()`. Unpacks data for a particular message format. Note that the + * `allocator` parameter is usually `NULL` to indicate that the system's + * `malloc()` and `free()` functions should be used for dynamically allocating + * memory. + * +~~~{.c} +Foo__Bar__BazBah * + foo__bar__baz_bah__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +~~~ + * + * - `free_unpacked()`. Frees a message object obtained with the `unpack()` + * method. Freeing `NULL` is allowed (the same as with `free()`). + * +~~~{.c} +void foo__bar__baz_bah__free_unpacked + (Foo__Bar__BazBah *message, + ProtobufCAllocator *allocator); +~~~ + * + * - `get_packed_size()`. Calculates the length in bytes of the serialized + * representation of the message object. + * +~~~{.c} +size_t foo__bar__baz_bah__get_packed_size + (const Foo__Bar__BazBah *message); +~~~ + * + * - `pack()`. Pack a message object into a preallocated buffer. Assumes that + * the buffer is large enough. (Use `get_packed_size()` first.) + * +~~~{.c} +size_t foo__bar__baz_bah__pack + (const Foo__Bar__BazBah *message, + uint8_t *out); +~~~ + * + * - `pack_to_buffer()`. Packs a message into a "virtual buffer". This is an + * object which defines an "append bytes" callback to consume data as it is + * serialized. + * +~~~{.c} +size_t foo__bar__baz_bah__pack_to_buffer + (const Foo__Bar__BazBah *message, + ProtobufCBuffer *buffer); +~~~ + * + * \page pack Packing and unpacking messages + * + * To pack a message, first compute the packed size of the message with + * protobuf_c_message_get_packed_size(), then allocate a buffer of at least + * that size, then call protobuf_c_message_pack(). + * + * Alternatively, a message can be serialized without calculating the final size + * first. Use the protobuf_c_message_pack_to_buffer() function and provide a + * ProtobufCBuffer object which implements an "append" method that consumes + * data. + * + * To unpack a message, call the protobuf_c_message_unpack() function. The + * result can be cast to an object of the type that matches the descriptor for + * the message. + * + * The result of unpacking a message should be freed with + * protobuf_c_message_free_unpacked(). + */ + +#ifndef PROTOBUF_C_H +#define PROTOBUF_C_H + +#include <assert.h> +#include <limits.h> +#include <stddef.h> +#include <stdint.h> + +#ifdef __cplusplus +# define PROTOBUF_C__BEGIN_DECLS extern "C" { +# define PROTOBUF_C__END_DECLS } +#else +# define PROTOBUF_C__BEGIN_DECLS +# define PROTOBUF_C__END_DECLS +#endif + +PROTOBUF_C__BEGIN_DECLS + +#if defined(_WIN32) && defined(PROTOBUF_C_USE_SHARED_LIB) +# ifdef PROTOBUF_C_EXPORT +# define PROTOBUF_C__API __declspec(dllexport) +# else +# define PROTOBUF_C__API __declspec(dllimport) +# endif +#else +# define PROTOBUF_C__API +#endif + +#if !defined(PROTOBUF_C__NO_DEPRECATED) && \ + ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define PROTOBUF_C__DEPRECATED __attribute__((__deprecated__)) +#else +# define PROTOBUF_C__DEPRECATED +#endif + +#ifndef PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE + #define PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(enum_name) \ + , _##enum_name##_IS_INT_SIZE = INT_MAX +#endif + +#define PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC 0x14159bc3 +#define PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC 0x28aaeef9 +#define PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC 0x114315af + +/* Empty string used for initializers */ +extern const char protobuf_c_empty_string[]; + +/** + * \defgroup api Public API + * + * This is the public API for `libprotobuf-c`. These interfaces are stable and + * subject to Semantic Versioning guarantees. + * + * @{ + */ + +/** + * Values for the `flags` word in `ProtobufCFieldDescriptor`. + */ +typedef enum { + /** Set if the field is repeated and marked with the `packed` option. */ + PROTOBUF_C_FIELD_FLAG_PACKED = (1 << 0), + + /** Set if the field is marked with the `deprecated` option. */ + PROTOBUF_C_FIELD_FLAG_DEPRECATED = (1 << 1), + + /** Set if the field is a member of a oneof (union). */ + PROTOBUF_C_FIELD_FLAG_ONEOF = (1 << 2), +} ProtobufCFieldFlag; + +/** + * Message field rules. + * + * \see [Defining A Message Type] in the Protocol Buffers documentation. + * + * [Defining A Message Type]: + * https://developers.google.com/protocol-buffers/docs/proto#simple + */ +typedef enum { + /** A well-formed message must have exactly one of this field. */ + PROTOBUF_C_LABEL_REQUIRED, + + /** + * A well-formed message can have zero or one of this field (but not + * more than one). + */ + PROTOBUF_C_LABEL_OPTIONAL, + + /** + * This field can be repeated any number of times (including zero) in a + * well-formed message. The order of the repeated values will be + * preserved. + */ + PROTOBUF_C_LABEL_REPEATED, + + /** + * This field has no label. This is valid only in proto3 and is + * equivalent to OPTIONAL but no "has" quantifier will be consulted. + */ + PROTOBUF_C_LABEL_NONE, +} ProtobufCLabel; + +/** + * Field value types. + * + * \see [Scalar Value Types] in the Protocol Buffers documentation. + * + * [Scalar Value Types]: + * https://developers.google.com/protocol-buffers/docs/proto#scalar + */ +typedef enum { + PROTOBUF_C_TYPE_INT32, /**< int32 */ + PROTOBUF_C_TYPE_SINT32, /**< signed int32 */ + PROTOBUF_C_TYPE_SFIXED32, /**< signed int32 (4 bytes) */ + PROTOBUF_C_TYPE_INT64, /**< int64 */ + PROTOBUF_C_TYPE_SINT64, /**< signed int64 */ + PROTOBUF_C_TYPE_SFIXED64, /**< signed int64 (8 bytes) */ + PROTOBUF_C_TYPE_UINT32, /**< unsigned int32 */ + PROTOBUF_C_TYPE_FIXED32, /**< unsigned int32 (4 bytes) */ + PROTOBUF_C_TYPE_UINT64, /**< unsigned int64 */ + PROTOBUF_C_TYPE_FIXED64, /**< unsigned int64 (8 bytes) */ + PROTOBUF_C_TYPE_FLOAT, /**< float */ + PROTOBUF_C_TYPE_DOUBLE, /**< double */ + PROTOBUF_C_TYPE_BOOL, /**< boolean */ + PROTOBUF_C_TYPE_ENUM, /**< enumerated type */ + PROTOBUF_C_TYPE_STRING, /**< UTF-8 or ASCII string */ + PROTOBUF_C_TYPE_BYTES, /**< arbitrary byte sequence */ + PROTOBUF_C_TYPE_MESSAGE, /**< nested message */ +} ProtobufCType; + +/** + * Field wire types. + * + * \see [Message Structure] in the Protocol Buffers documentation. + * + * [Message Structure]: + * https://developers.google.com/protocol-buffers/docs/encoding#structure + */ +typedef enum { + PROTOBUF_C_WIRE_TYPE_VARINT = 0, + PROTOBUF_C_WIRE_TYPE_64BIT = 1, + PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED = 2, + /* "Start group" and "end group" wire types are unsupported. */ + PROTOBUF_C_WIRE_TYPE_32BIT = 5, +} ProtobufCWireType; + +struct ProtobufCAllocator; +struct ProtobufCBinaryData; +struct ProtobufCBuffer; +struct ProtobufCBufferSimple; +struct ProtobufCEnumDescriptor; +struct ProtobufCEnumValue; +struct ProtobufCEnumValueIndex; +struct ProtobufCFieldDescriptor; +struct ProtobufCIntRange; +struct ProtobufCMessage; +struct ProtobufCMessageDescriptor; +struct ProtobufCMessageUnknownField; +struct ProtobufCMethodDescriptor; +struct ProtobufCService; +struct ProtobufCServiceDescriptor; + +typedef struct ProtobufCAllocator ProtobufCAllocator; +typedef struct ProtobufCBinaryData ProtobufCBinaryData; +typedef struct ProtobufCBuffer ProtobufCBuffer; +typedef struct ProtobufCBufferSimple ProtobufCBufferSimple; +typedef struct ProtobufCEnumDescriptor ProtobufCEnumDescriptor; +typedef struct ProtobufCEnumValue ProtobufCEnumValue; +typedef struct ProtobufCEnumValueIndex ProtobufCEnumValueIndex; +typedef struct ProtobufCFieldDescriptor ProtobufCFieldDescriptor; +typedef struct ProtobufCIntRange ProtobufCIntRange; +typedef struct ProtobufCMessage ProtobufCMessage; +typedef struct ProtobufCMessageDescriptor ProtobufCMessageDescriptor; +typedef struct ProtobufCMessageUnknownField ProtobufCMessageUnknownField; +typedef struct ProtobufCMethodDescriptor ProtobufCMethodDescriptor; +typedef struct ProtobufCService ProtobufCService; +typedef struct ProtobufCServiceDescriptor ProtobufCServiceDescriptor; + +/** Boolean type. */ +typedef int protobuf_c_boolean; + +typedef void (*ProtobufCClosure)(const ProtobufCMessage *, void *closure_data); +typedef void (*ProtobufCMessageInit)(ProtobufCMessage *); +typedef void (*ProtobufCServiceDestroy)(ProtobufCService *); + +/** + * Structure for defining a custom memory allocator. + */ +struct ProtobufCAllocator { + /** Function to allocate memory. */ + void *(*alloc)(void *allocator_data, size_t size); + + /** Function to free memory. */ + void (*free)(void *allocator_data, void *pointer); + + /** Opaque pointer passed to `alloc` and `free` functions. */ + void *allocator_data; +}; + +/** + * Structure for the protobuf `bytes` scalar type. + * + * The data contained in a `ProtobufCBinaryData` is an arbitrary sequence of + * bytes. It may contain embedded `NUL` characters and is not required to be + * `NUL`-terminated. + */ +struct ProtobufCBinaryData { + size_t len; /**< Number of bytes in the `data` field. */ + uint8_t *data; /**< Data bytes. */ +}; + +/** + * Structure for defining a virtual append-only buffer. Used by + * protobuf_c_message_pack_to_buffer() to abstract the consumption of serialized + * bytes. + * + * `ProtobufCBuffer` "subclasses" may be defined on the stack. For example, to + * write to a `FILE` object: + * +~~~{.c} +typedef struct { + ProtobufCBuffer base; + FILE *fp; +} BufferAppendToFile; + +static void +my_buffer_file_append(ProtobufCBuffer *buffer, + size_t len, + const uint8_t *data) +{ + BufferAppendToFile *file_buf = (BufferAppendToFile *) buffer; + fwrite(data, len, 1, file_buf->fp); // XXX: No error handling! +} +~~~ + * + * To use this new type of ProtobufCBuffer, it could be called as follows: + * +~~~{.c} +... +BufferAppendToFile tmp = {0}; +tmp.base.append = my_buffer_file_append; +tmp.fp = fp; +protobuf_c_message_pack_to_buffer(&message, &tmp); +... +~~~ + */ +struct ProtobufCBuffer { + /** Append function. Consumes the `len` bytes stored at `data`. */ + void (*append)(ProtobufCBuffer *buffer, + size_t len, + const uint8_t *data); +}; + +/** + * Simple buffer "subclass" of `ProtobufCBuffer`. + * + * A `ProtobufCBufferSimple` object is declared on the stack and uses a + * scratch buffer provided by the user for the initial allocation. It performs + * exponential resizing, using dynamically allocated memory. A + * `ProtobufCBufferSimple` object can be created and used as follows: + * +~~~{.c} +uint8_t pad[128]; +ProtobufCBufferSimple simple = PROTOBUF_C_BUFFER_SIMPLE_INIT(pad); +ProtobufCBuffer *buffer = (ProtobufCBuffer *) &simple; +~~~ + * + * `buffer` can now be used with `protobuf_c_message_pack_to_buffer()`. Once a + * message has been serialized to a `ProtobufCBufferSimple` object, the + * serialized data bytes can be accessed from the `.data` field. + * + * To free the memory allocated by a `ProtobufCBufferSimple` object, if any, + * call PROTOBUF_C_BUFFER_SIMPLE_CLEAR() on the object, for example: + * +~~~{.c} +PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple); +~~~ + * + * \see PROTOBUF_C_BUFFER_SIMPLE_INIT + * \see PROTOBUF_C_BUFFER_SIMPLE_CLEAR + */ +struct ProtobufCBufferSimple { + /** "Base class". */ + ProtobufCBuffer base; + /** Number of bytes allocated in `data`. */ + size_t alloced; + /** Number of bytes currently stored in `data`. */ + size_t len; + /** Data bytes. */ + uint8_t *data; + /** Whether `data` must be freed. */ + protobuf_c_boolean must_free_data; + /** Allocator to use. May be NULL to indicate the system allocator. */ + ProtobufCAllocator *allocator; +}; + +/** + * Describes an enumeration as a whole, with all of its values. + */ +struct ProtobufCEnumDescriptor { + /** Magic value checked to ensure that the API is used correctly. */ + uint32_t magic; + + /** The qualified name (e.g., "namespace.Type"). */ + const char *name; + /** The unqualified name as given in the .proto file (e.g., "Type"). */ + const char *short_name; + /** Identifier used in generated C code. */ + const char *c_name; + /** The dot-separated namespace. */ + const char *package_name; + + /** Number elements in `values`. */ + unsigned n_values; + /** Array of distinct values, sorted by numeric value. */ + const ProtobufCEnumValue *values; + + /** Number of elements in `values_by_name`. */ + unsigned n_value_names; + /** Array of named values, including aliases, sorted by name. */ + const ProtobufCEnumValueIndex *values_by_name; + + /** Number of elements in `value_ranges`. */ + unsigned n_value_ranges; + /** Value ranges, for faster lookups by numeric value. */ + const ProtobufCIntRange *value_ranges; + + /** Reserved for future use. */ + void *reserved1; + /** Reserved for future use. */ + void *reserved2; + /** Reserved for future use. */ + void *reserved3; + /** Reserved for future use. */ + void *reserved4; +}; + +/** + * Represents a single value of an enumeration. + */ +struct ProtobufCEnumValue { + /** The string identifying this value in the .proto file. */ + const char *name; + + /** The string identifying this value in generated C code. */ + const char *c_name; + + /** The numeric value assigned in the .proto file. */ + int value; +}; + +/** + * Used by `ProtobufCEnumDescriptor` to look up enum values. + */ +struct ProtobufCEnumValueIndex { + /** Name of the enum value. */ + const char *name; + /** Index into values[] array. */ + unsigned index; +}; + +/** + * Describes a single field in a message. + */ +struct ProtobufCFieldDescriptor { + /** Name of the field as given in the .proto file. */ + const char *name; + + /** Tag value of the field as given in the .proto file. */ + uint32_t id; + + /** Whether the field is `REQUIRED`, `OPTIONAL`, or `REPEATED`. */ + ProtobufCLabel label; + + /** The type of the field. */ + ProtobufCType type; + + /** + * The offset in bytes of the message's C structure's quantifier field + * (the `has_MEMBER` field for optional members or the `n_MEMBER` field + * for repeated members or the case enum for oneofs). + */ + unsigned quantifier_offset; + + /** + * The offset in bytes into the message's C structure for the member + * itself. + */ + unsigned offset; + + /** + * A type-specific descriptor. + * + * If `type` is `PROTOBUF_C_TYPE_ENUM`, then `descriptor` points to the + * corresponding `ProtobufCEnumDescriptor`. + * + * If `type` is `PROTOBUF_C_TYPE_MESSAGE`, then `descriptor` points to + * the corresponding `ProtobufCMessageDescriptor`. + * + * Otherwise this field is NULL. + */ + const void *descriptor; /* for MESSAGE and ENUM types */ + + /** The default value for this field, if defined. May be NULL. */ + const void *default_value; + + /** + * A flag word. Zero or more of the bits defined in the + * `ProtobufCFieldFlag` enum may be set. + */ + uint32_t flags; + + /** Reserved for future use. */ + unsigned reserved_flags; + /** Reserved for future use. */ + void *reserved2; + /** Reserved for future use. */ + void *reserved3; +}; + +/** + * Helper structure for optimizing int => index lookups in the case + * where the keys are mostly consecutive values, as they presumably are for + * enums and fields. + * + * The data structures requires that the values in the original array are + * sorted. + */ +struct ProtobufCIntRange { + int start_value; + unsigned orig_index; + /* + * NOTE: the number of values in the range can be inferred by looking + * at the next element's orig_index. A dummy element is added to make + * this simple. + */ +}; + +/** + * An instance of a message. + * + * `ProtobufCMessage` is a light-weight "base class" for all messages. + * + * In particular, `ProtobufCMessage` doesn't have any allocation policy + * associated with it. That's because it's common to create `ProtobufCMessage` + * objects on the stack. In fact, that's what we recommend for sending messages. + * If the object is allocated from the stack, you can't really have a memory + * leak. + * + * This means that calls to functions like protobuf_c_message_unpack() which + * return a `ProtobufCMessage` must be paired with a call to a free function, + * like protobuf_c_message_free_unpacked(). + */ +struct ProtobufCMessage { + /** The descriptor for this message type. */ + const ProtobufCMessageDescriptor *descriptor; + /** The number of elements in `unknown_fields`. */ + unsigned n_unknown_fields; + /** The fields that weren't recognized by the parser. */ + ProtobufCMessageUnknownField *unknown_fields; +}; + +/** + * Describes a message. + */ +struct ProtobufCMessageDescriptor { + /** Magic value checked to ensure that the API is used correctly. */ + uint32_t magic; + + /** The qualified name (e.g., "namespace.Type"). */ + const char *name; + /** The unqualified name as given in the .proto file (e.g., "Type"). */ + const char *short_name; + /** Identifier used in generated C code. */ + const char *c_name; + /** The dot-separated namespace. */ + const char *package_name; + + /** + * Size in bytes of the C structure representing an instance of this + * type of message. + */ + size_t sizeof_message; + + /** Number of elements in `fields`. */ + unsigned n_fields; + /** Field descriptors, sorted by tag number. */ + const ProtobufCFieldDescriptor *fields; + /** Used for looking up fields by name. */ + const unsigned *fields_sorted_by_name; + + /** Number of elements in `field_ranges`. */ + unsigned n_field_ranges; + /** Used for looking up fields by id. */ + const ProtobufCIntRange *field_ranges; + + /** Message initialisation function. */ + ProtobufCMessageInit message_init; + + /** Reserved for future use. */ + void *reserved1; + /** Reserved for future use. */ + void *reserved2; + /** Reserved for future use. */ + void *reserved3; +}; + +/** + * An unknown message field. + */ +struct ProtobufCMessageUnknownField { + /** The tag number. */ + uint32_t tag; + /** The wire type of the field. */ + ProtobufCWireType wire_type; + /** Number of bytes in `data`. */ + size_t len; + /** Field data. */ + uint8_t *data; +}; + +/** + * Method descriptor. + */ +struct ProtobufCMethodDescriptor { + /** Method name. */ + const char *name; + /** Input message descriptor. */ + const ProtobufCMessageDescriptor *input; + /** Output message descriptor. */ + const ProtobufCMessageDescriptor *output; +}; + +/** + * Service. + */ +struct ProtobufCService { + /** Service descriptor. */ + const ProtobufCServiceDescriptor *descriptor; + /** Function to invoke the service. */ + void (*invoke)(ProtobufCService *service, + unsigned method_index, + const ProtobufCMessage *input, + ProtobufCClosure closure, + void *closure_data); + /** Function to destroy the service. */ + void (*destroy)(ProtobufCService *service); +}; + +/** + * Service descriptor. + */ +struct ProtobufCServiceDescriptor { + /** Magic value checked to ensure that the API is used correctly. */ + uint32_t magic; + + /** Service name. */ + const char *name; + /** Short version of service name. */ + const char *short_name; + /** C identifier for the service name. */ + const char *c_name; + /** Package name. */ + const char *package; + /** Number of elements in `methods`. */ + unsigned n_methods; + /** Method descriptors, in the order defined in the .proto file. */ + const ProtobufCMethodDescriptor *methods; + /** Sort index of methods. */ + const unsigned *method_indices_by_name; +}; + +/** + * Get the version of the protobuf-c library. Note that this is the version of + * the library linked against, not the version of the headers compiled against. + * + * \return A string containing the version number of protobuf-c. + */ +PROTOBUF_C__API +const char * +protobuf_c_version(void); + +/** + * Get the version of the protobuf-c library. Note that this is the version of + * the library linked against, not the version of the headers compiled against. + * + * \return A 32 bit unsigned integer containing the version number of + * protobuf-c, represented in base-10 as (MAJOR*1E6) + (MINOR*1E3) + PATCH. + */ +PROTOBUF_C__API +uint32_t +protobuf_c_version_number(void); + +/** + * The version of the protobuf-c headers, represented as a string using the same + * format as protobuf_c_version(). + */ +#define PROTOBUF_C_VERSION "1.3.0" + +/** + * The version of the protobuf-c headers, represented as an integer using the + * same format as protobuf_c_version_number(). + */ +#define PROTOBUF_C_VERSION_NUMBER 1003000 + +/** + * The minimum protoc-c version which works with the current version of the + * protobuf-c headers. + */ +#define PROTOBUF_C_MIN_COMPILER_VERSION 1000000 + +/** + * Look up a `ProtobufCEnumValue` from a `ProtobufCEnumDescriptor` by name. + * + * \param desc + * The `ProtobufCEnumDescriptor` object. + * \param name + * The `name` field from the corresponding `ProtobufCEnumValue` object to + * match. + * \return + * A `ProtobufCEnumValue` object. + * \retval NULL + * If not found or if the optimize_for = CODE_SIZE option was set. + */ +PROTOBUF_C__API +const ProtobufCEnumValue * +protobuf_c_enum_descriptor_get_value_by_name( + const ProtobufCEnumDescriptor *desc, + const char *name); + +/** + * Look up a `ProtobufCEnumValue` from a `ProtobufCEnumDescriptor` by numeric + * value. + * + * \param desc + * The `ProtobufCEnumDescriptor` object. + * \param value + * The `value` field from the corresponding `ProtobufCEnumValue` object to + * match. + * + * \return + * A `ProtobufCEnumValue` object. + * \retval NULL + * If not found. + */ +PROTOBUF_C__API +const ProtobufCEnumValue * +protobuf_c_enum_descriptor_get_value( + const ProtobufCEnumDescriptor *desc, + int value); + +/** + * Look up a `ProtobufCFieldDescriptor` from a `ProtobufCMessageDescriptor` by + * the name of the field. + * + * \param desc + * The `ProtobufCMessageDescriptor` object. + * \param name + * The name of the field. + * \return + * A `ProtobufCFieldDescriptor` object. + * \retval NULL + * If not found or if the optimize_for = CODE_SIZE option was set. + */ +PROTOBUF_C__API +const ProtobufCFieldDescriptor * +protobuf_c_message_descriptor_get_field_by_name( + const ProtobufCMessageDescriptor *desc, + const char *name); + +/** + * Look up a `ProtobufCFieldDescriptor` from a `ProtobufCMessageDescriptor` by + * the tag value of the field. + * + * \param desc + * The `ProtobufCMessageDescriptor` object. + * \param value + * The tag value of the field. + * \return + * A `ProtobufCFieldDescriptor` object. + * \retval NULL + * If not found. + */ +PROTOBUF_C__API +const ProtobufCFieldDescriptor * +protobuf_c_message_descriptor_get_field( + const ProtobufCMessageDescriptor *desc, + unsigned value); + +/** + * Determine the number of bytes required to store the serialised message. + * + * \param message + * The message object to serialise. + * \return + * Number of bytes. + */ +PROTOBUF_C__API +size_t +protobuf_c_message_get_packed_size(const ProtobufCMessage *message); + +/** + * Serialise a message from its in-memory representation. + * + * This function stores the serialised bytes of the message in a pre-allocated + * buffer. + * + * \param message + * The message object to serialise. + * \param[out] out + * Buffer to store the bytes of the serialised message. This buffer must + * have enough space to store the packed message. Use + * protobuf_c_message_get_packed_size() to determine the number of bytes + * required. + * \return + * Number of bytes stored in `out`. + */ +PROTOBUF_C__API +size_t +protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out); + +/** + * Serialise a message from its in-memory representation to a virtual buffer. + * + * This function calls the `append` method of a `ProtobufCBuffer` object to + * consume the bytes generated by the serialiser. + * + * \param message + * The message object to serialise. + * \param buffer + * The virtual buffer object. + * \return + * Number of bytes passed to the virtual buffer. + */ +PROTOBUF_C__API +size_t +protobuf_c_message_pack_to_buffer( + const ProtobufCMessage *message, + ProtobufCBuffer *buffer); + +/** + * Unpack a serialised message into an in-memory representation. + * + * \param descriptor + * The message descriptor. + * \param allocator + * `ProtobufCAllocator` to use for memory allocation. May be NULL to + * specify the default allocator. + * \param len + * Length in bytes of the serialised message. + * \param data + * Pointer to the serialised message. + * \return + * An unpacked message object. + * \retval NULL + * If an error occurred during unpacking. + */ +PROTOBUF_C__API +ProtobufCMessage * +protobuf_c_message_unpack( + const ProtobufCMessageDescriptor *descriptor, + ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); + +/** + * Free an unpacked message object. + * + * This function should be used to deallocate the memory used by a call to + * protobuf_c_message_unpack(). + * + * \param message + * The message object to free. May be NULL. + * \param allocator + * `ProtobufCAllocator` to use for memory deallocation. May be NULL to + * specify the default allocator. + */ +PROTOBUF_C__API +void +protobuf_c_message_free_unpacked( + ProtobufCMessage *message, + ProtobufCAllocator *allocator); + +/** + * Check the validity of a message object. + * + * Makes sure all required fields (`PROTOBUF_C_LABEL_REQUIRED`) are present. + * Recursively checks nested messages. + * + * \retval TRUE + * Message is valid. + * \retval FALSE + * Message is invalid. + */ +PROTOBUF_C__API +protobuf_c_boolean +protobuf_c_message_check(const ProtobufCMessage *); + +/** Message initialiser. */ +#define PROTOBUF_C_MESSAGE_INIT(descriptor) { descriptor, 0, NULL } + +/** + * Initialise a message object from a message descriptor. + * + * \param descriptor + * Message descriptor. + * \param message + * Allocated block of memory of size `descriptor->sizeof_message`. + */ +PROTOBUF_C__API +void +protobuf_c_message_init( + const ProtobufCMessageDescriptor *descriptor, + void *message); + +/** + * Free a service. + * + * \param service + * The service object to free. + */ +PROTOBUF_C__API +void +protobuf_c_service_destroy(ProtobufCService *service); + +/** + * Look up a `ProtobufCMethodDescriptor` by name. + * + * \param desc + * Service descriptor. + * \param name + * Name of the method. + * + * \return + * A `ProtobufCMethodDescriptor` object. + * \retval NULL + * If not found or if the optimize_for = CODE_SIZE option was set. + */ +PROTOBUF_C__API +const ProtobufCMethodDescriptor * +protobuf_c_service_descriptor_get_method_by_name( + const ProtobufCServiceDescriptor *desc, + const char *name); + +/** + * Initialise a `ProtobufCBufferSimple` object. + */ +#define PROTOBUF_C_BUFFER_SIMPLE_INIT(array_of_bytes) \ +{ \ + { protobuf_c_buffer_simple_append }, \ + sizeof(array_of_bytes), \ + 0, \ + (array_of_bytes), \ + 0, \ + NULL \ +} + +/** + * Clear a `ProtobufCBufferSimple` object, freeing any allocated memory. + */ +#define PROTOBUF_C_BUFFER_SIMPLE_CLEAR(simp_buf) \ +do { \ + if ((simp_buf)->must_free_data) { \ + if ((simp_buf)->allocator != NULL) \ + (simp_buf)->allocator->free( \ + (simp_buf)->allocator, \ + (simp_buf)->data); \ + else \ + free((simp_buf)->data); \ + } \ +} while (0) + +/** + * The `append` method for `ProtobufCBufferSimple`. + * + * \param buffer + * The buffer object to append to. Must actually be a + * `ProtobufCBufferSimple` object. + * \param len + * Number of bytes in `data`. + * \param data + * Data to append. + */ +PROTOBUF_C__API +void +protobuf_c_buffer_simple_append( + ProtobufCBuffer *buffer, + size_t len, + const unsigned char *data); + +PROTOBUF_C__API +void +protobuf_c_service_generated_init( + ProtobufCService *service, + const ProtobufCServiceDescriptor *descriptor, + ProtobufCServiceDestroy destroy); + +PROTOBUF_C__API +void +protobuf_c_service_invoke_internal( + ProtobufCService *service, + unsigned method_index, + const ProtobufCMessage *input, + ProtobufCClosure closure, + void *closure_data); + +/**@}*/ + +PROTOBUF_C__END_DECLS + +#endif /* PROTOBUF_C_H */ diff --git a/Software/Embedded_SW/Embedded/Common/report/distributor.c b/Software/Embedded_SW/Embedded/Common/report/distributor.c new file mode 100644 index 000000000..38b9ccff8 --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/report/distributor.c @@ -0,0 +1,851 @@ +/****************************************************************************** + * 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[REPORT_MAX_MSG_LEN]; + char FileName[REPORT_MAX_MSG_LEN]; + int LineNumber; + int errorCode; + ErrorSeverity severity; + int parameter1; + int parameter2; +}INPUT_MESSAGE; + +#define INPUT_MESSAGE_LEN sizeof(INPUT_MESSAGE) + +typedef struct +{ + int fd; + ReportFunction function; +}DESTINATION; + +#define DESTINATION_SIZE sizeof(DESTINATION) + +#define NUM_OF_DESTINATIONS 4 +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<NUM_OF_DESTINATIONS; j++) + { + Dist_Table[i].dest[j].fd = -1; + Dist_Table[i].dest[j].function = NULL; + } + Dist_Table[i].IsActive = false; + Dist_Table[i].IsAlive = false; + } + /* Reset the internal (basic) distributor */ + strcpy(Dist_Table[0].name,REPORT_ROOT_NAME); + Dist_Table[0].IsActive = true; + Dist_Table[0].IsAlive = true; + + /* initialize local data */ + DistCounter = 1; + + initialized = true; + return OK; +} + + +/*************************************************************************** + * + * Name : reportDistribute + * + * Function : Send message to destibutor + * + * Notes : Function trancates message if it length grater + * than INPUT_MESSAGE_LEN + * + * Parameters: message - user message + * extErrorType - error type and severity + * errorCode - error code + * parameter1 - user parameter 1 + * parameter2 - user parameter 2 + * + * Return value: STATUS - OK or ERROR + **************************************************************************/ +STATUS reportDistribute(FormatType format, + const char *message, + char *FileName, + int LineNumber, + int errorCode, + ErrorSeverity severity, + int parameter1, + int parameter2) +{ + INPUT_MESSAGE msg; + int Distributor = GET_PRIVATE_SEVERITY(severity); + + if (Distributor > 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; + strncpy(msg.message, message, REPORT_MAX_MSG_LEN); + 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; + + 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.parameter2); + } +} + +/*----------------------------------------------------------------------------*/ +/*----------------------------- 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; index++) + if (strcmp(Dist_Table[index].name,distributorName)==0) + { + if (SwitchAddRemove == REPORT_ADD) + { + if (Dist_Table[index].IsAlive) + { + errno = REPORT_ERROR_NAME_EXISTS; + return -1; + } + else + { + Dist_Table[index].IsAlive = true; + return index; + } + } + else /* Private severity disable */ + { + if (Dist_Table[index].IsAlive) + { + Dist_Table[index].IsAlive = false; + return index; + } + else + { + errno = REPORT_ERROR_NAME_ALREADY_DISABLE; + return -1; + } + } + } + if (SwitchAddRemove == REPORT_REMOVE) + { + errno = REPORT_ERROR_NAME_NOT_EXISTS; + return -1; /* nothing to remove */ + } + strcpy(Dist_Table[DistCounter].name,distributorName); + Dist_Table[DistCounter].IsAlive = true; + DistCounter++; + return (DistCounter-1); +} + + +/*************************************************************************** + * + * Name : ReportAddDistributor + * + * Function : Add static distributor + * + * Notes : + * + * Parameters: distributorName - The name must be up to 10 letters long + * + * Return value: the new distributor handle, or -1 and thus: + * errno = REPORT_ERROR_NAME_TOO_LONG in case of long name, + * errno = REPORT_ERROR_TABLE_FULL if there are already too + * many distributors, + * errno = REPORT_ERROR_NAME_EXISTS if the distributorName + * already exists. + **************************************************************************/ +DistributorHandle ReportAddDistributor(const char *distributorName) +{ + return ReportDistributor(distributorName,REPORT_ADD); +} + + +/*************************************************************************** + * + * Name : ReportRemoveDistributor + * + * Function : Remove static distributor + * + * Notes : The distributor's messages will be discarded. + * Its name will be no longer seen in the distributor's list + * when the REP_CONTROL is typed in the Monitor. + * + * Parameters: distributorName - The severity's name must be up to 10 + * letters long. + * + * Return value: OK; or ERROR and thus errno is set to one of the following: + * 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. + **************************************************************************/ +STATUS ReportRemoveDistributor(const char *distributorName) +{ + return ReportDistributor(distributorName,REPORT_REMOVE); +} + + +/*************************************************************************** + * + * Name : ReportDistributorControl + * + * Function : Disable / enable the flow of reports given its static + * severity + * + * Notes : Disable reports using the constant REPORT_OFF + * Enable the reports using the constant REPORT_ON + * + * Return value: OK or ERROR if illegal Distributor + **************************************************************************/ +STATUS ReportDistributorControl(DistributorHandle Distributor, uint32_t SwitchOnOff) +{ + if ((Distributor > 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; + + 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 pointer */ + if( func == NULL ) + { + errno = REPORT_ERROR_ILLEGAL_PARAMETER; + return ERROR; + } + + /* search for func - if already exists */ + for( i = 0; i < NUM_OF_DESTINATIONS; i++ ) + if (Dist_Table[Distributor].dest[i].function == func) + break; + + if (i == NUM_OF_DESTINATIONS) + { + if (SwitchAddRemove == REPORT_REMOVE) /* nothing to remove */ + { + errno = REPORT_ERROR_CODE_NOT_FOUND; + return ERROR; + } + /* Add routine */ + /* add new destination to the end of the table */ + Dist_Table[Distributor].dest[index].function = func; + /* set the fd to illegal value to ensure that destination is nothing but function */ + Dist_Table[Distributor].dest[index].fd = -1; + } + else if (SwitchAddRemove == REPORT_ADD) + return OK; /* this routine is already exists in the table */ + else /* Remove routine */ + Dist_Table[Distributor].dest[i].function = NULL; + 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 <ENTER>). + * 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 + * + */ + +static void messageDistribute(char *msg, + int DistTableEntry, + char *FileName, + int LineNumber, + int errorCode, + int parameter1, + int parameter2) +{ + 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); + } +} + + +/*------------- 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<NUM_OF_DESTINATIONS; index++) + if ((Dist_Table[DistTableEntry].dest[index].fd == -1) && + (Dist_Table[DistTableEntry].dest[index].function == NULL)) + return index; + + return ERROR; +} + + +/*************************************************************************** + * + * Name : ReportStrCmp + * + * Function : compare between two string with case-insensitive. + * + * Notes : + * + * Return value: true - strings are identical; false - otherwise + **************************************************************************/ +bool ReportStrCmp(const char *str1, const char *str2) +{ + int i=0; + + while ((str1[i] != '\0') || (str2[i] != '\0')) + { + if (tolower(str1[i]) != tolower(str2[i])) + return false; + i++; + } + if ((str1[i] == '\0') && (str2[i] == '\0')) + return true; + return false; +} + + +/*************************************************************************** + * + * Name : IsNameExistsInDistributorTable + * + * Function : Check if a given name is already found in the table + * of the static severities + * + * Notes : + * + * Return value: true if found; false otherwise + **************************************************************************/ +bool IsNameExistsInDistributorTable(const char *name) +{ + int index; + + for (index=0; index<=DistCounter; index++) + if (ReportStrCmp(name,Dist_Table[index].name) == true) + return true; + return false; + +} + + diff --git a/Software/Embedded_SW/Embedded/Common/report/distributor.h b/Software/Embedded_SW/Embedded/Common/report/distributor.h new file mode 100644 index 000000000..4b7f9185a --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/report/distributor.h @@ -0,0 +1,94 @@ + +#ifndef __RDISTRIBUTOR_H__ +#define __RDISTRIBUTOR_H__ + +/* The following enum is to inform about the kind of message format. For example: + * MESSAGE_FORMAT: this is a message + * REPORT_FORMAT: distributor.h.7, Error: this is a message. 0, (0x0,0x1) */ +typedef enum { MESSAGE_FORMAT, REPORT_FORMAT } FormatType; + +/* Use the following macro in order to get the private severity as the */ +/* severity parameter from one of the Report routines */ +#define GET_PRIVATE_SEVERITY(handle) (DistributorHandle)((handle)>>5) + +/* The mask of currently enabled severity. */ +extern bool filterTest(ErrorSeverity severity); + +extern STATUS distibutorInit( int priority, int maxMsgs, int maxDestinations ); + +extern STATUS reportDistribute(FormatType format, + const char *message, + char *FileName, + int LineNumber, + int errorCode, + ErrorSeverity severity, + int parameter1, + int parameter2); + + +/*************************************************************************** + * + * Name : ReportStrCmp + * + * Function : compare between two string with case-insensitive. + * + * Notes : + * + * Return value: TRUE - strings are identical; FALSE - otherwise + **************************************************************************/ +extern bool ReportStrCmp(const char *str1, const char *str2); + + +/*************************************************************************** + * + * Name : IsNameExistsInDistributorTable + * + * Function : Check if a given name is already found in the table + * of the private severities + * + * Notes : + * + * Return value: TRUE if found; FALSE otherwise + **************************************************************************/ +extern bool IsNameExistsInDistributorTable(const char *name); + +/*************************************************************************** + * + * Name : ReportGetDistributorHandleByName + * + * Function : Get the severity handle given the severity's name + * + * Notes : + * + * Return value: the handle; or -1 if no such name + **************************************************************************/ +extern DistributorHandle ReportGetDistributorHandleByName(const char *distributorName); + + +/*************************************************************************** + * + * Name : GetDistributorParamsByHandle + * + * Function : Get the private severity details according to its handle + * + * Parameters : DistributorHandle - table entry + * name - buffer to contain the private severity's name + * IsActive - FALSE if the private severity + * + * 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 private + * severity has already removed (and thus it is no + * no longer exists until re-added). + **************************************************************************/ +extern STATUS GetDistributorParamsByHandle(uint32_t DistributorHandle, + char *name, + bool *IsActive); +/* Total message length w/o message text in bytes + (for reportMsgFormat function ) */ +#define REPORT_MSG_FORMAT_LEN 61 + +#endif /* __RDISTRIBUTOR_H__ */ + diff --git a/Software/Embedded_SW/Embedded/Common/report/filter.c b/Software/Embedded_SW/Embedded/Common/report/filter.c new file mode 100644 index 000000000..7efc56d36 --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/report/filter.c @@ -0,0 +1,526 @@ + /*+************************************************************************* + * File name : FILTER.C + * Title : TERMINAL DRIVER INTERFACE + * Project : NEVADA + * Subsystem : SYSTEM + * Date created: 18 SEP, 1997 + * Revision : Rev 1.0 + * Author : Zvika Zilberman + * History : 18.09.97 Zvika Zilberman - porting to DCME SWINFRA + * + * Description : This file includes the FILTER part of the report package + * + * + * Procedures: + * + * Report - Report message using filters and message multiplexing. + * ReportSeveritySet - Set message severity + * + ******************************************************************************/ + +#include "report.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include "stdint.h" /* RETCODE */ +#include "filter.h" +#include "distributor.h" /* reportDistribute */ + +#define MAX_STRING_LEN 255 + +/*------------- Local Data ------------------------------*/ + +/* the filter's table */ + +packageFilter *packageFilterTable; +uint8_t filterTableSize; +uint8_t filterNumOfCurrentEntries; + +/* The mask of currently enabled severity. */ +static ErrorSeverity SeverityLevel; + +/* flag allows or dennies filter usage */ +static bool filterDontUse; + + +/*************************************************************************** + * + * Name : filterTableInit + * + * Function : Init the filtering mechanism + * + * Notes : + * + * Return value: OK; ERROR if malloc is failed + **************************************************************************/ +STATUS filterTableInit(uint32_t TableSize) +{ + int index; + + filterTableSize = TableSize; + packageFilterTable = (packageFilter*)malloc(sizeof(packageFilter)*TableSize); + if (packageFilterTable == NULL) + return ERROR; + for (index=0; index<TableSize; index++) + packageFilterTable[index].IsActive = true; + filterNumOfCurrentEntries = 0; + return OK; +} + + +/*************************************************************************** + * + * Name : ReportFilterPackage + * + * Function : Add or remove a filter to/from the filter's data base + * + * Notes : + * + * Parameters : filterName - The filter's name must be up to 10 letters + * long + * SwitchAddRemove - REPORT_ADD to add the new filter, + * REPORT_REMOVE to remove it. + * + * Return value: the new filter handle; or -1 in case of an ERROR, thus: + * errno = REPORT_ERROR_NAME_TOO_LONG in case of long name, + * errno = REPORT_ERROR_TABLE_FULL if there are already too + * many filters, + * errno = REPORT_ERROR_NAME_EXISTS if the filterName already exists. + **************************************************************************/ +int ReportFilterPackage(const char *filterName, uint8_t SwitchAddRemove) +{ + int index; + + if ((filterNumOfCurrentEntries == filterTableSize) && (SwitchAddRemove == REPORT_ADD)) + { + errno = REPORT_ERROR_TABLE_FULL; + return -1; + } + else if (strlen(filterName) > 10) + { + errno = REPORT_ERROR_NAME_TOO_LONG; + return -1; + } + else if ((IsNameExistsInDistributorTable(filterName)) && (SwitchAddRemove == REPORT_ADD)) + { + errno = REPORT_ERROR_NAME_EXISTS; + return -1; + } + for (index=0; index<filterNumOfCurrentEntries; index++) + if (ReportStrCmp(packageFilterTable[index].filterName,filterName)) + { + if (SwitchAddRemove == REPORT_ADD) + { + if (packageFilterTable[index].IsActive) + { + errno = REPORT_ERROR_NAME_EXISTS; + return -1; + } + else + { + packageFilterTable[index].IsActive = true; + return index; + } + } + else /* Filter disable */ + { + if (packageFilterTable[index].IsActive) + { + packageFilterTable[index].IsActive = false; + return index; + } + else + { + errno = REPORT_ERROR_NAME_ALREADY_DISABLE; + return -1; + } + } + } + if (SwitchAddRemove == REPORT_REMOVE) + { + errno = REPORT_ERROR_NAME_NOT_EXISTS; + return -1; /* nothing to remove */ + } + strcpy(packageFilterTable[filterNumOfCurrentEntries].filterName,filterName); + packageFilterTable[filterNumOfCurrentEntries].filterDontUse = true; + filterNumOfCurrentEntries++; + return (filterNumOfCurrentEntries-1); +} + + +/*************************************************************************** + * + * Name : ReportAddFilterPackage + * + * Function : Add a package filter to the package filter's data base + * + * Notes : + * + * Parameters : filterName - The filter's name must be up to 10 letters + * long + * + * Return value: the new filter handle; or -1 in case of an ERROR, thus: + * errno = REPORT_ERROR_NAME_TOO_LONG in case of long name, + * errno = REPORT_ERROR_TABLE_FULL if there are already too + * many filters, + * errno = REPORT_ERROR_NAME_EXISTS if the filterName already exists. + **************************************************************************/ +PackageHandle ReportAddFilterPackage(const char *filterName) +{ + return ReportFilterPackage(filterName, REPORT_ADD); +} + + +/*************************************************************************** + * + * Name : ReportRemoveFilterPackage + * + * Function : Remove a package filter from the package filter's data base + * + * Notes : + * + * Parameters : filterName - The filter's name must be up to 10 letters + * long + * + * Return value: OK; or ERROR and thus errno is set to one of the following: + * errno = REPORT_ERROR_NAME_TOO_LONG in case of long name, + * errno = REPORT_ERROR_NAME_ALREADY_DISABLE if the filter was + * already removed, + * errno = REPORT_ERROR_NAME_NOT_EXISTS if the filterName not exists. + **************************************************************************/ +STATUS ReportRemoveFilterPackage(const char *filterName) +{ + return ReportFilterPackage(filterName, REPORT_REMOVE); +} + + +/*************************************************************************** + * + * Name : ReportSwitchPackageFilter + * + * Function : Switch the filter of the given handle + * + * Notes : REPORT_ON - filter is active. messages do not discarded. + * REPORT_OFF - filter is not active. Its messages are discarded. + * + * Return value: OK; or ERROR if wrong handle + **************************************************************************/ +STATUS ReportSwitchPackageFilter(PackageHandle ReportPackageHandle, uint32_t SwitchOnOff) +{ + if (ReportPackageHandle >= filterNumOfCurrentEntries) + return ERROR; + packageFilterTable[ReportPackageHandle].filterDontUse = (SwitchOnOff == REPORT_OFF); + return OK; +} + + +/*************************************************************************** + * + * Name : GetFilterParamsByHandle + * + * Function : Get the filter details according to its handle + * + * Notes : filterNameBuf must exceeds 10 bytes long + * + * Return value: OK; or ERROR if wrong handle + **************************************************************************/ +STATUS GetFilterParamsByHandle(uint32_t filterHandle, + packageFilter *pPackage) +{ + if (filterHandle >= filterNumOfCurrentEntries) + return ERROR; + strcpy(pPackage->filterName,packageFilterTable[filterHandle].filterName); + pPackage->filterDontUse = packageFilterTable[filterHandle].filterDontUse; + pPackage->IsActive = packageFilterTable[filterHandle].IsActive; + return OK; +} + + +/*************************************************************************** + * + * Name : GetFilterHandleByName + * + * Function : Get the filter handle given the filter's name + * + * Notes : + * + * Return value: the handle; or -1 if no such name + **************************************************************************/ +int ReportGetFilterHandleByName(const char *filterName) +{ + int index; + + for (index = 0; index < filterNumOfCurrentEntries; index++) + if (ReportStrCmp(filterName,packageFilterTable[index].filterName) == true) + { + if (packageFilterTable[index].IsActive) + return index; + else + return -1; /* disable used */ + } + return -1; +} + + +/*************************************************************************** + * + * Name : IsNameExistsInFiltersTable + * + * Function : Check if a given name is already found in the filter's + * table. + * + * Notes : + * + * Return value: true if found; false otherwise + **************************************************************************/ +bool IsNameExistsInFiltersTable(const char *name) +{ + int index; + + for (index = 0; index < filterNumOfCurrentEntries; index++) + if (ReportStrCmp(name,packageFilterTable[index].filterName) == true) + return true; + return false; +} + + +/*************************************************************************** + * + * Name : ReportFilterTest + * + * Function : Test the filter's handle to check if to report or not + * + * Notes : + * + * Return value: true - discard the report; false - report. + **************************************************************************/ +bool ReportFilterTest(uint8_t filterHandle) +{ + if (filterHandle >= filterNumOfCurrentEntries) + return false; + return (packageFilterTable[filterHandle].filterDontUse); +} + + +bool filterTest(ErrorSeverity severity) +{ + if (filterDontUse) + return true; /* The filter machnism is disabled - */ + /* all errors are enabled */ + if( SeverityLevel <= severity ) /* check for severity */ + return true; + + return false; +} + + +/*************************************************************************** + * + * Name : ReportSeveritySet + * + * Function : Determine the filter level of the message's severity + * + * Notes : Messages with severity below this level wont be sent to + * their output + * + * Return value: void + **************************************************************************/ +void ReportSeveritySet(ErrorSeverity level) +{ + SeverityLevel = level; +} + + +/*************************************************************************** + * + * Name : Report + * + * Function : PEPORT main routine + * + * Notes : + * + * Parameters: message - user's message + * errorCode - should be the return code of the routine that + * failed and made this report + * severity - the error level + * parameter1 - user params no.1 (for additional information) + * parameter2 - another user params. + * + * Return value: OK or ERROR if failed to send to distributor + **************************************************************************/ +STATUS Report(const char *message, + char *FileName, + int LineNumber, + int errorCode, + ErrorSeverity severity, + int parameter1, + int parameter2) +{ + + /* if message passes the filter send it to distributor */ + if (filterTest(severity) || (GET_PRIVATE_SEVERITY(severity) > 0)) + return reportDistribute(REPORT_FORMAT, + message, + FileName, + LineNumber, + errorCode, + severity, + parameter1, + parameter2); + return OK; +} + + +/*************************************************************************** + * + * Name : ReportMessage2SysDist + * + * Function : Report a message to the System Distributor + * + * Notes : The severity of this report is always <Message> + * + * Return value: OK or ERROR if failed to send to distributor + **************************************************************************/ +/*STATUS ReportMessage2SysDist(const char *message) +{ + if (filterTest(RpMessage) == false) + return OK; + return reportDistribute(MESSAGE_FORMAT, message,NULL,0, 0, RpMessage, 0, 0); +} + +STATUS ReportMessage(const char *message) +{ + if (filterTest(RpMessage) == false) + return OK; + return reportDistribute(MESSAGE_FORMAT, message, NULL, 0,0, RpMessage, 0, 0); +} + +*/ +/*************************************************************************** + * + * Name : ReportPackageMessage2SysDist + * + * Function : Report a message to the System distributor if the handle + * is not filtered + * + * Notes : The severity of this report is always <Message> + * + * Return value: OK or ERROR if failed to send to distributor + **************************************************************************/ +/*STATUS ReportPackageMessage2SysDist(PackageHandle ReportPackageHandle, const char *message) +{ + if (filterTest(RpMessage) == false) + return OK; + if (ReportFilterTest(ReportPackageHandle)) + return OK; + return ReportMessage2SysDist(message); +} +*/ + +/*************************************************************************** + * + * Name : ReportFormatMessage2SysDist + * + * Function : Report a formatted message (like printf) to the System + * distributor + * + * Notes : The severity of this report is always <Message> + * IMPORTANT: the formatting is done in the context of the + * calling application!! + * + * Return value: OK or ERROR if failed to send to distributor + **************************************************************************/ +/*STATUS ReportFormatMessage2SysDist(const char *format, ...) +{ + static char text[MAX_STRING_LEN]; + va_list ap; + + if (filterTest(RpMessage) == false) + return OK; + + va_start (ap , format ); + vsprintf ( text , format , ap ); + va_end ( ap ); + return reportDistribute(MESSAGE_FORMAT, text, NULL,0,0, RpMessage, 0, 0); +} + +STATUS Reportf(const char *format, ...) +{ + static char text[MAX_STRING_LEN]; + va_list ap; + + if (filterTest(RpMessage) == false) + return OK; + + va_start (ap , format ); + vsprintf ( text , format , ap ); + va_end ( ap ); + return reportDistribute(MESSAGE_FORMAT, text, NULL,0,0, RpMessage, 0, 0); +} + +*/ +/*************************************************************************** + * + * Name : ReportWithFilter + * + * Function : PEPORT with filter - main routine + * + * Notes : It is recommended to use one of the macros below instead + * of using this routine directly. This is because the macros + * support other benefits such: file name, line number etc. + * + * Parameters: handle - filter's handle + * message - user's message + * errorCode - should be the return code of the routine that + * failed and made this report + * severity - the error level + * parameter1 - user params no.1 (for additional information) + * parameter2 - another user param. + * + * Return value: OK or ERROR if failed to send to distributor + **************************************************************************/ +STATUS ReportWithPackageFilter(PackageHandle ReportPackageHandle, + const char *message, + char *FileName, + int LineNumber, + int errorCode, + ErrorSeverity severity, + int parameter1, + int parameter2) +{ + if (ReportFilterTest(ReportPackageHandle)) + return OK; /* discard message */ + return Report(message,FileName,LineNumber,errorCode,severity,parameter1,parameter2); +} + + +/*************************************************************************** + * + * Name : ReportFormatPackageMessage2SysDist + * + * Function : Report a formatted message (like printf) to the output + * if handle is not filtered + * + * Notes : The severity of this report is always <Message> + * IMPORTANT: the formatting is done in the context of the + * calling task!! + * + * Return value: OK or ERROR if failed to send to distributor + **************************************************************************/ +/*STATUS ReportFormatPackageMessage2SysDist(PackageHandle ReportPackageHandle, + const char *format, ...) +{ + static char text[MAX_STRING_LEN]; + va_list ap; + + if (ReportFilterTest(ReportPackageHandle)) + return OK; + if (filterTest(RpMessage) == false) + return OK; + va_start (ap , format ); + vsprintf ( text , format , ap ); + va_end ( ap ); + return reportDistribute(MESSAGE_FORMAT, text, NULL,0,0, RpMessage, 0, 0); +}*/ + diff --git a/Software/Embedded_SW/Embedded/Common/report/filter.h b/Software/Embedded_SW/Embedded/Common/report/filter.h new file mode 100644 index 000000000..481f6cb66 --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/report/filter.h @@ -0,0 +1,74 @@ + +#ifndef __RFILTER_H__ +#define __RFILTER_H__ + +/* the type definition of the filter per package */ +#ifdef __cplusplus +extern "C"{ +#endif + +typedef struct packageFilter { + char filterName[11]; /* up to 10 letter of filter's name */ + bool filterDontUse; /* TRUE - dont use. FALSE - send to report */ + bool IsActive; /* TRUE - can be used. FALSE - disable it */ +} packageFilter; + +/*************************************************************************** + * + * Name : filterTableInit + * + * Function : Init the filtering mechanism + * + * Notes : + * + * Return value: OK; ERROR if malloc is failed + **************************************************************************/ +extern STATUS filterTableInit(uint32_t TableSize); + + +/*************************************************************************** + * + * Name : GetFilterParamsByHandle + * + * Function : Get the filter details according to its handle + * + * Notes : filterNameBuf must exceeds 10 bytes long + * + * Return value: OK; or ERROR if wrong handle + **************************************************************************/ +extern STATUS GetFilterParamsByHandle(uint32_t filterHandle, + packageFilter *pPackage); + + +/*************************************************************************** + * + * Name : IsNameExistsInFiltersTable + * + * Function : Check if a given name is already found in the filter's + * table. + * + * Notes : + * + * Return value: TRUE if found; FALSE otherwise + **************************************************************************/ +extern bool IsNameExistsInFiltersTable(const char *name); + + +/*************************************************************************** + * + * Name : GetFilterHandleByName + * + * Function : Get the filter handle given the filter's name + * + * Notes : + * + * Return value: the handle; or -1 if no such name (or filter was removed). + **************************************************************************/ +extern int ReportGetFilterHandleByName(const char *filterName); + +#ifdef __cplusplus +} +#endif + +#endif /* __RFILTER_H__ */ + diff --git a/Software/Embedded_SW/Embedded/Common/report/report.h b/Software/Embedded_SW/Embedded/Common/report/report.h new file mode 100644 index 000000000..d98844d71 --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/report/report.h @@ -0,0 +1,593 @@ +/****************************************************************************** + * File name : REPORT.H + * Title : INFRA REPORT PACKAGE - Application Interface + * Date created : 16 SEP, 1997 + * Revision : 2.0 + * Author : Zvika Zilberman + * + * Description : This package provides services for reporting and + * debug tracing. The package includes: + * - Error coding convention definitions + * - Message report interface + * - Message filtering interface + * - Message distributor interface + * - Compatibility with UT_EXCEPTION package + * + ****************************************************************************** + * + * History: + * 01.05.96 Roie Geron - first cut + * 01.09.96 Ilia Maller - start of coding + * 21.02.97 Ilia Maller - minor improvements + * 16.09.97 Zvika Zilberman - porting to DCME SWINFRA (0200 - 0240) + * 29.07.98 Zvika Zilberman - approach to new generation (0300 - 0320) + * 10.11.98 Zvika Zilberman - update the new generation (0330) + * + ****************************************************************************** + * Dependencies of SWINFRA packages: + * Terminal + * Monitor + ******************************************************************************/ + +#ifndef __REPORT_H__ +#define __REPORT_H__ + + +/*---------------------------- Includes ---------------------------------------*/ + +#include "include.h" +#include <assert.h> /* _ASSET_STR */ +#include "PMR/common/MessageContainer.pb-c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*#define OK 0 +#define ERROR -1 +//#define FALSE false +//#define TRUE true +#define OFF 0 +#define ON 1 +*/ +#define RET_NOTOK -1 +#define RET_OK 0 +typedef int STATUS; +/*--------------------------- Type definitions -------------------------------*/ + +/* This following redefinition is the filter level. Reports with lower severity than */ +/* the filter's one, won't be sent to the output. */ +typedef int ErrorSeverity; + +#define RpMessage 0x1 +#define RpWarning 0x2 +#define RpError 0x4 +#define RpFatalError 0x8 +#define RpPrivate 0x10 +typedef int DistributorHandle; +typedef int PackageHandle; + +#define REPORT_MAX_MSG_LEN 128 + +/* Use the following macro in order to pass the private severity as the */ +/* severity parameter to one of the Report routines */ +#define SET_PRIVATE_DISTRIBUTOR(handle) (ErrorSeverity)(Private | ((handle)<<5)) + +/* The following are some constant for control and manipulation throughout the */ +/* Report's control routines */ +#define REPORT_OFF 0 +#define REPORT_ON 1 +#define REPORT_REMOVE 0 +#define REPORT_ADD 1 + +/* This is a prototype of the output hook. When adding a function to the distributor, */ +/* the routine's prototype should be the same as here */ +typedef int (* ReportFunction)(char *message, /* The formatted message */ + char *FileName, + int LineNumber, + int errorCode, /* error code that caused the report */ + int parameter1, /* user parameter no. 1 */ + int parameter2); /* user parameter no. 2 */ + +/* Initialization struct. Default values are below */ +typedef struct{ + int DistributorTaskPriority; /* The report task's priority */ + int DistributorQueueMaxMsgs; /* Maximum number of messages in the queue */ + int MaxNumberOfPrivateDistributors; /* Maximum number of private distributor */ + int MaxNumOfFilterNames; /* Maximum number of filters to enable the applica */ +}ReportInitParams; +/* these values can be used as default in the above package configuration */ +#define REPORT_TASK_PRIORITY 150 +#define REPORT_MAX_FILTER_PACKAGES 20 +#define REPORT_QUEUE_MAX_MSGS 100 + + +/*----------------------------------------------------------------------------*/ +/*---------------------- Report Tracing and Exceptions -----------------------*/ +/*---------------------------- without filtering -----------------------------*/ +/*----------------------------------------------------------------------------*/ +//void SendStatusResponse (uint32_t Code, char *Token); +/*************************************************************************** + * + * Name : ReportInit + * + * Function : PEPORT library init + * + * Notes : Should be called before any other function from the Report + * package. + * + * Return value: OK or ERROR if malloc has failed or task creation has + * failed + **************************************************************************/ +extern STATUS ReportInit(ReportInitParams InitParams); +extern uint32_t ReportInitMessage(MessageContainer* requestContainer); + +/*************************************************************************** + * + * Name : Report + * + * Function : PEPORT main routine + * + * Notes : It is recommended to use one of the macros below (Debug + * Tracing ) instead of using this routine directly. This + * is because the macros support other benefits such: file + * name, line number etc. + * + * Parameters: message - user's message + * errorCode - should be the return code of the routine that + * failed and made this report + * severity - the error level + * parameter1 - user params no.1 (for additional information) + * parameter2 - another user param. + * + * Return value: OK or ERROR if failed to send to distributor + **************************************************************************/ +extern STATUS Report(const char *message, + char *FileName, + int LineNumber, + int errorCode, + ErrorSeverity severity, + int parameter1, + int parameter2); + + +/*************************************************************************** + * + * Name : ReportMessage2SysDist + * + * Function : Report a message to the System distributor + * + * Notes : The severity of this report is always <Message> + * + * Return value: OK or ERROR if failed to send to distributor + **************************************************************************/ +extern STATUS ReportMessage2SysDist(const char *message); + + +/*************************************************************************** + * + * Name : ReportFormatMessage2SysDist + * + * Function : Report a formatted message (like printf) to the System + * distributor + * + * Notes : The severity of this report is always <Message> + * IMPORTANT: the formatting is done in the context of the + * calling task!! + * + * Return value: OK or ERROR if failed to send to distributor + **************************************************************************/ +extern STATUS ReportFormatMessage2SysDist(const char *format, ...); + + +/*************************************************************************** + * + * 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 + **************************************************************************/ +extern STATUS ReportMessage2Dist(DistributorHandle distributor, const char *message); + + +/*************************************************************************** + * + * Name : REPORT_ERR + * + * Function : Report an error + * + * Notes : Attention: this is a macro. Will add the file name & the + * line number where the error is reported + * + * Parameters : See above, Report. + * + * Return value: OK; or Report's return code + **************************************************************************/ +#define REPORT_ERR(msg, error, severity, par1, par2) \ + Report(REPORT_LINE(msg), error, severity, par1, par2) + + +/*************************************************************************** + * + * Name : REPORT_IF_ERROR + * + * Function : if <condition> is TRUE then report an error + * + * Notes : Attention: this is a macro. Will add the file name & the + * line number where the error is reported + * + * Parameters : See above, Report. + * + * Return value: OK; or Report's return code + **************************************************************************/ +#define REPORT_IF_ERROR(condition, msg, error, severity, par1, par2) \ + ((condition) ? Report(REPORT_LINE(msg), error, severity, par1, par2) : OK) + +/*----------------------------------------------------------------------------*/ +/*---------------------- Report Tracing and Exceptions -----------------------*/ +/*----------------------------- with filtering -------------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*************************************************************************** + * + * Name : ReportWithPackageFilter + * + * Function : PEPORT with package filter - main routine + * + * Notes : It is recommended to use one of the macros below instead + * of using this routine directly. This is because the macros + * support other benefits such: file name, line number etc. + * + * Parameters: ReportPackageHandle - filter's handle + * message - user's message + * errorCode - should be the return code of the routine + * that failed and made this report + * severity - the error level + * parameter1 - user params no.1 (for additional + * information) + * parameter2 - another user param. + * + * Return value: OK or ERROR if failed to send to distributor + **************************************************************************/ +extern STATUS ReportWithPackageFilter(PackageHandle ReportPackageHandle, + const char *message, + char *FileName, + int LineNumber, + int errorCode, + ErrorSeverity severity, + int parameter1, + int parameter2); + + +/*************************************************************************** + * + * Name : ReportPackageMessage2SysDist + * + * Function : Report a message to the System distributor if the handle + * is not filtered + * + * Notes : The severity of this report is always <Message> + * + * Return value: OK or ERROR if failed to send to distributor + **************************************************************************/ +/*extern STATUS ReportPackageMessage2SysDist(PackageHandle ReportPackageHandle, + const char *message); +*/ + +/*************************************************************************** + * + * Name : ReportFormatPackageMessage2SysDist + * + * Function : Report a formatted message (like printf) to the output + * if handle is not filtered + * + * Notes : The severity of this report is always <Message> + * IMPORTANT: the formatting is done in the context of the + * calling task!! + * + * Return value: OK or ERROR if failed to send to distributor + **************************************************************************/ +/*extern STATUS ReportFormatPackageMessage2SysDist(PackageHandle ReportPackageHandle, + const char *format, ...); +*/ + +/*************************************************************************** + * + * Name : REPORT_ERR_FILTER + * + * Function : Report an error if handle is not filtered + * + * Notes : Attention: this is a macro. Will add the file name & the + * line number where the error is reported + * + * Parameters : See above, Report. + * + * Return value: OK; or Report's return code + **************************************************************************/ +#define REPORT_ERR_FILTER(handle, msg, FileName, LineNumber,error, severity, par1, par2) \ + ReportWithPackageFilter(handle, REPORT_LINE(msg), FileName, LineNumber,error, severity, par1, par2) + + +/*************************************************************************** + * + * Name : REPORT_IF_ERROR_FILTER + * + * Function : if <condition> is TRUE and handle is not filtered + * then report an error + * + * Notes : Attention: this is a macro. Will add the file name & the + * line number where the error is reported + * + * Parameters : See above, Report. + * + * Return value: OK; or Report's return code + **************************************************************************/ +#define REPORT_IF_ERROR_FILTER(condition, handle, msg, FileName, LineNumber,error, severity, par1, par2) \ + ((condition) ? REPORT_ERR_FILTER(handle,msg,FileName, LineNumber,error,severity,par1,par2) : OK) + + +/*************************************************************************** + * + * Name : ReportAddFilterPackage + * + * Function : Add a package filter to the package filter's data base + * + * Notes : + * + * Parameters : filterName - The filter's name must be up to 10 letters + * long + * + * Return value: The new filter handle; or -1 in case of an ERROR, thus: + * errno = REPORT_ERROR_NAME_TOO_LONG in case of long name, + * errno = REPORT_ERROR_TABLE_FULL if there are already too + * many filters, + * errno = REPORT_ERROR_NAME_EXISTS if the filterName already exists. + **************************************************************************/ +extern PackageHandle ReportAddFilterPackage(const char *filterName); + + +/*************************************************************************** + * + * Name : ReportRemoveFilterPackage + * + * Function : Remove a package filter from the package filter's data base + * + * Notes : + * + * Parameters : filterName - The filter's name must be up to 10 letters + * long + * + * Return value: OK; or ERROR and thus errno is set to one of the following: + * errno = REPORT_ERROR_NAME_TOO_LONG in case of long name, + * errno = REPORT_ERROR_NAME_ALREADY_DISABLE if the filter was + * already removed, + * errno = REPORT_ERROR_NAME_NOT_EXISTS if the filterName not exists. + **************************************************************************/ +extern STATUS ReportRemoveFilterPackage(const char *filterName); + + +/*************************************************************************** + * + * Name : ReportSwitchPackageFilter + * + * Function : Switch the filter of the given handle + * + * Notes : REPORT_ON - filter is active. messages do not discarded. + * REPORT_OFF - filter is not active. Its messages are discarded. + * + * Return value: OK; or ERROR if wrong handle + **************************************************************************/ +extern STATUS ReportSwitchPackageFilter(PackageHandle ReportPackageHandle, uint32_t SwitchOnOff); + +/*----------------------------------------------------------------------------*/ +/*---------------------------- Distributor -----------------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*************************************************************************** + * + * Name : ReportAddDistributor + * + * Function : Add private distributor + * + * Notes : + * + * Parameters: distributorName - The name must be up to 10 letters long + * + * Return value: The new distributor handle, or -1 and thus: + * errno = REPORT_ERROR_NAME_TOO_LONG in case of long name, + * errno = REPORT_ERROR_TABLE_FULL if there are already too + * many distributors, + * errno = REPORT_ERROR_NAME_EXISTS if the distributorName + * already exists. + **************************************************************************/ +extern DistributorHandle ReportAddDistributor(const char *distributorName); + + +/*************************************************************************** + * + * Name : ReportRemoveDistributor + * + * Function : Remove private distributor + * + * Notes : The distributor's messages will be discarded. + * Its name will be no longer seen in the distributor's list + * when the REP_CONTROL is typed in the Monitor. + * + * Parameters: distributorName - The severity's name must be up to 10 + * letters long. + * + * Return value: OK; or ERROR and thus errno is set to one of the following: + * 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. + **************************************************************************/ +extern DistributorHandle ReportRemoveDistributor(const char *distributorName); + + +/*************************************************************************** + * + * Name : ReportDistributorControl + * + * Function : Disable / enable the flow of reports given its private + * severity + * + * Notes : Disable reports using the constant REPORT_OFF + * Enable the reports using the constant REPORT_ON + * + * Return value: OK or ERROR if illegal Distributor + **************************************************************************/ +extern STATUS ReportDistributorControl(DistributorHandle Distributor, uint32_t SwitchOnOff); + +/*----------------------------------------------------------------------------*/ +/*------------------------ Message Distributor -------------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*************************************************************************** + * + * 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 private + * severity, or the private 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 + **************************************************************************/ +extern STATUS ReportFd(int fd, uint32_t SwitchAddRemove, DistributorHandle Distributor); + + +/*************************************************************************** + * + * 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 private + * severity, or give the private 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) + **************************************************************************/ +extern STATUS ReportFunc(ReportFunction func, + uint32_t SwitchAddRemove, + DistributorHandle Distributor); + + +/*************************************************************************** + * + * 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 <ENTER>). + * 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 each + * of the private distributors + * + * Parameters: SwitchAddRemove - REPORT_ADD to add the routine + * REPORT_REMOVE to remove it. + * Distributor - Set 0 if not concerned with any private + * severity, or give the private severity's + * handle to set with it . + * + * Return value: void + **************************************************************************/ +extern void ReportMonitorFunc(uint32_t SwitchAddRemove, uint32_t Distributor); + +/*----------------------------------------------------------------------------*/ +/*------------------------------ Severity ------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*************************************************************************** + * + * Name : ReportSeveritySet + * + * Function : Determine the filter level of the message's severity + * + * Notes : Messages with severity below this level wont be sent to + * their output + * It does not affect the private severities + * + * Return value: void + **************************************************************************/ +extern void ReportSeveritySet(ErrorSeverity level); + +/*----------------------------------------------------------------------------*/ + +#define S1(x) #x +#define S2(x) S1(x) +//#define LOCATION __FILE__ " : " S2(__LINE__) +#define REPORT_LINE(message) __FILE__ "." S2(__LINE__) ":t"S2(UsersysTickGet())" : " S2(message) +//#define REPORT_LINE(message) __FILE__ "." _ASSERT_STR(__LINE__) ": " message + +/*----------------------------------------------------------------------------*/ +/*---------------------- Backward Support to UT_Except -----------------------*/ +/*----------------------------------------------------------------------------*/ + +#define ON_ERROR_REPORT_ERROR(msg) if ( rc != 0 ) \ + Report("\n\r*** ERROR :" REPORT_LINE(msg),__FILE__,__LINE__,rc,RpFatalError,0,0) + +#define REPORT_ERROR(rc,msg) \ + Report("\n\r*** ERROR :" REPORT_LINE(msg),__FILE__,__LINE__,rc,RpFatalError,0,0) + +#define ON_ERROR_LOG_ERROR(msg) if ( rc != 0 ) \ + Report("\n\r*** ERROR :" REPORT_LINE(msg),__FILE__,__LINE__,rc,RpError,0,0) + +#define LOG_ERROR(rc,msg) \ + Report("\n\r*** ERROR :" REPORT_LINE(msg),__FILE__,__LINE__,rc,RpError,0,0) + +/*----------------------------------------------------------------------------*/ +/*----------------------- Backward Compatible --------------------------------*/ +/*----------------------------------------------------------------------------*/ +extern STATUS ReportMessage(const char *message); +extern STATUS Reportf(const char *format, ...); +#define ReportFilterMessage ReportPackageMessage2SysDist + +/*----------------------------------------------------------------------------*/ +/*---------------------------- Error Codes -----------------------------------*/ +/*----------------------------------------------------------------------------*/ + +/* Error, returned by errno in Report's routines */ +#define REPORT_ERROR_ILLEGAL_PARAMETER 1 +#define REPORT_ERROR_CODE_NOT_FOUND 2 +#define REPORT_ERROR_FILTER_NOT_ALIVE 3 +#define REPORT_ERROR_NAME 10 +#define REPORT_ERROR_NAME_EXISTS 11 +#define REPORT_ERROR_NAME_NOT_EXISTS 12 +#define REPORT_ERROR_NAME_TOO_LONG 13 +#define REPORT_ERROR_NAME_ALREADY_DISABLE 14 +#define REPORT_ERROR_NOT_ENOUGH_MEMORY 20 +#define REPORT_ERROR_TABLE_FULL 21 + +#ifdef __cplusplus +} +#endif + +#endif /* __REPORT_H__ */ + diff --git a/Software/Embedded_SW/Embedded/Common/report/reportInit.c b/Software/Embedded_SW/Embedded/Common/report/reportInit.c new file mode 100644 index 000000000..c7ea0c194 --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/report/reportInit.c @@ -0,0 +1,161 @@ +/****************************************************************************** + * File name : reportInit.c + * Title : REPORT PACKAGE - Application Interface + * Date created : 01 SEP, 1996 + * Revision : 1.0 + * Author : Ilia Maller, Zvika Zilberman + * + * Description : + * + ****************************************************************************** + * + * Procedures: + * + * ReportInit - Initialise report package + * + ****************************************************************************** + * + * 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 <stdio.h> /* puts(), etc. */ +#include "report.h" +#include "distributor.h" /* distibutorInit */ +#include "filter.h" +#include "include.h" + +#include <Modules/Stubs_Handler/DataDef.h> +#include "PMR/common/MessageContainer.pb-c.h" +#include "PMR/debugging/DebugLogRequest.pb-c.h" +#include "PMR/debugging/DebugLogResponse.pb-c.h" +#include "drivers/twine_usblib/usb_serial_adapter.h" +//#include "graphics_adapter.h" +#include "Modules/Stubs_Handler/Container.h" + +#include "Modules/thread/thread.h" + +MotorConfigStruc MotorsCfg[MAX_THREAD_MOTORS_NUM]; +InternalWinderConfigStruc InternalWinderCfg; +char protobufToken[36]; +/*void SendStatusResponse (uint32_t Code, char *Token) +{ + MessageContainer responseContainer; + StatusResponse response = STATUS_RESPONSE__INIT; + + + response.has_status = true; + response.status = (ErrorCode)Code; + + responseContainer = createContainer(MESSAGE_TYPE__StatusResponse, Token, true, &response, &status_response__pack, &status_response__get_packed_size); + uint8_t* container_buffer = malloc(message_container__get_packed_size(&responseContainer)); + size_t container_size = message_container__pack(&responseContainer, container_buffer); + SendChars((char*)container_buffer, container_size); + free(container_buffer); + + +}*/ + +int ReportResponseFunc(char *message, /* The formatted message */ + char *FileName, + int LineNumber, + int errorCode, /* error code that caused the report */ + int parameter1, /* user parameter no. 1 */ + int parameter2) /* user parameter no. 2 */ +{ + MessageContainer responseContainer; + + DebugLogResponse response = DEBUG_LOG_RESPONSE__INIT; + response.filename = FileName; + response.has_linenumber = true; + response.linenumber = LineNumber; + /*response.has_errorcode = true; + response.errorcode = (ErrorCode)errorCode; + response.has_severity = true; + response.severity = (Severity)parameter1;*/ + response.has_filter = true; + response.has_category = true; + response.category = (DebugLogCategory)parameter1; + response.filter = parameter2; + strcpy (response.message,message); + responseContainer = createContainer(MESSAGE_TYPE__DebugLogResponse, protobufToken, false, &response, &debug_log_response__pack, &debug_log_response__get_packed_size); + uint8_t* container_buffer = malloc(message_container__get_packed_size(&responseContainer)); + size_t container_size = message_container__pack(&responseContainer, container_buffer); + SendChars((char*)container_buffer, container_size); + + return OK; + +} + + +uint32_t ReportInitMessage(MessageContainer* requestContainer) +{ + uint32_t status = NOT_SUPPORTED; + //MessageContainer responseContainer; + + ReportInitParams InitParams; + + DebugLogRequest* request = debug_log_request__unpack(NULL, requestContainer->data.len, requestContainer->data.data); + strcpy (protobufToken, requestContainer->token); + InitParams.DistributorQueueMaxMsgs = 20; + InitParams.DistributorTaskPriority = 6; + InitParams.MaxNumOfFilterNames = 1; + InitParams.MaxNumberOfPrivateDistributors = 2; + status |= ReportInit (InitParams); + DistributorHandle ReportHandle = ReportAddDistributor("ProtoBuf"); + if (ReportHandle == NULL) status |= 0x8; + status |= ReportFunc(ReportResponseFunc , REPORT_ADD, ReportHandle); + + return status; +} + +#define REPORT_RESERVED_NUM_OF_FILTER_PACKAGES 30 /* This reserved for swinfra packages */ + +/*************************************************************************** + * + * Name : ReportInit + * + * Function : PEPORT library init + * + * Notes : Should be called before any other function from the Report + * package. + * + * Return value: OK or ERROR if malloc has failed or task creation has + * failed + **************************************************************************/ +STATUS ReportInit(ReportInitParams InitParams) +{ + static int initialized = false; + STATUS status; + int MaxNumOfFilterNames; + + if (initialized) + return OK; + + /* Set the filter to receive all kind */ + ReportSeveritySet(RpMessage); + + /* Configure distributor */ + if( distibutorInit(InitParams.DistributorTaskPriority, + InitParams.DistributorQueueMaxMsgs, + InitParams.MaxNumberOfPrivateDistributors) == -1) + return ERROR; + + /* Add the support of the monitor commands */ + //ReportMonitorInit(); + /* Add the Monitor Output routine, by default */ + //ReportMonitorFunc(REPORT_ADD, 0); + + MaxNumOfFilterNames = InitParams.MaxNumOfFilterNames; + MaxNumOfFilterNames += REPORT_RESERVED_NUM_OF_FILTER_PACKAGES; + status = filterTableInit(MaxNumOfFilterNames); + if (status == OK) + initialized = true; + + return status; +} |
