diff --git a/.gitignore b/.gitignore index c44eb3f..09a2756 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -/STM32F103_Example/MDK-ARM/Modbus_example \ No newline at end of file +/STM32F103_Example/MDK-ARM/Modbus_example +/Modbus/.vs/ diff --git a/Modbus/__crc_algs.c b/Modbus/__crc_algs.c new file mode 100644 index 0000000..a8d0058 --- /dev/null +++ b/Modbus/__crc_algs.c @@ -0,0 +1,116 @@ +#include "__crc_algs.h" + + +uint32_t CRC_calc; +uint32_t CRC_ref; + +//uint16_t CRC_calc; +//uint16_t CRC_ref; + + +// left this global for debug +uint8_t uchCRCHi = 0xFF; +uint8_t uchCRCLo = 0xFF; +unsigned uIndex; + + +uint32_t crc32(uint8_t *data, uint32_t data_size) +{ + static const unsigned int crc32_table[] = +{ + 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 +}; +unsigned int crc = 0xFFFFFFFF; + while (data_size--) + { + crc = (crc >> 8) ^ crc32_table[(crc ^ *data) & 255]; + data++; + } + return crc^0xFFFFFFFF; +} + + +uint16_t crc16(uint8_t *data, uint32_t data_size) +{ + /*Table of CRC values for high order byte*/ + static unsigned char auchCRCHi[]= + { + 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, + 0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41, + 0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41, + 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, + 0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41, + 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, + 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, + 0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41, + 0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41, + 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, + 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, + 0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41, + 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, + 0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41, + 0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41, + 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, + }; + /*Table of CRC values for low order byte*/ + static char auchCRCLo[] = + { + 0x00,0xC0,0xC1,0x01,0xC3,0x03,0x02,0xC2,0xC6,0x06,0x07,0xC7,0x05,0xC5,0xC4,0x04, + 0xCC,0x0C,0x0D,0xCD,0x0F,0xCF,0xCE,0x0E,0x0A,0xCA,0xCB,0x0B,0xC9,0x09,0x08,0xC8, + 0xD8,0x18,0x19,0xD9,0x1B,0xDB,0xDA,0x1A,0x1E,0xDE,0xDF,0x1F,0xDD,0x1D,0x1C,0xDC, + 0x14,0xD4,0xD5,0x15,0xD7,0x17,0x16,0xD6,0xD2,0x12,0x13,0xD3,0x11,0xD1,0xD0,0x10, + 0xF0,0x30,0x31,0xF1,0x33,0xF3,0xF2,0x32,0x36,0xF6,0xF7,0x37,0xF5,0x35,0x34,0xF4, + 0x3C,0xFC,0xFD,0x3D,0xFF,0x3F,0x3E,0xFE,0xFA,0x3A,0x3B,0xFB,0x39,0xF9,0xF8,0x38, + 0x28,0xE8,0xE9,0x29,0xEB,0x2B,0x2A,0xEA,0xEE,0x2E,0x2F,0xEF,0x2D,0xED,0xEC,0x2C, + 0xE4,0x24,0x25,0xE5,0x27,0xE7,0xE6,0x26,0x22,0xE2,0xE3,0x23,0xE1,0x21,0x20,0xE0, + 0xA0,0x60,0x61,0xA1,0x63,0xA3,0xA2,0x62,0x66,0xA6,0xA7,0x67,0xA5,0x65,0x64,0xA4, + 0x6C,0xAC,0xAD,0x6D,0xAF,0x6F,0x6E,0xAE,0xAA,0x6A,0x6B,0xAB,0x69,0xA9,0xA8,0x68, + 0x78,0xB8,0xB9,0x79,0xBB,0x7B,0x7A,0xBA,0xBE,0x7E,0x7F,0xBF,0x7D,0xBD,0xBC,0x7C, + 0xB4,0x74,0x75,0xB5,0x77,0xB7,0xB6,0x76,0x72,0xB2,0xB3,0x73,0xB1,0x71,0x70,0xB0, + 0x50,0x90,0x91,0x51,0x93,0x53,0x52,0x92,0x96,0x56,0x57,0x97,0x55,0x95,0x94,0x54, + 0x9C,0x5C,0x5D,0x9D,0x5F,0x9F,0x9E,0x5E,0x5A,0x9A,0x9B,0x5B,0x99,0x59,0x58,0x98, + 0x88,0x48,0x49,0x89,0x4B,0x8B,0x8A,0x4A,0x4E,0x8E,0x8F,0x4F,0x8D,0x4D,0x4C,0x8C, + 0x44,0x84,0x85,0x45,0x87,0x47,0x46,0x86,0x82,0x42,0x43,0x83,0x41,0x81,0x80,0x40, + }; + uchCRCHi = 0xFF; + uchCRCLo = 0xFF; + /* CRC Generation Function */ + while( data_size--) /* pass through message buffer */ + { + uIndex = uchCRCHi ^ *data++; /* calculate the CRC */ + uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex]; + uchCRCLo = auchCRCLo[uIndex]; + } + return uchCRCHi | uchCRCLo<<8; +} diff --git a/Modbus/crc_algs.h b/Modbus/__crc_algs.h similarity index 100% rename from Modbus/crc_algs.h rename to Modbus/__crc_algs.h diff --git a/Modbus/crc_algs.c b/Modbus/crc_algs.c deleted file mode 100644 index fcfa779..0000000 --- a/Modbus/crc_algs.c +++ /dev/null @@ -1,116 +0,0 @@ -#include "crc_algs.h" - - -uint32_t CRC_calc; -uint32_t CRC_ref; - -//uint16_t CRC_calc; -//uint16_t CRC_ref; - - -// left this global for debug -uint8_t uchCRCHi = 0xFF; -uint8_t uchCRCLo = 0xFF; -unsigned uIndex; - - -uint32_t crc32(uint8_t *data, uint32_t data_size) -{ - static const unsigned int crc32_table[] = -{ - 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 -}; -unsigned int crc = 0xFFFFFFFF; - while (data_size--) - { - crc = (crc >> 8) ^ crc32_table[(crc ^ *data) & 255]; - data++; - } - return crc^0xFFFFFFFF; -} - - -uint16_t crc16(uint8_t *data, uint32_t data_size) -{ - /*Table of CRC values for high order byte*/ - static unsigned char auchCRCHi[]= - { - 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, - 0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41, - 0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41, - 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, - 0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41, - 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, - 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, - 0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41, - 0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41, - 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, - 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, - 0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41, - 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, - 0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41, - 0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41, - 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, - }; - /*Table of CRC values for low order byte*/ - static char auchCRCLo[] = - { - 0x00,0xC0,0xC1,0x01,0xC3,0x03,0x02,0xC2,0xC6,0x06,0x07,0xC7,0x05,0xC5,0xC4,0x04, - 0xCC,0x0C,0x0D,0xCD,0x0F,0xCF,0xCE,0x0E,0x0A,0xCA,0xCB,0x0B,0xC9,0x09,0x08,0xC8, - 0xD8,0x18,0x19,0xD9,0x1B,0xDB,0xDA,0x1A,0x1E,0xDE,0xDF,0x1F,0xDD,0x1D,0x1C,0xDC, - 0x14,0xD4,0xD5,0x15,0xD7,0x17,0x16,0xD6,0xD2,0x12,0x13,0xD3,0x11,0xD1,0xD0,0x10, - 0xF0,0x30,0x31,0xF1,0x33,0xF3,0xF2,0x32,0x36,0xF6,0xF7,0x37,0xF5,0x35,0x34,0xF4, - 0x3C,0xFC,0xFD,0x3D,0xFF,0x3F,0x3E,0xFE,0xFA,0x3A,0x3B,0xFB,0x39,0xF9,0xF8,0x38, - 0x28,0xE8,0xE9,0x29,0xEB,0x2B,0x2A,0xEA,0xEE,0x2E,0x2F,0xEF,0x2D,0xED,0xEC,0x2C, - 0xE4,0x24,0x25,0xE5,0x27,0xE7,0xE6,0x26,0x22,0xE2,0xE3,0x23,0xE1,0x21,0x20,0xE0, - 0xA0,0x60,0x61,0xA1,0x63,0xA3,0xA2,0x62,0x66,0xA6,0xA7,0x67,0xA5,0x65,0x64,0xA4, - 0x6C,0xAC,0xAD,0x6D,0xAF,0x6F,0x6E,0xAE,0xAA,0x6A,0x6B,0xAB,0x69,0xA9,0xA8,0x68, - 0x78,0xB8,0xB9,0x79,0xBB,0x7B,0x7A,0xBA,0xBE,0x7E,0x7F,0xBF,0x7D,0xBD,0xBC,0x7C, - 0xB4,0x74,0x75,0xB5,0x77,0xB7,0xB6,0x76,0x72,0xB2,0xB3,0x73,0xB1,0x71,0x70,0xB0, - 0x50,0x90,0x91,0x51,0x93,0x53,0x52,0x92,0x96,0x56,0x57,0x97,0x55,0x95,0x94,0x54, - 0x9C,0x5C,0x5D,0x9D,0x5F,0x9F,0x9E,0x5E,0x5A,0x9A,0x9B,0x5B,0x99,0x59,0x58,0x98, - 0x88,0x48,0x49,0x89,0x4B,0x8B,0x8A,0x4A,0x4E,0x8E,0x8F,0x4F,0x8D,0x4D,0x4C,0x8C, - 0x44,0x84,0x85,0x45,0x87,0x47,0x46,0x86,0x82,0x42,0x43,0x83,0x41,0x81,0x80,0x40, - }; - uchCRCHi = 0xFF; - uchCRCLo = 0xFF; - /* CRC Generation Function */ - while( data_size--) /* pass through message buffer */ - { - uIndex = uchCRCHi ^ *data++; /* calculate the CRC */ - uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex]; - uchCRCLo = auchCRCLo[uIndex]; - } - return uchCRCHi | uchCRCLo<<8; -} diff --git a/Modbus/modbus.c b/Modbus/modbus.c index 55970c1..1658f9e 100644 --- a/Modbus/modbus.c +++ b/Modbus/modbus.c @@ -1,8 +1,8 @@ /** ************************************************************************** -* @file modbus.c -* @brief Модуль для реализации MODBUS. -************************************************************************** +* @file modbus.c +* @brief Модуль для реализации MODBUS. +************************************************************************** * @details Файл содержит реализацию функций работы с Modbus, включая: * - доступ к coils и registers; * - обработку команд протокола; @@ -24,11 +24,12 @@ * - MB_DefineCoilsAddress() — Определить начальный адрес coils. * - MB_Check_Address_For_Arr() — Проверить, принадлежит ли адрес массиву. * - Основные команды Modbus: -* - MB_Read_Coils() -* - MB_Read_Hold_Regs() -* - MB_Write_Single_Coil() +* - MB_Proccess_Read_Coils() +* - MB_Proccess_Read_Hold_Regs() +* - MB_Proccess_Write_Single_Coil() +* - MB_Proccess_Write_Single_Reg() * - MB_Write_Miltuple_Coils() -* - MB_Write_Miltuple_Regs() +* - MB_Proccess_Write_Miltuple_Regs() * * ### Функции для работы с RS (UART): * - RS_Parse_Message() / RS_Collect_Message() — Парсинг и сборка сообщения. @@ -42,11 +43,11 @@ * @section Структура данных Modbus * * #### Holding/Input Registers: -* - Регистры — 16-битные слова. Доступ к регистрам осуществляется через указатель. +* - Регистры — 16-битные слова. Доступ к регистрам осуществляется через указатель. * Таким образом, сами регистры могут представлять собой как массив так и структуру. * * #### Coils: -* - Coils — это биты, упакованные в 16-битные слова. Доступ к коилам осуществляется через указатель. +* - Coils — это биты, упакованные в 16-битные слова. Доступ к коилам осуществляется через указатель. * Таким образом, сами коилы могут представлять собой как массив так и структуру. * * @section Инструкция по подключению @@ -72,480 +73,486 @@ extern TIM_HandleTypeDef rs_htim; RS_HandleTypeDef hmodbus1; /* DEFINE REGISTERS/COILS */ -MB_DeviceIdentificationTypeDef MB_INFO; -MB_DataStructureTypeDef MB_DATA; +MB_DeviceIdentificationTypeDef MB_DEVID; +MB_DataStructureTypeDef MB_DATA = {0};; RS_MsgTypeDef MODBUS_MSG; //------------------------------------------------------------------- //-----------------------------FOR USER------------------------------ /** - * @brief First set up of MODBUS. - * @details Первый инит модбас. Заполняет структуры и инициализирует таймер и юарт для общения по модбас. - * @note This called from main - */ + * @brief First set up of MODBUS. + * @details Первый инит модбас. Заполняет структуры и инициализирует таймер и юарт для общения по модбас. + * @note This called from main + */ void MODBUS_FirstInit(void) { - MB_DevoceInentificationInit(); - //-----------SETUP MODBUS------------- - // set up modbus: MB_RX_Size_NotConst and Timeout enable - hmodbus1.ID = MODBUS_DEVICE_ID; + MB_DeviceInentificationInit(); + //-----------SETUP MODBUS------------- + // set up modbus: MB_RX_Size_NotConst and Timeout enable + hmodbus1.ID = MODBUS_DEVICE_ID; hmodbus1.sRS_Timeout = MODBUS_TIMEOUT; - hmodbus1.sRS_Mode = SLAVE_ALWAYS_WAIT; - hmodbus1.sRS_RX_Size_Mode = RS_RX_Size_NotConst; - - // INIT - hmodbus1.RS_STATUS = RS_Init(&hmodbus1, &rs_huart, &rs_htim, 0); + hmodbus1.sRS_Mode = SLAVE_ALWAYS_WAIT; + hmodbus1.sRS_RX_Size_Mode = RS_RX_Size_NotConst; + + // INIT + hmodbus1.RS_STATUS = RS_Init(&hmodbus1, &rs_huart, &rs_htim, 0); - RS_EnableReceive(); + RS_EnableReceive(); } /** - * @brief Set or Reset Coil at its global address. - * @param Addr - адрес коила. - * @param WriteVal - Что записать в коил: 0 или 1. - * @return ExceptionCode - Код исключения если коила по адресу не существует, и NO_ERRORS если все ок. - * - * @details Позволяет обратиться к любому коилу по его глобальному адрессу. - Вне зависимости от того как коилы размещены в памяти. - */ + * @brief Set or Reset Coil at its global address. + * @param Addr - адрес коила. + * @param WriteVal - Что записать в коил: 0 или 1. + * @return ExceptionCode - Код исключения если коила по адресу не существует, и NO_ERRORS если все ок. + * + * @details Позволяет обратиться к любому коилу по его глобальному адрессу. + Вне зависимости от того как коилы размещены в памяти. + */ MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal) { - //---------CHECK FOR ERRORS---------- - MB_ExceptionTypeDef Exception = NO_ERRORS; - uint16_t *coils; - uint16_t start_shift = 0; // shift in coils register - - //------------WRITE COIL------------- - Exception = MB_DefineCoilsAddress(&coils, Addr, 1, &start_shift, 1); - if(Exception == NO_ERRORS) - { - switch(WriteVal) - { - case SET_COIL: - *coils |= (1<= R_ARR_ADDR) - { - // if quantity too big return error - if ((Addr - R_ARR_ADDR) + Qnt > R_ARR_NUMB) - { - return ILLEGAL_DATA_ADDRESS; // return exception code - } - // if all ok - return no errors - return NO_ERRORS; - } - // if address isnt from this array return error - else - return ILLEGAL_DATA_ADDRESS; // return exception code + // if address from this array + if(Addr >= R_ARR_ADDR) + { + // if quantity too big return error + if ((Addr - R_ARR_ADDR) + Qnt > R_ARR_NUMB) + { + return ILLEGAL_DATA_ADDRESS; // return exception code + } + // if all ok - return no errors + return NO_ERRORS; + } + // if address isnt from this array return error + else + return ILLEGAL_DATA_ADDRESS; // return exception code } /** - * @brief Define Address Origin for Input/Holding Registers - * @param pRegs - указатель на указатель регистров. - * @param Addr - адрес начального регистра. - * @param Qnt - количество запрашиваемых регистров. - * @param WriteFlag - флаг регистр нужны для чтения или записи. - * @return ExceptionCode - Код исключения если есть, и NO_ERRORS если нет. - * - * @details Определение адреса начального регистра. - * @note WriteFlag пока не используется. - */ + * @brief Define Address Origin for Input/Holding Registers + * @param pRegs - указатель на указатель регистров. + * @param Addr - адрес начального регистра. + * @param Qnt - количество запрашиваемых регистров. + * @param WriteFlag - флаг регистр нужны для чтения или записи. + * @return ExceptionCode - Код исключения если есть, и NO_ERRORS если нет. + * + * @details Определение адреса начального регистра. + * @note WriteFlag пока не используется. + */ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType) -{ - /* check quantity error */ - if (Qnt > 125) - { - return ILLEGAL_DATA_VALUE; // return exception code - } - - if(RegisterType == RegisterType_Holding) - { - // Default holding registers - if(MB_Check_Address_For_Arr(Addr, Qnt, R_HOLDING_ADDR, R_HOLDING_QNT) == NO_ERRORS) - { - *pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr); // указатель на выбранный по Addr регистр - } - // if address doesnt match any array - return illegal data address response - else - { - return ILLEGAL_DATA_ADDRESS; - } - } - else if(RegisterType == RegisterType_Input) - { - // Default input registers - if(MB_Check_Address_For_Arr(Addr, Qnt, R_INPUT_ADDR, R_INPUT_QNT) == NO_ERRORS) - { - *pRegs = MB_Set_Register_Ptr(&MB_DATA.InRegs, Addr); // указатель на выбранный по Addr регистр - } - // if address doesnt match any array - return illegal data address response - else - { - return ILLEGAL_DATA_ADDRESS; - } - } - else - { - return ILLEGAL_FUNCTION; - } - // if found requeried array return no err - return NO_ERRORS; // return no errors +{ + /* check quantity error */ + if (Qnt > 125) + { + return ILLEGAL_DATA_VALUE; // return exception code + } + + if(RegisterType == RegisterType_Holding) + { + // Default holding registers + if(MB_Check_Address_For_Arr(Addr, Qnt, R_HOLDING_ADDR, R_HOLDING_QNT) == NO_ERRORS) + { + *pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr); // указатель на выбранный по Addr регистр + } + // if address doesnt match any array - return illegal data address response + else + { + return ILLEGAL_DATA_ADDRESS; + } + } + else if(RegisterType == RegisterType_Input) + { + // Default input registers + if(MB_Check_Address_For_Arr(Addr, Qnt, R_INPUT_ADDR, R_INPUT_QNT) == NO_ERRORS) + { + *pRegs = MB_Set_Register_Ptr(&MB_DATA.InRegs, Addr); // указатель на выбранный по Addr регистр + } + // if address doesnt match any array - return illegal data address response + else + { + return ILLEGAL_DATA_ADDRESS; + } + } + else + { + return ILLEGAL_FUNCTION; + } + // if found requeried array return no err + return NO_ERRORS; // return no errors } /** - * @brief Define Address Origin for coils - * @param pCoils - указатель на указатель коилов. - * @param Addr - адресс начального коила. - * @param Qnt - количество запрашиваемых коилов. - * @param start_shift - указатель на переменную содержащую сдвиг внутри регистра для начального коила. - * @param WriteFlag - флаг коилы нужны для чтения или записи. - * @return ExceptionCode - Код исключения если есть, и NO_ERRORS если нет. - * - * @details Определение адреса начального регистра запрашиваемых коилов. - * @note WriteFlag используется для определния регистров GPIO: ODR или IDR. - */ + * @brief Define Address Origin for coils + * @param pCoils - указатель на указатель коилов. + * @param Addr - адресс начального коила. + * @param Qnt - количество запрашиваемых коилов. + * @param start_shift - указатель на переменную содержащую сдвиг внутри регистра для начального коила. + * @param WriteFlag - флаг коилы нужны для чтения или записи. + * @return ExceptionCode - Код исключения если есть, и NO_ERRORS если нет. + * + * @details Определение адреса начального регистра запрашиваемых коилов. + * @note WriteFlag используется для определния регистров GPIO: ODR или IDR. + */ MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag) -{ - /* check quantity error */ - if (Qnt > 2000) - { - return ILLEGAL_DATA_VALUE; // return exception code - } - - // Default coils - if(MB_Check_Address_For_Arr(Addr, Qnt, C_CONTROL_ADDR, C_CONTROL_QNT) == NO_ERRORS) - { - *pCoils = MB_Set_Coil_Reg_Ptr(&MB_DATA.Coils, Addr); // указатель на выбранный по Addr массив коилов - } - // if address doesnt match any array - return illegal data address response - else - { - return ILLEGAL_DATA_ADDRESS; - } - - *start_shift = Addr % 16; // set shift to requested coil - // if found requeried array return no err - return NO_ERRORS; // return no errors +{ + /* check quantity error */ + if (Qnt > 2000) + { + return ILLEGAL_DATA_VALUE; // return exception code + } + + // Default coils + if(MB_Check_Address_For_Arr(Addr, Qnt, C_CONTROL_ADDR, C_CONTROL_QNT) == NO_ERRORS) + { + *pCoils = MB_Set_Coil_Reg_Ptr(&MB_DATA.Coils, Addr); // указатель на выбранный по Addr массив коилов + } + // if address doesnt match any array - return illegal data address response + else + { + return ILLEGAL_DATA_ADDRESS; + } + + *start_shift = Addr % 16; // set shift to requested coil + // if found requeried array return no err + return NO_ERRORS; // return no errors } /** - * @brief Proccess command Read Coils (01 - 0x01). - * @param modbus_msg - указатель на структуру собщения modbus. - * @return fMessageHandled - статус о результате обработки комманды. - * @details Обработка команды Read Coils. - */ -uint8_t MB_Read_Coils(RS_MsgTypeDef *modbus_msg) + * @brief Proccess command Read Coils (01 - 0x01). + * @param modbus_msg - указатель на структуру собщения modbus. + * @return fMessageHandled - статус о результате обработки комманды. + * @details Обработка команды Read Coils. + */ +uint8_t MB_Proccess_Read_Coils(RS_MsgTypeDef *modbus_msg) { - //---------CHECK FOR ERRORS---------- - uint16_t *coils; - uint16_t start_shift = 0; // shift in coils register - - modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, modbus_msg->Qnt, &start_shift, 0); - if(modbus_msg->Except_Code != NO_ERRORS) - return 0; - - //-----------READING COIL------------ - // setup output message data size - modbus_msg->ByteCnt = Divide_Up(modbus_msg->Qnt, 8); - // create mask for coils - uint16_t mask_for_coils = 0; // mask for coils that've been chosen - uint16_t setted_coils = 0; // value of setted coils - uint16_t temp_reg = 0; // temp register for saving coils that hasnt been chosen - uint16_t coil_cnt = 0; // counter for processed coils + //---------CHECK FOR ERRORS---------- + uint16_t *coils; + uint16_t start_shift = 0; // shift in coils register + + modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, modbus_msg->Qnt, &start_shift, 0); + if(modbus_msg->Except_Code != NO_ERRORS) + return 0; + + //-----------READING COIL------------ + // setup output message data size + modbus_msg->ByteCnt = Divide_Up(modbus_msg->Qnt, 8); + // create mask for coils + uint16_t mask_for_coils = 0; // mask for coils that've been chosen + uint16_t setted_coils = 0; // value of setted coils + uint16_t temp_reg = 0; // temp register for saving coils that hasnt been chosen + uint16_t coil_cnt = 0; // counter for processed coils - // cycle until all registers with requered coils would be processed - int shift = start_shift; // set shift to first coil in first register - int ind = 0; // index for coils registers and data - for(; ind <= Divide_Up(start_shift + modbus_msg->Qnt, 16); ind++) - { - //----SET MASK FOR COILS REGISTER---- - mask_for_coils = 0; - for(; shift < 0x10; shift++) - { - mask_for_coils |= 1<<(shift); // choose certain coil - if(++coil_cnt >= modbus_msg->Qnt) - break; - } - shift = 0; // set shift to zero for the next step - - //-----------READ COILS-------------- - modbus_msg->DATA[ind] = (*(coils+ind)&mask_for_coils) >> start_shift; - if(ind > 0) - modbus_msg->DATA[ind-1] |= ((*(coils+ind)&mask_for_coils) << 16) >> start_shift; - - } - // т.к. DATA 16-битная, для 8-битной передачи, надо поменять местами верхний и нижний байты - for(; ind >= 0; --ind) - modbus_msg->DATA[ind] = ByteSwap16(modbus_msg->DATA[ind]); - - return 1; + // cycle until all registers with requered coils would be processed + int shift = start_shift; // set shift to first coil in first register + int ind = 0; // index for coils registers and data + for(; ind <= Divide_Up(start_shift + modbus_msg->Qnt, 16); ind++) + { + //----SET MASK FOR COILS REGISTER---- + mask_for_coils = 0; + for(; shift < 0x10; shift++) + { + mask_for_coils |= 1<<(shift); // choose certain coil + if(++coil_cnt >= modbus_msg->Qnt) + break; + } + shift = 0; // set shift to zero for the next step + + //-----------READ COILS-------------- + modbus_msg->DATA[ind] = (*(coils+ind)&mask_for_coils) >> start_shift; + if(ind > 0) + modbus_msg->DATA[ind-1] |= ((*(coils+ind)&mask_for_coils) << 16) >> start_shift; + + } + // т.к. DATA 16-битная, для 8-битной передачи, надо поменять местами верхний и нижний байты + for(; ind >= 0; --ind) + modbus_msg->DATA[ind] = ByteSwap16(modbus_msg->DATA[ind]); + + return 1; } /** - * @brief Proccess command Read Holding Registers (03 - 0x03). - * @param modbus_msg - указатель на структуру собщения modbus. - * @return fMessageHandled - статус о результате обработки комманды. - * @details Обработка команды Read Holding Registers. - */ -uint8_t MB_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg) + * @brief Proccess command Read Holding Registers (03 - 0x03). + * @param modbus_msg - указатель на структуру собщения modbus. + * @return fMessageHandled - статус о результате обработки комманды. + * @details Обработка команды Read Holding Registers. + */ +uint8_t MB_Proccess_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg) { - //---------CHECK FOR ERRORS---------- - // get origin address for data - uint16_t *pHoldRegs; - modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров - if(modbus_msg->Except_Code != NO_ERRORS) - return 0; - + //---------CHECK FOR ERRORS---------- + // get origin address for data + uint16_t *pHoldRegs; + modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров + if(modbus_msg->Except_Code != NO_ERRORS) + return 0; + - //-----------READING REGS------------ - // setup output message data size - modbus_msg->ByteCnt = modbus_msg->Qnt*2; // *2 because we transmit 8 bits, not 16 bits - // read data - int i; - for (i = 0; iQnt; i++) - { - modbus_msg->DATA[i] = *(pHoldRegs++); - } - return 1; + //-----------READING REGS------------ + // setup output message data size + modbus_msg->ByteCnt = modbus_msg->Qnt*2; // *2 because we transmit 8 bits, not 16 bits + // read data + int i; + for (i = 0; iQnt; i++) + { + modbus_msg->DATA[i] = *(pHoldRegs++); + } + return 1; } /** - * @brief Proccess command Read Input Registers (04 - 0x04). - * @param modbus_msg - указатель на структуру собщения modbus. - * @return fMessageHandled - статус о результате обработки комманды. - * @details Обработка команды Read Input Registers. - */ -uint8_t MB_Read_Input_Regs(RS_MsgTypeDef *modbus_msg) + * @brief Proccess command Read Input Registers (04 - 0x04). + * @param modbus_msg - указатель на структуру собщения modbus. + * @return fMessageHandled - статус о результате обработки комманды. + * @details Обработка команды Read Input Registers. + */ +uint8_t MB_Proccess_Read_Input_Regs(RS_MsgTypeDef *modbus_msg) { - //---------CHECK FOR ERRORS---------- - // get origin address for data - uint16_t *pInRegs; - modbus_msg->Except_Code = MB_DefineRegistersAddress(&pInRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Input); // определение адреса регистров - if(modbus_msg->Except_Code != NO_ERRORS) - return 0; - + //---------CHECK FOR ERRORS---------- + // get origin address for data + uint16_t *pInRegs; + modbus_msg->Except_Code = MB_DefineRegistersAddress(&pInRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Input); // определение адреса регистров + if(modbus_msg->Except_Code != NO_ERRORS) + return 0; + - //-----------READING REGS------------ - // setup output message data size - modbus_msg->ByteCnt = modbus_msg->Qnt*2; // *2 because we transmit 8 bits, not 16 bits - // read data - int i; - for (i = 0; iQnt; i++) - { + //-----------READING REGS------------ + // setup output message data size + modbus_msg->ByteCnt = modbus_msg->Qnt*2; // *2 because we transmit 8 bits, not 16 bits + // read data + int i; + for (i = 0; iQnt; i++) + { if(*((int16_t *)pInRegs) > 0) - modbus_msg->DATA[i] = (*pInRegs++); + modbus_msg->DATA[i] = (*pInRegs++); else - modbus_msg->DATA[i] = (*pInRegs++); - } - return 1; + modbus_msg->DATA[i] = (*pInRegs++); + } + return 1; } /** - * @brief Proccess command Write Single Coils (05 - 0x05). - * @param modbus_msg - указатель на структуру собщения modbus. - * @return fMessageHandled - статус о результате обработки комманды. - * @details Обработка команды Write Single Coils. - */ -uint8_t MB_Write_Single_Coil(RS_MsgTypeDef *modbus_msg) + * @brief Proccess command Write Single Coils (05 - 0x05). + * @param modbus_msg - указатель на структуру собщения modbus. + * @return fMessageHandled - статус о результате обработки комманды. + * @details Обработка команды Write Single Coils. + */ +uint8_t MB_Proccess_Write_Single_Coil(RS_MsgTypeDef *modbus_msg) { - //---------CHECK FOR ERRORS---------- - if ((modbus_msg->Qnt != 0x0000) && (modbus_msg->Qnt != 0xFF00)) - { - modbus_msg->Except_Code = ILLEGAL_DATA_VALUE; - return 0; - } - // define position of coil - uint16_t *coils; - uint16_t start_shift = 0; // shift in coils register - modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, 0, &start_shift, 1); - if(modbus_msg->Except_Code != NO_ERRORS) - return 0; - + //---------CHECK FOR ERRORS---------- + if ((modbus_msg->Qnt != 0x0000) && (modbus_msg->Qnt != 0xFF00)) + { + modbus_msg->Except_Code = ILLEGAL_DATA_VALUE; + return 0; + } + // define position of coil + uint16_t *coils; + uint16_t start_shift = 0; // shift in coils register + modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, 0, &start_shift, 1); + if(modbus_msg->Except_Code != NO_ERRORS) + return 0; + - //----------WRITTING COIL------------ - if(modbus_msg->Qnt == 0xFF00) - *(coils) |= 1<Qnt == 0xFF00) + *(coils) |= 1<Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, 1, RegisterType_Holding); // определение адреса регистров - if(modbus_msg->Except_Code != NO_ERRORS) - return 0; - - //-----------WRITTING REG------------ - *(pHoldRegs) = modbus_msg->Qnt; - return 1; + * @brief Proccess command Write Single Register (06 - 0x06). + * @param modbus_msg - указатель на структуру собщения modbus. + * @return fMessageHandled - статус о результате обработки комманды. + * @details Обработка команды Write Single Register. + */ +uint8_t MB_Proccess_Write_Single_Reg(RS_MsgTypeDef *modbus_msg) +{ + // get origin address for data + uint16_t *pHoldRegs; + modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, 1, RegisterType_Holding); // определение адреса регистров + if(modbus_msg->Except_Code != NO_ERRORS) + return 0; + + //-----------WRITTING REG------------ + *(pHoldRegs) = modbus_msg->Qnt; + return 1; } /** - * @brief Proccess command Write Multiple Coils (15 - 0x0F). - * @param modbus_msg - указатель на структуру собщения modbus. - * @return fMessageHandled - статус о результате обработки комманды. - * @details Обработка команды Write Multiple Coils. - */ + * @brief Proccess command Write Multiple Coils (15 - 0x0F). + * @param modbus_msg - указатель на структуру собщения modbus. + * @return fMessageHandled - статус о результате обработки комманды. + * @details Обработка команды Write Multiple Coils. + */ uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg) { - //---------CHECK FOR ERRORS---------- - if (modbus_msg->ByteCnt != Divide_Up(modbus_msg->Qnt, 8)) - { // if quantity too large OR if quantity and bytes count arent match - modbus_msg->Except_Code = ILLEGAL_DATA_VALUE; - return 0; - } - // define position of coil - uint16_t *coils; // pointer to coils - uint16_t start_shift = 0; // shift in coils register - modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, modbus_msg->Qnt, &start_shift, 1); - if(modbus_msg->Except_Code != NO_ERRORS) - return 0; - - //----------WRITTING COILS----------- - // create mask for coils - uint16_t mask_for_coils = 0; // mask for coils that've been chosen - uint32_t setted_coils = 0; // value of setted coils - uint16_t temp_reg = 0; // temp register for saving coils that hasnt been chosen - uint16_t coil_cnt = 0; // counter for processed coils + //---------CHECK FOR ERRORS---------- + if (modbus_msg->ByteCnt != Divide_Up(modbus_msg->Qnt, 8)) + { // if quantity too large OR if quantity and bytes count arent match + modbus_msg->Except_Code = ILLEGAL_DATA_VALUE; + return 0; + } + // define position of coil + uint16_t *coils; // pointer to coils + uint16_t start_shift = 0; // shift in coils register + modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, modbus_msg->Qnt, &start_shift, 1); + if(modbus_msg->Except_Code != NO_ERRORS) + return 0; + + //----------WRITTING COILS----------- + // create mask for coils + uint16_t mask_for_coils = 0; // mask for coils that've been chosen + uint32_t setted_coils = 0; // value of setted coils + uint16_t temp_reg = 0; // temp register for saving coils that hasnt been chosen + uint16_t coil_cnt = 0; // counter for processed coils - // cycle until all registers with requered coils would be processed - int shift = start_shift; // set shift to first coil in first register - for(int ind = 0; ind <= Divide_Up(start_shift + modbus_msg->Qnt, 16); ind++) - { - //----SET MASK FOR COILS REGISTER---- - mask_for_coils = 0; - for(; shift < 0x10; shift++) - { - mask_for_coils |= 1<<(shift); // choose certain coil - if(++coil_cnt >= modbus_msg->Qnt) - break; - } - shift = 0; // set shift to zero for the next step - - - - //-----------WRITE COILS------------- - // get current coils - temp_reg = *(coils+ind); - // set coils - setted_coils = ByteSwap16(modbus_msg->DATA[ind]) << start_shift; - if(ind > 0) - { - setted_coils |= ((ByteSwap16(modbus_msg->DATA[ind-1]) << start_shift) >> 16); - } - // write coils - - *(coils+ind) = setted_coils & mask_for_coils; - // restore untouched coils - *(coils+ind) |= temp_reg&(~mask_for_coils); - - - if(coil_cnt >= modbus_msg->Qnt) // if all coils written - break cycle - break; // *kind of unnecessary - } - - return 1; + // cycle until all registers with requered coils would be processed + int shift = start_shift; // set shift to first coil in first register + for(int ind = 0; ind <= Divide_Up(start_shift + modbus_msg->Qnt, 16); ind++) + { + //----SET MASK FOR COILS REGISTER---- + mask_for_coils = 0; + for(; shift < 0x10; shift++) + { + mask_for_coils |= 1<<(shift); // choose certain coil + if(++coil_cnt >= modbus_msg->Qnt) + break; + } + shift = 0; // set shift to zero for the next step + + + + //-----------WRITE COILS------------- + // get current coils + temp_reg = *(coils+ind); + // set coils + setted_coils = ByteSwap16(modbus_msg->DATA[ind]) << start_shift; + if(ind > 0) + { + setted_coils |= ((ByteSwap16(modbus_msg->DATA[ind-1]) << start_shift) >> 16); + } + // write coils + + *(coils+ind) = setted_coils & mask_for_coils; + // restore untouched coils + *(coils+ind) |= temp_reg&(~mask_for_coils); + + + if(coil_cnt >= modbus_msg->Qnt) // if all coils written - break cycle + break; // *kind of unnecessary + } + + return 1; } /** - * @brief Proccess command Write Multiple Registers (16 - 0x10). - * @param modbus_msg - указатель на структуру собщения modbus. - * @return fMessageHandled - статус о результате обработки комманды. - * @details Обработка команды Write Multiple Registers. - */ -uint8_t MB_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg) + * @brief Proccess command Write Multiple Registers (16 - 0x10). + * @param modbus_msg - указатель на структуру собщения modbus. + * @return fMessageHandled - статус о результате обработки комманды. + * @details Обработка команды Write Multiple Registers. + */ +uint8_t MB_Proccess_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg) { - //---------CHECK FOR ERRORS---------- - if (modbus_msg->Qnt*2 != modbus_msg->ByteCnt) - { // if quantity and bytes count arent match - modbus_msg->Except_Code = 3; - return 0; - } - // get origin address for data - uint16_t *pHoldRegs; - modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров - if(modbus_msg->Except_Code != NO_ERRORS) - return 0; - - //-----------WRITTING REGS----------- - for (int i = 0; iQnt; i++) - { - *(pHoldRegs++) = modbus_msg->DATA[i]; - } - return 1; + //---------CHECK FOR ERRORS---------- + if (modbus_msg->Qnt*2 != modbus_msg->ByteCnt) + { // if quantity and bytes count arent match + modbus_msg->Except_Code = 3; + return 0; + } + // get origin address for data + uint16_t *pHoldRegs; + modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров + if(modbus_msg->Except_Code != NO_ERRORS) + return 0; + + //-----------WRITTING REGS----------- + for (int i = 0; iQnt; i++) + { + *(pHoldRegs++) = modbus_msg->DATA[i]; + } + return 1; } -void MB_WriteObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef *obj) + +/** + * @brief Write Object of Device Identification to MessageData + * @param mbdata - указатель на массив данных в структуре RS_MsgTypeDef. + * @return obj - объект для записи. + */ +void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef *obj) { mbdata[(*ind)++] = obj->length; for (int i = 0; i < obj->length; i++) @@ -553,175 +560,257 @@ void MB_WriteObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef mbdata[(*ind)++] = obj->name[i]; } } + + /** - * @brief Proccess command Read Device Identification (43/14 - 0x2B/0E). - * @param modbus_msg - указатель на структуру собщения modbus. - * @return fMessageHandled - статус о результате обработки комманды. - * @details Обработка команды Write Single Register. + * @brief Write Object of Device Identification to MessageData + * @param mbdata - указатель на массив данных в структуре RS_MsgTypeDef. + * @return obj - объект для записи. */ -uint8_t MB_Read_Device_Identification(RS_MsgTypeDef *modbus_msg) +void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj) { - char *mbdata = (char *)modbus_msg->DATA; + MB_DeviceObjectTypeDef *obj = (MB_DeviceObjectTypeDef *)&MB_DEVID; + unsigned objidtmp = modbus_msg->DevId.NextObjId; + + /* Define number of object in one message */ + unsigned lastobjid = 0; + for(int i = 0; i < DATA_SIZE*2;) + { + i += 2; + i += obj[objidtmp].length; + /* Если все еще помещается в массив переходим на следующий объект */ + if(i < DATA_SIZE*2) + { + objidtmp++; + } + /* Если объекты для записи закончились - выходим из цикла*/ + if(objidtmp > maxidofobj) + break; + } + lastobjid = objidtmp-1; + + + /* Fill message with objects data */ + char *mbdata = (char *)&modbus_msg->DATA; unsigned ind = 0; + unsigned objid = modbus_msg->DevId.NextObjId; + for(; objid <= lastobjid; objid++) + { + mbdata[ind++] = objid; + MB_WriteSingleObjectToMessage(mbdata, &ind, &obj[objid]); + } + objid--; + modbus_msg->ByteCnt = ind; + modbus_msg->DevId.NextObjId = lastobjid+1; + if(objid == maxidofobj) + { + modbus_msg->DevId.MoreFollows = 0; + } + else + { + modbus_msg->DevId.MoreFollows = 0xFF; + } +} + + +/** + * @brief Proccess command Read Device Identification (43/14 - 0x2B/0E). + * @param modbus_msg - указатель на структуру собщения modbus. + * @return fMessageHandled - статус о результате обработки комманды. + * @details Обработка команды Write Single Register. + */ +uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg) +{ switch(modbus_msg->DevId.ReadDevId) { case MB_BASIC_IDENTIFICATION: - mbdata[ind++] = 0x00; - MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.VendorName); - mbdata[ind++] = 0x01; - MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.ProductCode); - mbdata[ind++] = 0x02; - MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.Revision); + if (modbus_msg->DevId.NextObjId == 0) + { + modbus_msg->DevId.NextObjId = 0; + } + + MB_WriteObjectsToMessage(modbus_msg, 2); modbus_msg->DevId.NumbOfObj = 3; break; + case MB_REGULAR_IDENTIFICATION: - mbdata[ind++] = 0x03; - MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.VendorUrl); - mbdata[ind++] = 0x04; - MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.ProductName); - mbdata[ind++] = 0x05; - MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.ModelName); - mbdata[ind++] = 0x06; - MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.UserApplicationName); + if (modbus_msg->DevId.NextObjId == 0) + { + modbus_msg->DevId.NextObjId = 3; + } + + MB_WriteObjectsToMessage(modbus_msg, 6); modbus_msg->DevId.NumbOfObj = 4; break; + + case MB_EXTENDED_IDENTIFICATION: + if (modbus_msg->DevId.NextObjId == 0) + { + modbus_msg->DevId.NextObjId = 0x80; + } + + MB_WriteObjectsToMessage(modbus_msg, 0x80+MODBUS_NUMB_OF_USEROBJECTS); + modbus_msg->DevId.NumbOfObj = MODBUS_NUMB_OF_USEROBJECTS; + break; + + case MB_SPEDIFIC_IDENTIFICATION: + MB_WriteObjectsToMessage(modbus_msg, modbus_msg->DevId.NextObjId); + modbus_msg->DevId.NumbOfObj = 1; + break; default: return 0; } - - modbus_msg->ByteCnt = ind; return 1; } /** - * @brief Respond accord to received message. - * @param hRS - указатель на хендлер RS. - * @param RS_msg - указатель на структуру сообщения. - * @return RS_RES - статус о результате ответа на комманду. - * @details Обработка принятой комманды и ответ на неё. - */ + * @brief Respond accord to received message. + * @param hRS - указатель на хендлер RS. + * @param RS_msg - указатель на структуру сообщения. + * @return RS_RES - статус о результате ответа на комманду. + * @details Обработка принятой комманды и ответ на неё. + */ RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) { - RS_StatusTypeDef MB_RES = 0; - hmodbus->f.MessageHandled = 0; - hmodbus->f.EchoResponse = 0; - RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit - - if(modbus_msg->Func_Code < ERR_VALUES_START)// if no errors after parsing - { - switch (modbus_msg->Func_Code) - { - // Read Coils - case MB_R_COILS: - hmodbus->f.MessageHandled = MB_Read_Coils(hmodbus->pMessagePtr); - break; - - // Read Hodling Registers - case MB_R_HOLD_REGS: - hmodbus->f.MessageHandled = MB_Read_Hold_Regs(hmodbus->pMessagePtr); - break; - case MB_R_IN_REGS: - hmodbus->f.MessageHandled = MB_Read_Input_Regs(hmodbus->pMessagePtr); - break; - - - // Write Single Coils - case MB_W_COIL: - hmodbus->f.MessageHandled = MB_Write_Single_Coil(hmodbus->pMessagePtr); - if(hmodbus->f.MessageHandled) - { - hmodbus->f.EchoResponse = 1; - hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes) - } - break; - - case MB_W_HOLD_REG: - hmodbus->f.MessageHandled = MB_Write_Single_Reg(hmodbus->pMessagePtr); - if(hmodbus->f.MessageHandled) - { - hmodbus->f.EchoResponse = 1; - hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes) - } - break; - - // Write Multiple Coils - case MB_W_COILS: - hmodbus->f.MessageHandled = MB_Write_Miltuple_Coils(hmodbus->pMessagePtr); - if(hmodbus->f.MessageHandled) - { - hmodbus->f.EchoResponse = 1; - hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes) - } - break; - - // Write Multiple Registers - case MB_W_HOLD_REGS: - hmodbus->f.MessageHandled = MB_Write_Miltuple_Regs(hmodbus->pMessagePtr); - if(hmodbus->f.MessageHandled) - { - hmodbus->f.EchoResponse = 1; - hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes) - } - break; - + RS_StatusTypeDef MB_RES = 0; + hmodbus->f.MessageHandled = 0; + hmodbus->f.EchoResponse = 0; + RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit + + if(hmodbus->ID == 0) + { + hmodbus->RS_STATUS = RS_SKIP; + return MB_RES; + } + + if(modbus_msg->Func_Code < ERR_VALUES_START)// if no errors after parsing + { + switch (modbus_msg->Func_Code) + { + // Read Coils + case MB_R_COILS: + hmodbus->f.MessageHandled = MB_Proccess_Read_Coils(hmodbus->pMessagePtr); + break; + + // Read Hodling Registers + case MB_R_HOLD_REGS: + hmodbus->f.MessageHandled = MB_Proccess_Read_Hold_Regs(hmodbus->pMessagePtr); + break; + case MB_R_IN_REGS: + hmodbus->f.MessageHandled = MB_Proccess_Read_Input_Regs(hmodbus->pMessagePtr); + break; + + + // Write Single Coils + case MB_W_COIL: + hmodbus->f.MessageHandled = MB_Proccess_Write_Single_Coil(hmodbus->pMessagePtr); + if(hmodbus->f.MessageHandled) + { + hmodbus->f.DataUpdated = 1; + hmodbus->f.EchoResponse = 1; + hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes) + } + break; + + case MB_W_HOLD_REG: + hmodbus->f.MessageHandled = MB_Proccess_Write_Single_Reg(hmodbus->pMessagePtr); + if(hmodbus->f.MessageHandled) + { + hmodbus->f.DataUpdated = 1; + hmodbus->f.EchoResponse = 1; + hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes) + } + break; + + // Write Multiple Coils + case MB_W_COILS: + hmodbus->f.MessageHandled = MB_Write_Miltuple_Coils(hmodbus->pMessagePtr); + if(hmodbus->f.MessageHandled) + { + hmodbus->f.DataUpdated = 1; + hmodbus->f.EchoResponse = 1; + hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes) + } + break; + + // Write Multiple Registers + case MB_W_HOLD_REGS: + hmodbus->f.MessageHandled = MB_Proccess_Write_Miltuple_Regs(hmodbus->pMessagePtr); + if(hmodbus->f.MessageHandled) + { + hmodbus->f.DataUpdated = 1; + hmodbus->f.EchoResponse = 1; + hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes) + } + break; + case MB_R_DEVICE_INFO: - hmodbus->f.MessageHandled = MB_Read_Device_Identification(hmodbus->pMessagePtr); + hmodbus->f.MessageHandled = MB_Proccess_Read_Device_Identification(hmodbus->pMessagePtr); break; - - /* unknown func code */ - default: modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */ - } - - if(hmodbus->f.MessageHandled == 0) + /* unknown func code */ + default: modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */ + } + + if(hmodbus->f.MessageHandled == 0) { - modbus_msg->Func_Code += ERR_VALUES_START; + TrackerCnt_Warn(hmodbus->rs_err); + modbus_msg->Func_Code |= ERR_VALUES_START; } else { + TrackerCnt_Ok(hmodbus->rs_err); } - - - } - - // if we need response - check that transmit isnt busy - if( RS_Is_TX_Busy(hmodbus) ) - RS_Abort(hmodbus, ABORT_TX); // if tx busy - set it free - - // Transmit right there, or sets (fDeferredResponse) to transmit response in main code - MB_RES = RS_Handle_Transmit_Start(hmodbus, modbus_msg); - - hmodbus->RS_STATUS = MB_RES; - return MB_RES; + + + } + + // if we need response - check that transmit isnt busy + if( RS_Is_TX_Busy(hmodbus) ) + RS_Abort(hmodbus, ABORT_TX); // if tx busy - set it free + + // Transmit right there, or sets (fDeferredResponse) to transmit response in main code + if(hmodbus->f.DeferredResponse == 0) + { + MB_RES = RS_Handle_Transmit_Start(hmodbus, modbus_msg); + } + else + { + RS_Handle_Receive_Start(hmodbus, modbus_msg); + hmodbus->f.DeferredResponse = 0; + } + + hmodbus->RS_STATUS = MB_RES; + return MB_RES; } /** - * @brief Collect message in buffer to transmit it. - * @param hRS - указатель на хендлер RS. - * @param RS_msg - указатель на структуру сообщения. - * @param msg_uart_buff - указатель на буффер UART. - * @return RS_RES - статус о результате заполнения буфера. - * @details Заполнение буффера UART из структуры сообщения. - */ + * @brief Collect message in buffer to transmit it. + * @param hRS - указатель на хендлер RS. + * @param RS_msg - указатель на структуру сообщения. + * @param msg_uart_buff - указатель на буффер UART. + * @return RS_RES - статус о результате заполнения буфера. + * @details Заполнение буффера UART из структуры сообщения. + */ RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) { - int ind = 0; // ind for modbus-uart buffer - - if(hmodbus->f.EchoResponse && hmodbus->f.MessageHandled) // if echo response need - ind = hmodbus->RS_Message_Size; - else - { - //------INFO ABOUT DATA/MESSAGE------ - //-----------[first bytes]----------- - // set ID of message/user - modbus_uart_buff[ind++] = modbus_msg->MbAddr; + int ind = 0; // ind for modbus-uart buffer + + if(hmodbus->f.EchoResponse && hmodbus->f.MessageHandled) // if echo response need + ind = hmodbus->RS_Message_Size; + else + { + //------INFO ABOUT DATA/MESSAGE------ + //-----------[first bytes]----------- + // set ID of message/user + modbus_uart_buff[ind++] = modbus_msg->MbAddr; - // set dat or err response - modbus_uart_buff[ind++] = modbus_msg->Func_Code; + // set dat or err response + modbus_uart_buff[ind++] = modbus_msg->Func_Code; - if (modbus_msg->Func_Code < ERR_VALUES_START) // if no error occur - { + if (modbus_msg->Func_Code < ERR_VALUES_START) // if no error occur + { // fill modbus header if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // devide identification header { @@ -734,6 +823,7 @@ RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mo if (modbus_msg->ByteCnt > DATA_SIZE*2) // if ByteCnt less than DATA_SIZE { + TrackerCnt_Err(hmodbus->rs_err); return RS_COLLECT_MSG_ERR; } @@ -742,7 +832,7 @@ RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mo //-----------[data bytes]------------ uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA; for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data - { // set data + { // set data modbus_uart_buff[ind++] = *tmp_data_addr; tmp_data_addr++; } @@ -753,8 +843,9 @@ RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mo // set size of received data if (modbus_msg->ByteCnt <= DATA_SIZE*2) // if ByteCnt less than DATA_SIZE modbus_uart_buff[ind++] = modbus_msg->ByteCnt; - else // otherwise return data_size err + else // otherwise return data_size err { + TrackerCnt_Err(hmodbus->rs_err); return RS_COLLECT_MSG_ERR; } @@ -762,10 +853,10 @@ RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mo //-----------[data bytes]------------ uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA; for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data - { // set data - if (i%2 == 0) // HI byte + { // set data + if (i%2 == 0) // HI byte modbus_uart_buff[ind++] = (*tmp_data_addr)>>8; - else // LO byte + else // LO byte { modbus_uart_buff[ind++] = *tmp_data_addr; tmp_data_addr++; @@ -774,48 +865,57 @@ RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mo } - } - else // if some error occur - { // send expection code - modbus_uart_buff[ind++] = modbus_msg->Except_Code; - } - } - //---------------CRC---------------- - //---------[last 16 bytes]---------- - // calc crc of received data - uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind); - // write crc to message structure and modbus-uart buffer - modbus_msg->MB_CRC = CRC_VALUE; - modbus_uart_buff[ind++] = CRC_VALUE; - modbus_uart_buff[ind++] = CRC_VALUE >> 8; - - hmodbus->RS_Message_Size = ind; - - return RS_OK; // returns ok + } + else // if some error occur + { // send expection code + modbus_uart_buff[ind++] = modbus_msg->Except_Code; + } + } + //---------------CRC---------------- + //---------[last 16 bytes]---------- + // calc crc of received data + uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind); + // write crc to message structure and modbus-uart buffer + modbus_msg->MB_CRC = CRC_VALUE; + modbus_uart_buff[ind++] = CRC_VALUE; + modbus_uart_buff[ind++] = CRC_VALUE >> 8; + + hmodbus->RS_Message_Size = ind; + + return RS_OK; // returns ok } /** - * @brief Parse message from buffer to process it. - * @param hRS - указатель на хендлер RS. - * @param RS_msg - указатель на структуру сообщения. - * @param msg_uart_buff - указатель на буффер UART. - * @return RS_RES - статус о результате заполнения структуры. - * @details Заполнение структуры сообщения из буффера UART. - */ + * @brief Parse message from buffer to process it. + * @param hRS - указатель на хендлер RS. + * @param RS_msg - указатель на структуру сообщения. + * @param msg_uart_buff - указатель на буффер UART. + * @return RS_RES - статус о результате заполнения структуры. + * @details Заполнение структуры сообщения из буффера UART. + */ RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) { - uint32_t check_empty_buff; - int ind = 0; // ind for modbus-uart buffer - //-----INFO ABOUT DATA/MESSAGE------- - //-----------[first bits]------------ - // get ID of message/user + uint32_t check_empty_buff; + int ind = 0; // ind for modbus-uart buffer + //-----INFO ABOUT DATA/MESSAGE------- + //-----------[first bits]------------ + // get ID of message/user + if(modbus_uart_buff[ind] != hmodbus->ID) + { + modbus_msg->MbAddr = 0; + return RS_SKIP; + } modbus_msg->MbAddr = modbus_uart_buff[ind++]; - if(modbus_msg->MbAddr != hmodbus->ID) - return RS_SKIP; - - // get func code - modbus_msg->Func_Code = modbus_uart_buff[ind++]; - if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // if it device identification request + + // get func code + modbus_msg->Func_Code = modbus_uart_buff[ind++]; + if(modbus_msg->Func_Code & ERR_VALUES_START) // явная херня + { + modbus_msg->MbAddr = 0; + return RS_SKIP; + } + + if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // if it device identification request { modbus_msg->DevId.MEI_Type = modbus_uart_buff[ind++]; modbus_msg->DevId.ReadDevId = modbus_uart_buff[ind++]; @@ -824,127 +924,117 @@ RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modb } else // if its classic modbus request { - // get address from CMD - modbus_msg->Addr = modbus_uart_buff[ind++] << 8; - modbus_msg->Addr |= modbus_uart_buff[ind++]; - - // get address from CMD - modbus_msg->Qnt = modbus_uart_buff[ind++] << 8; - modbus_msg->Qnt |= modbus_uart_buff[ind++]; - } - if(hmodbus->f.RX_Half == 0) // if all message received - { - //---------------DATA---------------- - // (optional) - if (modbus_msg->ByteCnt != 0) - { - ind++; // increment ind for data_size byte - //check that data size is correct - if (modbus_msg->ByteCnt > DATA_SIZE*2) - { - modbus_msg->Func_Code += ERR_VALUES_START; - return RS_PARSE_MSG_ERR; - } - uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA; - for(int i = 0; i < modbus_msg->ByteCnt; i++) // /2 because we transmit 8 bits, not 16 bits - { // set data - if (i%2 == 0) - *tmp_data_addr = ((uint16_t)modbus_uart_buff[ind++] << 8); - else - { - *tmp_data_addr |= modbus_uart_buff[ind++]; - tmp_data_addr++; - } - } - } - - //---------------CRC---------------- - //----------[last 16 bits]---------- - // calc crc of received data - uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind); - // get crc of received data - modbus_msg->MB_CRC = modbus_uart_buff[ind++]; - modbus_msg->MB_CRC |= modbus_uart_buff[ind++] << 8; - // compare crc - if (modbus_msg->MB_CRC != CRC_VALUE) + // get address from CMD + modbus_msg->Addr = modbus_uart_buff[ind++] << 8; + modbus_msg->Addr |= modbus_uart_buff[ind++]; + + // get address from CMD + modbus_msg->Qnt = modbus_uart_buff[ind++] << 8; + modbus_msg->Qnt |= modbus_uart_buff[ind++]; + } + + if((hmodbus->pMessagePtr->Func_Code == 0x0F) || (hmodbus->pMessagePtr->Func_Code == 0x10)) + hmodbus->pMessagePtr->ByteCnt = modbus_uart_buff[ind++]; + else + hmodbus->pMessagePtr->ByteCnt = 0; + //---------------DATA---------------- + // (optional) + if (modbus_msg->ByteCnt != 0) { - modbus_msg->Func_Code += ERR_VALUES_START; + //check that data size is correct + if (modbus_msg->ByteCnt > DATA_SIZE*2) + { + TrackerCnt_Err(hmodbus->rs_err); + modbus_msg->Func_Code |= ERR_VALUES_START; + return RS_PARSE_MSG_ERR; + } + uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA; + for(int i = 0; i < modbus_msg->ByteCnt; i++) + { // set data + if (i%2 == 0) + *tmp_data_addr = ((uint16_t)modbus_uart_buff[ind++] << 8); + else + { + *tmp_data_addr |= modbus_uart_buff[ind++]; + tmp_data_addr++; + } + } } - // hmodbus->MB_RESPONSE = MB_CRC_ERR; // set func code - error about wrong crc - - // check is buffer empty - check_empty_buff = 0; - for(int i=0; iMB_RESPONSE = MB_EMPTY_MSG; // - } - - return RS_OK; - + + //---------------CRC---------------- + //----------[last 16 bits]---------- + // calc crc of received data + uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind); + // get crc of received data + modbus_msg->MB_CRC = modbus_uart_buff[ind++]; + modbus_msg->MB_CRC |= modbus_uart_buff[ind++] << 8; + // compare crc + if (modbus_msg->MB_CRC != CRC_VALUE) + { + TrackerCnt_Err(hmodbus->rs_err); + modbus_msg->Func_Code |= ERR_VALUES_START; + } +// hmodbus->MB_RESPONSE = MB_CRC_ERR; // set func code - error about wrong crc + + // check is buffer empty + check_empty_buff = 0; + for(int i=0; iMB_RESPONSE = MB_EMPTY_MSG; // + + return RS_OK; } /** - * @brief Define size of RX Message that need to be received. - * @param hRS - указатель на хендлер RS. - * @param rx_data_size - указатель на переменную для записи кол-ва байт для принятия. - * @return RS_RES - статус о корректности рассчета кол-ва байт для принятия. - * @details Определение сколько байтов надо принять по протоколу. - */ + * @brief Define size of RX Message that need to be received. + * @param hRS - указатель на хендлер RS. + * @param rx_data_size - указатель на переменную для записи кол-ва байт для принятия. + * @return RS_RES - статус о корректности рассчета кол-ва байт для принятия. + * @details Определение сколько байтов надо принять по протоколу. + */ RS_StatusTypeDef RS_Define_Size_of_RX_Message(RS_HandleTypeDef *hmodbus, uint32_t *rx_data_size) -{ - RS_StatusTypeDef MB_RES = 0; - - MB_RES = RS_Parse_Message(hmodbus, hmodbus->pMessagePtr, hmodbus->pBufferPtr); - if(MB_RES == RS_SKIP) // if message not for us - return MB_RES; // return - +{ + RS_StatusTypeDef MB_RES = 0; - if ((hmodbus->pMessagePtr->Func_Code & ~ERR_VALUES_START) < 0x0F) - { - hmodbus->pMessagePtr->ByteCnt = 0; - *rx_data_size = 1; + MB_RES = RS_Parse_Message(hmodbus, hmodbus->pMessagePtr, hmodbus->pBufferPtr); +// if(MB_RES == RS_SKIP) // if message not for us +// return MB_RES; // return + + + if ((hmodbus->pMessagePtr->Func_Code & ~ERR_VALUES_START) < 0x0F) + { + hmodbus->pMessagePtr->ByteCnt = 0; + *rx_data_size = 1; - } - else - { - hmodbus->pMessagePtr->ByteCnt = hmodbus->pBufferPtr[RX_FIRST_PART_SIZE-1]; // get numb of data in command - // +1 because that defines is size, not ind. - *rx_data_size = hmodbus->pMessagePtr->ByteCnt + 2; - } + } + else + { + hmodbus->pMessagePtr->ByteCnt = hmodbus->pBufferPtr[RX_FIRST_PART_SIZE-1]; // get numb of data in command + // +1 because that defines is size, not ind. + *rx_data_size = hmodbus->pMessagePtr->ByteCnt + 2; + } if(hmodbus->pMessagePtr->Func_Code == MB_R_DEVICE_INFO) { - *rx_data_size = 0; + *rx_data_size = 0; } - hmodbus->RS_Message_Size = RX_FIRST_PART_SIZE + *rx_data_size; // size of whole message - return RS_OK; + hmodbus->RS_Message_Size = RX_FIRST_PART_SIZE + *rx_data_size; // size of whole message + return RS_OK; } -//-----------------------------FOR USER------------------------------ -//------------------------------------------------------------------- - -void MB_DevoceInentificationInit(void) +void MB_DeviceInentificationInit(void) { - MB_INFO.VendorName.name = MODBUS_VENDOR_NAME; - MB_INFO.ProductCode.name = MODBUS_PRODUCT_CODE; - MB_INFO.Revision.name = MODBUS_REVISION; - MB_INFO.VendorUrl.name = MODBUS_VENDOR_URL; - MB_INFO.ProductName.name = MODBUS_PRODUCT_NAME; - MB_INFO.ModelName.name = MODBUS_MODEL_NAME; - MB_INFO.UserApplicationName.name = MODBUS_USER_APPLICATION_NAME; - - - MB_INFO.VendorName.length = sizeof(MODBUS_VENDOR_NAME); - MB_INFO.ProductCode.length = sizeof(MODBUS_PRODUCT_CODE); - MB_INFO.Revision.length = sizeof(MODBUS_REVISION); - MB_INFO.VendorUrl.length = sizeof(MODBUS_VENDOR_URL); - MB_INFO.ProductName.length = sizeof(MODBUS_PRODUCT_NAME); - MB_INFO.ModelName.length = sizeof(MODBUS_MODEL_NAME); - MB_INFO.UserApplicationName.length = sizeof(MODBUS_USER_APPLICATION_NAME); + MB_ObjectInit(&MB_DEVID.VendorName, MODBUS_VENDOR_NAME); + MB_ObjectInit(&MB_DEVID.ProductCode, MODBUS_PRODUCT_CODE); + MB_ObjectInit(&MB_DEVID.Revision, MODBUS_REVISION); + MB_ObjectInit(&MB_DEVID.VendorUrl, MODBUS_VENDOR_URL); + MB_ObjectInit(&MB_DEVID.ProductName, MODBUS_PRODUCT_NAME); + MB_ObjectInit(&MB_DEVID.ModelName, MODBUS_MODEL_NAME); + } diff --git a/Modbus/modbus.h b/Modbus/modbus.h index 8514eb4..0d596e5 100644 --- a/Modbus/modbus.h +++ b/Modbus/modbus.h @@ -1,286 +1,400 @@ /** - ************************************************************************** - * @file modbus.h - * @brief Заголовочный файл модуля MODBUS. - * @details Данный файл необходимо подключить в rs_message.h. После подключать - * rs_message.h к основному проекту. - * - * @defgroup MODBUS - * @brief Modbus stuff - * - *************************************************************************/ + ************************************************************************** + * @file modbus.h + * @brief Заголовочный файл модуля MODBUS. + * @details Данный файл необходимо подключить в rs_message.h. После подключать + * rs_message.h к основному проекту. + * + * @defgroup MODBUS + * @brief Modbus stuff + * + *************************************************************************/ #ifndef __MODBUS_H_ #define __MODBUS_H_ #include "modbus_config.h" #include "modbus_data.h" -//#include "settings.h" // for modbus settings +#include "__crc_algs.h" /** - * @addtogroup MODBUS_SETTINGS - * @ingroup MODBUS - * @brief Some defines for modbus - @{ - */ + * @addtogroup MODBUS_SETTINGS + * @ingroup MODBUS + * @brief Some defines for modbus + @{ + */ ///////////////////////////////////////////////////////////////////// //////////////////////////---SETTINGS---///////////////////////////// // USER SETTINGS FOR MODBUS IN interface_config.h +/** + * @brief Поменять комманды 0x03 и 0x04 местами (для LabView терминалки от двигателей) + * @details Терминалка от двигателей использует для чтения регистров комманду R_HOLD_REGS вместо R_IN_REGS + * Поэтому чтобы считывать Input Regs - надо поменять их местами. + */ +//#define MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS //////////////////////////---SETTINGS---///////////////////////////// ///////////////////////////////////////////////////////////////////// -/////////////////////---USER MESSAGE DEFINES---////////////////////// +////////////////////---MODBUS MESSAGE DEFINES---///////////////////// //-------------DEFINES FOR STRUCTURE---------------- /* defines for structure of modbus message */ -#define MbAddr_SIZE 1 ///< size of (MbAddr) -#define Func_Code_SIZE 1 ///< size of (Func_Code) -#define Addr_SIZE 2 ///< size of (Addr) -#define Qnt_SIZE 2 ///< size of (Qnt) -#define ByteCnt_SIZE 1 ///< size of (ByteCnt) -#define DATA_SIZE 125 ///< maximum number of data: DWORD (NOT MESSAGE SIZE) -#define CRC_SIZE 2 ///< size of (MB_CRC) in bytes +#define MbAddr_SIZE 1 ///< size of (MbAddr) +#define Func_Code_SIZE 1 ///< size of (Func_Code) +#define Addr_SIZE 2 ///< size of (Addr) +#define Qnt_SIZE 2 ///< size of (Qnt) +#define ByteCnt_SIZE 1 ///< size of (ByteCnt) +#define DATA_SIZE 125 ///< maximum number of data: DWORD (NOT MESSAGE SIZE) +#define CRC_SIZE 2 ///< size of (MB_CRC) in bytes /** @brief Size of whole message */ -#define INFO_SIZE_MAX (MbAddr_SIZE+Func_Code_SIZE+Addr_SIZE+Qnt_SIZE+ByteCnt_SIZE) +#define INFO_SIZE_MAX (MbAddr_SIZE+Func_Code_SIZE+Addr_SIZE+Qnt_SIZE+ByteCnt_SIZE) /** @brief Size of first part of message that will be received first receive info part of message, than defines size of rest message*/ -#define RX_FIRST_PART_SIZE INFO_SIZE_MAX +#define RX_FIRST_PART_SIZE INFO_SIZE_MAX /** @brief Size of buffer: max size of whole message */ -#define MSG_SIZE_MAX (INFO_SIZE_MAX + DATA_SIZE*2 + CRC_SIZE) // max possible size of message +#define MSG_SIZE_MAX (INFO_SIZE_MAX + DATA_SIZE*2 + CRC_SIZE) // max possible size of message /** @brief Structure for modbus exception codes */ typedef enum //MB_ExceptionTypeDef { - // reading - NO_ERRORS = 0x00, ///< no errors - ILLEGAL_FUNCTION = 0x01, ///< Принятый код функции не может быть обработан - ILLEGAL_DATA_ADDRESS = 0x02, ///< Адрес данных, указанный в запросе, недоступен - ILLEGAL_DATA_VALUE = 0x03, ///< Значение, содержащееся в поле данных запроса, является недопустимой величиной - SLAVE_DEVICE_FAILURE = 0x04, ///< Невосстанавливаемая ошибка имела место, пока ведомое устройство пыталось выполнить затребованное действие -// ACKNOWLEDGE = 0x05, ///< idk -// SLAVE_DEVICE_BUSY = 0x06, ///< idk -// MEMORY_PARITY_ERROR = 0x08, ///< idk + // reading + NO_ERRORS = 0x00, ///< no errors + ILLEGAL_FUNCTION = 0x01, ///< Принятый код функции не может быть обработан + ILLEGAL_DATA_ADDRESS = 0x02, ///< Адрес данных, указанный в запросе, недоступен + ILLEGAL_DATA_VALUE = 0x03, ///< Значение, содержащееся в поле данных запроса, является недопустимой величиной + SLAVE_DEVICE_FAILURE = 0x04, ///< Невосстанавливаемая ошибка имела место, пока ведомое устройство пыталось выполнить затребованное действие +// ACKNOWLEDGE = 0x05, ///< idk +// SLAVE_DEVICE_BUSY = 0x06, ///< idk +// MEMORY_PARITY_ERROR = 0x08, ///< idk }MB_ExceptionTypeDef; -#define ERR_VALUES_START 0x80U ///< from this value starts error func codes +#define ERR_VALUES_START 0x80U ///< from this value starts error func codes /** @brief Structure for modbus func codes */ typedef enum //MB_FunctonTypeDef { /* COMMANDS */ - // reading - MB_R_COILS = 0x01, ///< Чтение битовых ячеек - MB_R_DISC_IN = 0x02, ///< Чтение дискретных входов + // reading + MB_R_COILS = 0x01, ///< Чтение битовых ячеек + MB_R_DISC_IN = 0x02, ///< Чтение дискретных входов #ifndef MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS - MB_R_HOLD_REGS = 0x03, ///< Чтение входных регистров - MB_R_IN_REGS = 0x04, ///< Чтение регистров хранения + MB_R_HOLD_REGS = 0x03, ///< Чтение входных регистров + MB_R_IN_REGS = 0x04, ///< Чтение регистров хранения #else - MB_R_HOLD_REGS = 0x04, ///< Чтение входных регистров - MB_R_IN_REGS = 0x03, ///< Чтение регистров хранения + MB_R_HOLD_REGS = 0x04, ///< Чтение входных регистров + MB_R_IN_REGS = 0x03, ///< Чтение регистров хранения #endif - - // writting - MB_W_COIL = 0x05, ///< Запись битовой ячейки - MB_W_HOLD_REG = 0x06, ///< Запись одиночного регистра - MB_W_COILS = 0x0F, ///< Запись нескольких битовых ячеек - MB_W_HOLD_REGS = 0x10, ///< Запись нескольких регистров - MB_R_DEVICE_INFO = 0x2B, ///< Чтения информации об устройстве + // writting + MB_W_COIL = 0x05, ///< Запись битовой ячейки + MB_W_HOLD_REG = 0x06, ///< Запись одиночного регистра + MB_W_COILS = 0x0F, ///< Запись нескольких битовых ячеек + MB_W_HOLD_REGS = 0x10, ///< Запись нескольких регистров + + MB_R_DIAGNOSTIC = 0x08, ///< Чтение диагностической информации устройства + MB_R_DEVICE_INFO = 0x2B, ///< Чтение информации об устройстве /* ERRORS */ - // error reading - MB_ERR_R_COILS = MB_R_COILS + ERR_VALUES_START, ///< Ошибка чтения битовых ячеек - MB_ERR_R_DISC_IN = MB_R_DISC_IN + ERR_VALUES_START, ///< Ошибка чтения дискретных входов - MB_ERR_R_IN_REGS = MB_R_IN_REGS + ERR_VALUES_START, ///< Ошибка чтения регистров хранения - MB_ERR_R_HOLD_REGS = MB_R_HOLD_REGS + ERR_VALUES_START, ///< Ошибка чтения входных регистров - - // error writting - MB_ERR_W_COIL = MB_W_COIL + ERR_VALUES_START, ///< Ошибка записи битовой ячейки - MB_ERR_W_HOLD_REG = MB_W_HOLD_REG + ERR_VALUES_START, ///< Ошибка записи одиночного регистра - MB_ERR_W_COILS = MB_W_COILS + ERR_VALUES_START, ///< Ошибка записи нескольких битовых ячеек - MB_ERR_W_HOLD_REGS = MB_W_HOLD_REGS + ERR_VALUES_START, ///< Ошибка записи нескольких регистров + // error reading + MB_ERR_R_COILS = MB_R_COILS + ERR_VALUES_START, ///< Ошибка чтения битовых ячеек + MB_ERR_R_DISC_IN = MB_R_DISC_IN + ERR_VALUES_START, ///< Ошибка чтения дискретных входов + MB_ERR_R_IN_REGS = MB_R_IN_REGS + ERR_VALUES_START, ///< Ошибка чтения регистров хранения + MB_ERR_R_HOLD_REGS = MB_R_HOLD_REGS + ERR_VALUES_START, ///< Ошибка чтения входных регистров + + // error writting + MB_ERR_W_COIL = MB_W_COIL + ERR_VALUES_START, ///< Ошибка записи битовой ячейки + MB_ERR_W_HOLD_REG = MB_W_HOLD_REG + ERR_VALUES_START, ///< Ошибка записи одиночного регистра + MB_ERR_W_COILS = MB_W_COILS + ERR_VALUES_START, ///< Ошибка записи нескольких битовых ячеек + MB_ERR_W_HOLD_REGS = MB_W_HOLD_REGS + ERR_VALUES_START, ///< Ошибка записи нескольких регистров + + MB_ERR_R_DIAGNOSTIC = MB_R_DIAGNOSTIC + ERR_VALUES_START, ///< Ошибка чтения диагностической информации устройства + MB_ERR_R_DEVICE_INFO = MB_R_DEVICE_INFO + ERR_VALUES_START, ///< Ошибка чтения информации об устройстве }MB_FunctonTypeDef; + +/** @brief Structure for modbus diagnostics sub-functions codes */ +typedef enum +{ + RETURN_QUERRY_DATA = 0x0, + RESTART_COMM_OPTIONS = 0x1, + RETURN_DIAG_REG = 0x2, + CHANGE_ASCII_INPUT_DELIMITER = 0x3, + FORCE_LISTEN_ONLY_MODE = 0x4, + CLEAR_CNT_AND_DIAG_REG = 0xA, + RETURN_BUS_MSG_CNT = 0xB, + RETURN_BUS_COMM_ERR_CNT = 0xC, + RETURN_BUS_EXCEPT_ERR_CNT = 0xD, + RETURN_SLAVE_MSG_CNT = 0xE, + RETURN_SLAVE_NO_RESP_CNT = 0xF, + RETURN_SLAVE_NAK_CNT = 0x10, + RETURN_SLAVE_BUSY_CNT = 0x11, + RETURN_BUS_CHAR_OVERRUN = 0x12, + CLEAR_OVR_CNT_AND_FLAG = 0x12, +}MB_DiagnosticsSubFunctionTypeDef; + + /** @brief Structure for MEI func codes */ typedef enum //MB_FunctonTypeDef { MEI_DEVICE_IDENTIFICATION = 0x0E, }MB_MEITypeDef; -/** @brief Structure for MEI func codes */ +/** @brief Structure for comformity */ typedef enum //MB_FunctonTypeDef { - MB_BASIC_IDENTIFICATION = 0x01, - MB_REGULAR_IDENTIFICATION = 0x02, + MB_BASIC_IDENTIFICATION = 0x01, /*!< @brief Basic Device Identification. + @details All objects of this category are mandatory: + VendorName,Product code, and revision number */ + MB_REGULAR_IDENTIFICATION = 0x02, /*!< @brief Regular Device Identification. + @details The device provides additional and optional + identification and description data objects */ + + MB_EXTENDED_IDENTIFICATION = 0x03, /*!< @brief Extended Device Identification. + @details The device provides additional and optional + identification and description private data about the physical + device itself. All of these data are device dependent. */ + + MB_SPEDIFIC_IDENTIFICATION = 0x04, /*!< @brief Specific Device Identification. + @details The device provides one specific identification object. */ /* ERRORS */ MB_ERR_BASIC_IDENTIFICATION = MB_BASIC_IDENTIFICATION + ERR_VALUES_START, MB_ERR_REGULAR_IDENTIFICATION = MB_REGULAR_IDENTIFICATION + ERR_VALUES_START, + MB_ERR_EXTENDED_IDENTIFICATION = MB_REGULAR_IDENTIFICATION + ERR_VALUES_START, + MB_ERR_SPEDIFIC_IDENTIFICATION = MB_REGULAR_IDENTIFICATION + ERR_VALUES_START, }MB_ConformityTypeDef; /** @brief Structure for decive identification message type */ typedef struct { - MB_MEITypeDef MEI_Type; ///< MEI Type assigned number for Device Identification Interface + MB_MEITypeDef MEI_Type; ///< MEI Type assigned number for Device Identification Interface MB_ConformityTypeDef ReadDevId; MB_ConformityTypeDef Conformity; - uint8_t MoreFollows; ///< in this library always a zero + uint8_t MoreFollows; uint8_t NextObjId; uint8_t NumbOfObj; }MB_DevIdMsgTypeDef; + /** @brief Structure for modbus messsage */ -typedef struct // RS_MsgTypeDef +typedef struct // RS_MsgTypeDef { - uint8_t MbAddr; ///< Modbus Slave Address - MB_FunctonTypeDef Func_Code; ///< Modbus Function Code + uint8_t MbAddr; ///< Modbus Slave Address + MB_FunctonTypeDef Func_Code; ///< Modbus Function Code MB_DevIdMsgTypeDef DevId; ///< Read Device Identification Header struct - uint16_t Addr; ///< Modbus Address of data - uint16_t Qnt; ///< Quantity of modbus data - uint8_t ByteCnt; ///< Quantity of bytes of data in message to transmit/receive - - uint16_t DATA[DATA_SIZE]; ///< Modbus Data - MB_ExceptionTypeDef Except_Code; ///< Exception Code for the command - - uint16_t MB_CRC; ///< Modbus CRC + uint16_t Addr; ///< Modbus Address of data + uint16_t Qnt; ///< Quantity of modbus data + uint8_t ByteCnt; ///< Quantity of bytes of data in message to transmit/receive + + uint16_t DATA[DATA_SIZE]; ///< Modbus Data + MB_ExceptionTypeDef Except_Code; ///< Exception Code for the command + + uint16_t MB_CRC; ///< Modbus CRC }RS_MsgTypeDef; //-------------------------------------------------- extern RS_MsgTypeDef MODBUS_MSG; -/////////////////////---MODBUS USER SETTINGS---////////////////////// +////////////////////---MODBUS MESSAGE DEFINES---///////////////////// + + +///////////////////////////////////////////////////////////////////// +///////////////---DEVICE IDENTIVICATIONS DEFINES---////////////////// + +/** @brief Структура для объекта (идентификатора устройства модбас) */ +typedef struct +{ + unsigned length; + char *name; +}MB_DeviceObjectTypeDef; + +/** @brief Структура со идентификаторами устройства модбас */ +typedef struct +{ + MB_DeviceObjectTypeDef VendorName; + MB_DeviceObjectTypeDef ProductCode; + MB_DeviceObjectTypeDef Revision; + MB_DeviceObjectTypeDef VendorUrl; + MB_DeviceObjectTypeDef ProductName; + MB_DeviceObjectTypeDef ModelName; + MB_DeviceObjectTypeDef UserApplicationName; + + MB_DeviceObjectTypeDef Reserved[0x79]; + + MB_DeviceObjectTypeDef User[MODBUS_NUMB_OF_USEROBJECTS]; +}MB_DeviceIdentificationTypeDef; +extern MB_DeviceIdentificationTypeDef MB_DEVID; +void MB_DeviceInentificationInit(void); +///////////////---DEVICE IDENTIVICATIONS DEFINES---////////////////// + +///////////////////////////////////////////////////////////////////// +/////////////////---DEVICE DIAGNOSTICS DEFINES---//////////////////// + +/** @brief Структура со диагностической информацией устройства модбас */ +typedef struct +{ + uint16_t DiagnosticRegister; + struct + { + uint16_t BusMessage; + uint16_t BusCommunicationErr; + uint16_t BusExceptionErr; + uint16_t SlaveMessage; + uint16_t SlaveNoResponse; + uint16_t SlaveNAK; + uint16_t SlaveBusy; + uint16_t BusCharacterOverrun; + }Counters; +}MB_DiagnosticsInfoTypeDef; +extern MB_DiagnosticsInfoTypeDef MB_DINFO; + + +/////////////////---DEVICE DIAGNOSTICS DEFINES---//////////////////// /** MODBUS_SETTINGS * @} */ ///////////////////////////////////////////////////////////////////// -////////////////////---MODBUS MESSAGE DEFINES---///////////////////// +////////////////////---MODBUS FUNCTION DEFINES---//////////////////// /** - * @addtogroup MODBUS_MESSAGE_DEFINES - * @ingroup MODBUS - * @brief Some defines for modbus - @{ - */ + * @addtogroup MODBUS_MESSAGE_DEFINES + * @ingroup MODBUS + * @brief Some defines for modbus + @{ + */ /** @brief Structure for coils operation */ typedef enum { - SET_COIL, - RESET_COIL, - TOOGLE_COIL, + SET_COIL, + RESET_COIL, + TOOGLE_COIL, }MB_CoilsOpTypeDef; //-------------------------------------------------- /** - * @brief Macros to set pointer to 16-bit array - * @param _arr_ - массив регистров (16-бит). - */ -#define MB_Set_Arr16_Ptr(_arr_) ((uint16_t*)(&(_arr_))) + * @brief Macros to set pointer to 16-bit array + * @param _arr_ - массив регистров (16-бит). + */ +#define MB_Set_Arr16_Ptr(_arr_) ((uint16_t*)(&(_arr_))) /** - * @brief Macros to set pointer to register - * @param _parr_ - массив регистров. - * @param _addr_ - Номер регистра (его индекс) от начала массива _arr_. - */ -#define MB_Set_Register_Ptr(_parr_, _addr_) ((uint16_t *)(_parr_)+(_addr_)) + * @brief Macros to set pointer to register + * @param _parr_ - массив регистров. + * @param _addr_ - Номер регистра (его индекс) от начала массива _arr_. + */ +#define MB_Set_Register_Ptr(_parr_, _addr_) ((uint16_t *)(_parr_)+(_addr_)) /** - * @brief Macros to set pointer to a certain register that contains certain coil - * @param _parr_ - массив коилов. - * @param _coil_ - Номер коила от начала массива _arr_. - * @note Используется вместе с @ref MB_Set_Coil_Mask - @verbatim Пояснение выражений - (_coil_/16) - get index (address shift) of register that contain certain coil - Visual explanation: 30th coil in coils registers array - xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx - |register[0]----| |register[1]----| - |skip this------| |get this-------| - |shift to 14 bit| - @endverbatim - */ -#define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16)) + * @brief Macros to set pointer to a certain register that contains certain coil + * @param _parr_ - массив коилов. + * @param _coil_ - Номер коила от начала массива _arr_. + * @note Используется вместе с @ref MB_Set_Coil_Mask + @verbatim Пояснение выражений + (_coil_/16) - get index (address shift) of register that contain certain coil + Visual explanation: 30th coil in coils registers array + xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx + |register[0]----| |register[1]----| + |skip this------| |get this-------| + |shift to 14 bit| + @endverbatim + */ +#define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16)) /** - * @brief Macros to set mask to a certain bit in coils register - * @param _coil_ - Номер коила от начала массива _arr_. - * @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr - @verbatim Пояснение выражений - (16*(_coil_/16) - how many coils we need to skip. e.g. (16*30/16) - skip 16 coils from first register - _coil_-(16*(_coil_/16)) - shift to certain coil in certain register - e.g. Coil(30) gets in register[1] (30/16 = 1) coil №14 (30 - (16*30/16) = 30 - 16 = 14) - - Visual explanation: 30th coil in coils registers array - xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx - |register[0]----| |register[1]----| - |skip this------| |get this-------| - |shift to 14 bit| - @endverbatim - */ -#define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) )) - + * @brief Macros to set mask to a certain bit in coils register + * @param _coil_ - Номер коила от начала массива _arr_. + * @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr + @verbatim Пояснение выражений + (16*(_coil_/16) - how many coils we need to skip. e.g. (16*30/16) - skip 16 coils from first register + _coil_-(16*(_coil_/16)) - shift to certain coil in certain register + e.g. Coil(30) gets in register[1] (30/16 = 1) coil №14 (30 - (16*30/16) = 30 - 16 = 14) + + Visual explanation: 30th coil in coils registers array + xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx + |register[0]----| |register[1]----| + |skip this------| |get this-------| + |shift to 14 bit| + @endverbatim + */ +#define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) )) + /** - * @brief Read Coil at its local address. - * @param _parr_ - массив коилов. - * @param _coil_ - Номер коила от начала массива _arr_. - * @return uint16_t - Возвращает запрошенный коил на 0м бите. - * - * @details Позволяет обратиться к коилу по адресу относительно _arr_. - */ -#define MB_Read_Coil_Local(_parr_, _coil_) (( *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) & MB_Set_Coil_Mask(_coil_) ) >> (_coil_)) + * @brief Read Coil at its local address. + * @param _parr_ - массив коилов. + * @param _coil_ - Номер коила от начала массива _arr_. + * @return uint16_t - Возвращает запрошенный коил на 0м бите. + * + * @details Позволяет обратиться к коилу по адресу относительно _arr_. + */ +#define MB_Read_Coil_Local(_parr_, _coil_) (( *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) & MB_Set_Coil_Mask(_coil_) ) >> (_coil_)) /** - * @brief Set Coil at its local address. - * @param _parr_ - указатель на массив коилов. - * @param _coil_ - Номер коила от начала массива _arr_. - * - * @details Позволяет обратиться к коилу по адресу относительно _arr_. - */ -#define MB_Set_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) |= MB_Set_Coil_Mask(_coil_) + * @brief Set Coil at its local address. + * @param _parr_ - указатель на массив коилов. + * @param _coil_ - Номер коила от начала массива _arr_. + * + * @details Позволяет обратиться к коилу по адресу относительно _arr_. + */ +#define MB_Set_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) |= MB_Set_Coil_Mask(_coil_) /** - * @brief Reset Coil at its local address. - * @param _parr_ - указатель на массив коилов. - * @param _coil_ - Номер коила от начала массива _arr_. - * - * @details Позволяет обратиться к коилу по адресу относительно _arr_. - */ -#define MB_Reset_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) &= ~(MB_Set_Coil_Mask(_coil_)) + * @brief Reset Coil at its local address. + * @param _parr_ - указатель на массив коилов. + * @param _coil_ - Номер коила от начала массива _arr_. + * + * @details Позволяет обратиться к коилу по адресу относительно _arr_. + */ +#define MB_Reset_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) &= ~(MB_Set_Coil_Mask(_coil_)) /** - * @brief Set Coil at its local address. - * @param _parr_ - указатель на массив коилов. - * @param _coil_ - Номер коила от начала массива _arr_. - * - * @details Позволяет обратиться к коилу по адресу относительно _arr_. - */ -#define MB_Toogle_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ^= MB_Set_Coil_Mask(_coil_) + * @brief Set Coil at its local address. + * @param _parr_ - указатель на массив коилов. + * @param _coil_ - Номер коила от начала массива _arr_. + * + * @details Позволяет обратиться к коилу по адресу относительно _arr_. + */ +#define MB_Toogle_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ^= MB_Set_Coil_Mask(_coil_) + + +/** + * @brief Инициализация объектов + * @details С помозью этого дефайна инициализируются объекты в @ref MB_DeviceInentificationInit + */ +#define MB_ObjectInit(_p_obj_, _userstring_) (_p_obj_)->length = sizeof(_userstring_);\ + (_p_obj_)->name = _userstring_; + /** + * @brief Инициализация пользовательских объектов + * @details С помозью этого дефайна инициализируются пользовательские объекты в MB_DeviceInentificationInit + */ +#define MB_UserObjectInit(_pinfostruct_, _user_numb_) MB_ObjectInit(&(_pinfostruct_)->User[_user_numb_], MODBUS_USEROBJECT##_user_numb_##_NAME) //-------------------------------------------------- //------------------OTHER DEFINES------------------- -#define RegisterType_Holding 0 -#define RegisterType_Input 1 -#define RegisterType_Discrete 2 +#define RegisterType_Holding 0 +#define RegisterType_Input 1 +#define RegisterType_Discrete 2 // create hadnles and settings for uart, tim, rs with _modbus_ name //-------------------------------------------------- #ifndef Divide_Up /** - * @brief Calc dividing including remainder - * @param _val_ - делимое. - * @param _div_ - делитель. - * @details Если результат деления без остатка: он возвращается как есть - Если с остатком - округляется вверх - */ -//#define Divide_Up(_val_, _div_) (((_val_)%(_div_))? (_val_)/(_div_)+1 : (_val_)/_div_) /* через тернарный оператор */ -#define Divide_Up(_val_, _div_) ((_val_ - 1) / _div_) + 1 /* через мат выражение */ + * @brief Calc dividing including remainder + * @param _val_ - делимое. + * @param _div_ - делитель. + * @details Если результат деления без остатка: он возвращается как есть + Если с остатком - округляется вверх + */ +//#define Divide_Up(_val_, _div_) (((_val_)%(_div_))? (_val_)/(_div_)+1 : (_val_)/_div_) /* через тернарный оператор */ +#define Divide_Up(_val_, _div_) ((_val_ - 1) / _div_) + 1 /* через мат выражение */ #endif #ifndef ByteSwap16 /** - * @brief Swap between Little Endian and Big Endian - * @param v - Переменная для свапа. - * @return v (new) - Свапнутая переменная. - * @details Переключения между двумя типами хранения слова: HI-LO байты и LO-HI байты. - */ -#define ByteSwap16(v) (((v&0xFF00) >> (8)) | ((v&0x00FF) << (8))) + * @brief Swap between Little Endian and Big Endian + * @param v - Переменная для свапа. + * @return v (new) - Свапнутая переменная. + * @details Переключения между двумя типами хранения слова: HI-LO байты и LO-HI байты. + */ +#define ByteSwap16(v) (((v&0xFF00) >> (8)) | ((v&0x00FF) << (8))) #endif /** GENERAL_MODBUS_STUFF * @} @@ -292,18 +406,18 @@ typedef enum ///////////////////////////////////////////////////////////////////// /////////////////////////---FUNCTIONS---///////////////////////////// /** - * @addtogroup MODBUS_FUNCTIONS - * @ingroup MODBUS - * @brief Function for controling modbus communication - */ - + * @addtogroup MODBUS_FUNCTIONS + * @ingroup MODBUS + * @brief Function for controling modbus communication + */ + //----------------FUNCTIONS FOR USER---------------- /** - * @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS - * @ingroup MODBUS_FUNCTIONS - * @brief Function for user use - @{ - */ + * @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS + * @ingroup MODBUS_FUNCTIONS + * @brief Function for user use + @{ + */ /* First set up of MODBUS */ void MODBUS_FirstInit(void); /* Set or Reset Coil at its global address */ @@ -314,14 +428,14 @@ uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception); /** MODBUS_DATA_ACCESS_FUNCTIONS * @} */ - + //---------PROCESS MODBUS COMMAND FUNCTIONS--------- /** - * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS - * @ingroup MODBUS_FUNCTIONS - * @brief Function process commands - @{ - */ + * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS + * @ingroup MODBUS_FUNCTIONS + * @brief Function process commands + @{ + */ /* Check is address valid for certain array */ MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB); /* Define Address Origin for Input/Holding Registers */ @@ -329,25 +443,27 @@ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, u /* Define Address Origin for coils */ MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag); /* Proccess command Read Coils (01 - 0x01) */ -uint8_t MB_Read_Coils(RS_MsgTypeDef *modbus_msg); +uint8_t MB_Proccess_Read_Coils(RS_MsgTypeDef *modbus_msg); /* Proccess command Read Holding Registers (03 - 0x03) */ -uint8_t MB_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg); +uint8_t MB_Proccess_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg); /* Proccess command Read Input Registers (04 - 0x04) */ -uint8_t MB_Read_Input_Regs(RS_MsgTypeDef *modbus_msg); -/* Proccess command Write Single Coils (05 - 0x05) */ -uint8_t MB_Write_Single_Coil(RS_MsgTypeDef *modbus_msg); +uint8_t MB_Proccess_Read_Input_Regs(RS_MsgTypeDef *modbus_msg); +/* Proccess command Write Single Coils (05 - 0x05) */ +uint8_t MB_Proccess_Write_Single_Coil(RS_MsgTypeDef *modbus_msg); +/* Proccess command Write Single Coils (06 - 0x06) */ +uint8_t MB_Proccess_Write_Single_Reg(RS_MsgTypeDef *modbus_msg); /* Proccess command Write Multiple Coils (15 - 0x0F) */ uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg); /* Proccess command Write Multiple Register (16 - 0x10) */ -uint8_t MB_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg); +uint8_t MB_Proccess_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg); /** MODBUS_DATA_ACCESS_FUNCTIONS * @} */ /////////////////////////---FUNCTIONS---///////////////////////////// - - - + + + ///////////////////////////////////////////////////////////////////// /////////////////////////---CALC DEFINES---////////////////////////// @@ -356,7 +472,7 @@ uint8_t MB_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg); #ifndef Trace_MB_UART_Enter #define Trace_MB_UART_Enter() #endif //Trace_MB_UART_Enter - + #ifndef Trace_MB_UART_Exit #define Trace_MB_UART_Exit() #endif //Trace_MB_UART_Exit @@ -364,7 +480,7 @@ uint8_t MB_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg); #ifndef Trace_MB_TIM_Enter #define Trace_MB_TIM_Enter() #endif //Trace_MB_TIM_Enter - + #ifndef Trace_MB_TIM_Exit #define Trace_MB_TIM_Exit() #endif //Trace_MB_TIM_Exit diff --git a/Modbus/modbus_config.h b/Modbus/modbus_config.h index 70138cb..1a893ae 100644 --- a/Modbus/modbus_config.h +++ b/Modbus/modbus_config.h @@ -8,8 +8,8 @@ #include "stm32f1xx_hal.h" // MODBUS PARAMS -#define MODBUS_DEVICE_ID 1 ///< девайс текущего устройства -#define MODBUS_TIMEOUT 5000 ///< максимальнйы тайтаут MB в тиках таймера +#define MODBUS_DEVICE_ID 1 ///< девайс текущего устройства +#define MODBUS_TIMEOUT 5000 ///< максимальнйы тайтаут MB в тиках таймера // STRING OBJECTS MODBUS #define MODBUS_VENDOR_NAME "NIO-12" @@ -19,14 +19,15 @@ #define MODBUS_PRODUCT_NAME "" #define MODBUS_MODEL_NAME "STM32F103" #define MODBUS_USER_APPLICATION_NAME "" +#define MODBUS_NUMB_OF_USEROBJECTS 0 // PERIPH FUNCTIONS AND HANDLERS -#define RS_UART_Init MX_USART1_UART_Init //инициализация uart -#define RS_UART_DeInit HAL_UART_MspDeInit //деинициализация uart -#define RS_TIM_Init MX_TIM3_Init //инициализация таймера +#define RS_UART_Init MX_USART1_UART_Init //инициализация uart +#define RS_UART_DeInit HAL_UART_MspDeInit //деинициализация uart +#define RS_TIM_Init MX_TIM3_Init //инициализация таймера #define RS_TIM_DeInit HAL_TIM_Base_MspDeInit//деинициализация таймера -#define rs_huart huart1 //используемый uart -#define rs_htim htim3 //используемый таймера +#define rs_huart huart1 //используемый uart +#define rs_htim htim3 //используемый таймера /** diff --git a/Modbus/modbus_data.h b/Modbus/modbus_data.h index 2f08ce8..df7820d 100644 --- a/Modbus/modbus_data.h +++ b/Modbus/modbus_data.h @@ -29,10 +29,10 @@ При добавлении новых массивов регистров, необходимо их добавить в функцию MB_DefineRegistersAddress - if(MB_Check_Address_For_Arr(Addr, Qnt, R__ADDR, R__QNT) == NO_ERRORS) - { - *pRegs = MB_Set_Register_Ptr(&, Addr); // начало регистров хранения/входных - } + if(MB_Check_Address_For_Arr(Addr, Qnt, R__ADDR, R__QNT) == NO_ERRORS) + { + *pRegs = MB_Set_Register_Ptr(&, Addr); // начало регистров хранения/входных + } @endverbatim * @{ */ @@ -43,7 +43,7 @@ */ typedef struct //MB_DataInRegsTypeDef { - + uint16_t in[16]; }MB_DataInRegsTypeDef; @@ -52,17 +52,17 @@ typedef struct //MB_DataInRegsTypeDef */ typedef struct //MB_DataInRegsTypeDef { - + uint16_t out[16]; }MB_DataHoldRegsTypeDef; // DEFINES FOR INPUT REGISTERS ARRAYS #define R_INPUT_ADDR 0 -#define R_INPUT_QNT 0 +#define R_INPUT_QNT 16 // DEFINES FOR HOLDING REGISTERS ARRAYS #define R_HOLDING_ADDR 0 -#define R_HOLDING_QNT 0 +#define R_HOLDING_QNT 16 /** MODBUS_DATA_RERISTERS_DEFINES @@ -128,32 +128,6 @@ typedef struct // tester modbus data extern MB_DataStructureTypeDef MB_DATA; -/** - * @brief Структура для объекта Modbus - * @ingroup MODBUS_DATA - */ -typedef struct -{ - unsigned length; - char *name; -}MB_DeviceObjectTypeDef; -/** - * @brief Структура для объектов Modbus - * @ingroup MODBUS_DATA - */ -typedef struct -{ - MB_DeviceObjectTypeDef VendorName; - MB_DeviceObjectTypeDef ProductCode; - MB_DeviceObjectTypeDef Revision; - MB_DeviceObjectTypeDef VendorUrl; - MB_DeviceObjectTypeDef ProductName; - MB_DeviceObjectTypeDef ModelName; - MB_DeviceObjectTypeDef UserApplicationName; -}MB_DeviceIdentificationTypeDef; -void MB_DevoceInentificationInit(void); - - #endif //_MODBUS_DATA_H_ ///////////////////////////////////////////////////////////// diff --git a/Modbus/rs_message.c b/Modbus/rs_message.c index 9fbeb14..aac739c 100644 --- a/Modbus/rs_message.c +++ b/Modbus/rs_message.c @@ -27,27 +27,27 @@ @verbatim //-------------------Функции-------------------// Functions: users - - RS_Parse_Message/RS_Collect_Message Заполнение структуры сообщения и буфера - - RS_Response Ответ на сообщение - - RS_Define_Size_of_RX_Message Определение размера принимаемых данных + - RS_Parse_Message/RS_Collect_Message Заполнение структуры сообщения и буфера + - RS_Response Ответ на сообщение + - RS_Define_Size_of_RX_Message Определение размера принимаемых данных Functions: general - - RS_Receive_IT Ожидание комманды и ответ на неё - - RS_Transmit_IT Отправление комманды и ожидание ответа - - RS_Init Инициализация переферии и структуры для RS - - RS_ReInit_UART Реинициализация UART для RS - - RS_Abort Отмена приема/передачи по ЮАРТ - - RS_Init Инициализация периферии и modbus handler + - RS_Receive_IT Ожидание комманды и ответ на неё + - RS_Transmit_IT Отправление комманды и ожидание ответа + - RS_Init Инициализация переферии и структуры для RS + - RS_ReInit_UART Реинициализация UART для RS + - RS_Abort Отмена приема/передачи по ЮАРТ + - RS_Init Инициализация периферии и modbus handler Functions: callback/handler - - RS_Handle_Receive_Start Функция для запуска приема или остановки RS - - RS_Handle_Transmit_Start Функция для запуска передачи или остановки RS + - RS_Handle_Receive_Start Функция для запуска приема или остановки RS + - RS_Handle_Transmit_Start Функция для запуска передачи или остановки RS - - RS_UART_RxCpltCallback Коллбек при окончании приема или передачи - RS_UART_TxCpltCallback + - RS_UART_RxCpltCallback Коллбек при окончании приема или передачи + RS_UART_TxCpltCallback - - RS_UART_Handler Обработчик прерывания для UART - - RS_TIM_Handler Обработчик прерывания для TIM + - RS_UART_Handler Обработчик прерывания для UART + - RS_TIM_Handler Обработчик прерывания для TIM @endverbatim *************************************************************************/ @@ -63,213 +63,218 @@ extern void RS_TIM_DeInit(TIM_HandleTypeDef *htim); //------------------------------------------------------------------- //-------------------------GENERAL FUNCTIONS------------------------- /** - * @brief Start receive IT. - * @param hRS - указатель на хендлер RS. - * @param RS_msg - указатель на структуру сообщения. - * @return RS_RES - статус о состоянии RS после инициализации приема. - */ + * @brief Start receive IT. + * @param hRS - указатель на хендлер RS. + * @param RS_msg - указатель на структуру сообщения. + * @return RS_RES - статус о состоянии RS после инициализации приема. + */ RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { - RS_StatusTypeDef RS_RES = 0; - HAL_StatusTypeDef uart_res = 0; - - //-------------CHECK RS LINE---------------- - // check that receive isnt busy - if( RS_Is_RX_Busy(hRS) ) // if tx busy - return busy status - return RS_BUSY; - - //-----------INITIALIZE RECEIVE------------- - // if all OK: start receiving - RS_EnableReceive(); - RS_Set_Busy(hRS); // set RS busy - RS_Set_RX_Flags(hRS); // initialize flags for receive - hRS->pMessagePtr = RS_msg; // set pointer to message structire for filling it from UARTHandler fucntions - - // start receiving - uart_res = HAL_UART_Receive_IT(hRS->huart, hRS->pBufferPtr, RX_FIRST_PART_SIZE); // receive until ByteCnt+1 byte, - // then in Callback restart receive for rest bytes - - // if receive isnt started - abort RS - if(uart_res != HAL_OK) - { - RS_RES = RS_Abort(hRS, ABORT_RS); - printf_rs_err("\n%d: Error RS: Failed to start RS receiving...", uwTick); - } - else + RS_StatusTypeDef RS_RES = 0; + HAL_StatusTypeDef uart_res = 0; + + //-------------CHECK RS LINE---------------- + // check that receive isnt busy + if( RS_Is_RX_Busy(hRS) ) // if tx busy - return busy status + return RS_BUSY; + + //-----------INITIALIZE RECEIVE------------- + // if all OK: start receiving + RS_EnableReceive(); + RS_Set_Busy(hRS); // set RS busy + RS_Set_RX_Flags(hRS); // initialize flags for receive + hRS->pMessagePtr = RS_msg; // set pointer to message structire for filling it from UARTHandler fucntions + + // start receiving + __HAL_UART_ENABLE_IT(hRS->huart, UART_IT_IDLE); + uart_res = HAL_UART_Receive_IT(hRS->huart, hRS->pBufferPtr, MSG_SIZE_MAX); // receive until ByteCnt+1 byte, + // then in Callback restart receive for rest bytes + + // if receive isnt started - abort RS + if(uart_res != HAL_OK) { - RS_RES = RS_OK; - printf_rs("\n%d: RS: Start Receiving...", uwTick); + RS_RES = RS_Abort(hRS, ABORT_RS); + printf_rs_err("Failed to start RS receiving..."); + TrackerCnt_Err(hRS->rs_err); } - - hRS->RS_STATUS = RS_RES; - return RS_RES; // returns result of receive init + else + { + RS_RES = RS_OK; + printf_rs("Start Receiving..."); + TrackerCnt_Ok(hRS->rs_err); + } + + hRS->RS_STATUS = RS_RES; + return RS_RES; // returns result of receive init } /** - * @brief Start transmit IT. - * @param hRS - указатель на хендлер RS. - * @param RS_msg - указатель на структуру сообщения. - * @return RS_RES - статус о состоянии RS после инициализации передачи. - */ + * @brief Start transmit IT. + * @param hRS - указатель на хендлер RS. + * @param RS_msg - указатель на структуру сообщения. + * @return RS_RES - статус о состоянии RS после инициализации передачи. + */ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) -{ - RS_StatusTypeDef RS_RES = 0; - HAL_StatusTypeDef uart_res = 0; - - //-------------CHECK RS LINE---------------- - // check that transmit isnt busy - if( RS_Is_TX_Busy(hRS) ) // if tx busy - return busy status - return RS_BUSY; - // check receive line +{ + RS_StatusTypeDef RS_RES = 0; + HAL_StatusTypeDef uart_res = 0; + + //-------------CHECK RS LINE---------------- + // check that transmit isnt busy + if( RS_Is_TX_Busy(hRS) ) // if tx busy - return busy status + return RS_BUSY; + // check receive line - - //------------COLLECT MESSAGE--------------- - RS_RES = RS_Collect_Message(hRS, RS_msg, hRS->pBufferPtr); - if (RS_RES != RS_OK) // if message isnt collect - stop RS and return error in RS_RES - {// need collect message status, so doesnt write abort to RS_RES - RS_Abort(hRS, ABORT_RS); - RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); // restart receive - } - else // if collect successful - { - - //----------INITIALIZE TRANSMIT------------- + + //------------COLLECT MESSAGE--------------- + RS_RES = RS_Collect_Message(hRS, RS_msg, hRS->pBufferPtr); + if (RS_RES != RS_OK) // if message isnt collect - stop RS and return error in RS_RES + {// need collect message status, so doesnt write abort to RS_RES + RS_Abort(hRS, ABORT_RS); + RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); // restart receive + } + else // if collect successful + { + + //----------INITIALIZE TRANSMIT------------- RS_EnableTransmit(); // for(int i = 0; i < hRS->sRS_Timeout; i++); - RS_Set_Busy(hRS); // set RS busy - RS_Set_TX_Flags(hRS); // initialize flags for transmit IT - hRS->pMessagePtr = RS_msg; // set pointer for filling given structure from UARTHandler fucntion + RS_Set_Busy(hRS); // set RS busy + RS_Set_TX_Flags(hRS); // initialize flags for transmit IT + hRS->pMessagePtr = RS_msg; // set pointer for filling given structure from UARTHandler fucntion - // if all OK: start transmitting - uart_res = HAL_UART_Transmit_IT(hRS->huart, hRS->pBufferPtr, hRS->RS_Message_Size); - // if transmit isnt started - abort RS - if(uart_res != HAL_OK) - { - RS_RES = RS_Abort(hRS, ABORT_RS); - printf_rs_err("\n%d: Error RS: Failed to start RS transmitting...", uwTick); + // if all OK: start transmitting + uart_res = HAL_UART_Transmit_IT(hRS->huart, hRS->pBufferPtr, hRS->RS_Message_Size); + // if transmit isnt started - abort RS + if(uart_res != HAL_OK) + { + RS_RES = RS_Abort(hRS, ABORT_RS); + printf_rs_err("Failed to start RS transmitting..."); + TrackerCnt_Err(hRS->rs_err); } else { RS_RES = RS_OK; - printf_rs("\n%d: RS: Start Transmitting...", uwTick); + printf_rs("Start Transmitting..."); + TrackerCnt_Ok(hRS->rs_err); } } - - - hRS->RS_STATUS = RS_RES; - return RS_RES; // returns result of transmit init + + + hRS->RS_STATUS = RS_RES; + return RS_RES; // returns result of transmit init } /** - * @brief Initialize UART and handle RS stucture. - * @param hRS - указатель на хендлер RS. - * @param suart - указатель на структуру с настройками UART. - * @param stim - указатель на структуру с настройками таймера. - * @param pRS_BufferPtr - указатель на буффер для приема-передачи по UART. Если он NULL, то поставиться библиотечный буфер. - * @return RS_RES - статус о состоянии RS после инициализации. - * @note Инициализация перефирии и структуры для приема-передачи по RS. - */ + * @brief Initialize UART and handle RS stucture. + * @param hRS - указатель на хендлер RS. + * @param suart - указатель на структуру с настройками UART. + * @param stim - указатель на структуру с настройками таймера. + * @param pRS_BufferPtr - указатель на буффер для приема-передачи по UART. Если он NULL, то поставиться библиотечный буфер. + * @return RS_RES - статус о состоянии RS после инициализации. + * @note Инициализация перефирии и структуры для приема-передачи по RS. + */ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr) { - // check that hRS is defined - if (hRS == NULL) - return RS_ERR; - // check that huart is defined - if (huart == NULL) - return RS_ERR; - // init uart + // check that hRS is defined + if (hRS == NULL) + return RS_ERR; + // check that huart is defined + if (huart == NULL) + return RS_ERR; + // init uart -// RS_UART_Init(); - hRS->huart = huart; - -// RS_TIM_Init(); - hRS->htim = htim; - - if (hRS->sRS_RX_Size_Mode == NULL) - return RS_ERR; - - // check that buffer is defined - if (hRS->pBufferPtr == NULL) - { - hRS->pBufferPtr = RS_Buffer; // if no - set default - } - else - hRS->pBufferPtr = pRS_BufferPtr; // if yes - set by user - - return RS_OK; +// RS_UART_Init(); + hRS->huart = huart; + +// RS_TIM_Init(); + hRS->htim = htim; + + if (hRS->sRS_RX_Size_Mode == NULL) + return RS_ERR; + + // check that buffer is defined + if (hRS->pBufferPtr == NULL) + { + hRS->pBufferPtr = RS_Buffer; // if no - set default + } + else + hRS->pBufferPtr = pRS_BufferPtr; // if yes - set by user + + return RS_OK; } /** - * @brief ReInitialize UART and RS receive. - * @param hRS - указатель на хендлер RS. - * @param suart - указатель на структуру с настройками UART. - * @return RS_RES - статус о состоянии RS после инициализации. - * @note Реинициализация UART и приема по RS. - */ + * @brief ReInitialize UART and RS receive. + * @param hRS - указатель на хендлер RS. + * @param suart - указатель на структуру с настройками UART. + * @return RS_RES - статус о состоянии RS после инициализации. + * @note Реинициализация UART и приема по RS. + */ HAL_StatusTypeDef RS_ReInit_UART(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart) { - HAL_StatusTypeDef RS_RES; - hRS->f.ReInit_UART = 0; - -// // check is settings are valid -// if(Check_UART_Init_Struct(suart) != HAL_OK) -// return HAL_ERROR; + HAL_StatusTypeDef RS_RES; + hRS->f.ReInit_UART = 0; - RS_Abort(hRS, ABORT_RS); +// // check is settings are valid +// if(Check_UART_Init_Struct(suart) != HAL_OK) +// return HAL_ERROR; - RS_UART_DeInit(huart); + RS_Abort(hRS, ABORT_RS); + + RS_UART_DeInit(huart); RS_UART_Init(); - - - RS_Receive_IT(hRS, hRS->pMessagePtr); - return RS_RES; + + + RS_Receive_IT(hRS, hRS->pMessagePtr); + return RS_RES; } /** - * @brief Abort RS/UART. - * @param hRS - указатель на хендлер RS. - * @param AbortMode - выбор, что надо отменить. - - ABORT_TX: Отмена передачи по ЮАРТ, с очищением флагов TX, - - ABORT_RX: Отмена приема по ЮАРТ, с очищением флагов RX, - - ABORT_RX_TX: Отмена приема и передачи по ЮАРТ, - - ABORT_RS: Отмена приема-передачи RS, с очищением всей структуры. - * @return RS_RES - статус о состоянии RS после аборта. - * @note Отмена работы UART в целом или отмена приема/передачи RS. - Также очищается хендл hRS. - */ + * @brief Abort RS/UART. + * @param hRS - указатель на хендлер RS. + * @param AbortMode - выбор, что надо отменить. + - ABORT_TX: Отмена передачи по ЮАРТ, с очищением флагов TX, + - ABORT_RX: Отмена приема по ЮАРТ, с очищением флагов RX, + - ABORT_RX_TX: Отмена приема и передачи по ЮАРТ, + - ABORT_RS: Отмена приема-передачи RS, с очищением всей структуры. + * @return RS_RES - статус о состоянии RS после аборта. + * @note Отмена работы UART в целом или отмена приема/передачи RS. + Также очищается хендл hRS. + */ RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode) { - HAL_StatusTypeDef uart_res = 0; + HAL_StatusTypeDef uart_res = 0; + + if(hRS->sRS_Timeout) // if timeout setted + HAL_TIM_Base_Stop_IT(hRS->htim); // stop timeout hRS->htim->Instance->CNT = 0; __HAL_TIM_CLEAR_IT(hRS->htim, TIM_IT_UPDATE); - - if(hRS->sRS_Timeout) // if timeout setted - HAL_TIM_Base_Stop_IT(hRS->htim); // stop timeout - - if((AbortMode&ABORT_RS) == 0x00) - { - if((AbortMode&ABORT_RX) == ABORT_RX) - { - uart_res = HAL_UART_AbortReceive(hRS->huart); // abort receive - RS_Reset_RX_Flags(hRS); - } - - if((AbortMode&ABORT_TX) == ABORT_TX) - { - uart_res = HAL_UART_AbortTransmit(hRS->huart); // abort transmit - RS_Reset_TX_Flags(hRS); - } - } - else - { - uart_res = HAL_UART_Abort(hRS->huart); - RS_Clear_All(hRS); - } - hRS->RS_STATUS = RS_ABORTED; - return RS_ABORTED; + + if((AbortMode&ABORT_RS) == 0x00) + { + if((AbortMode&ABORT_RX) == ABORT_RX) + { + uart_res = HAL_UART_AbortReceive(hRS->huart); // abort receive + RS_Reset_RX_Flags(hRS); + } + + if((AbortMode&ABORT_TX) == ABORT_TX) + { + uart_res = HAL_UART_AbortTransmit(hRS->huart); // abort transmit + RS_Reset_TX_Flags(hRS); + } + } + else + { + uart_res = HAL_UART_Abort(hRS->huart); + RS_Clear_All(hRS); + } + hRS->RS_STATUS = RS_ABORTED; + return RS_ABORTED; } @@ -281,210 +286,286 @@ RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode) //------------------------------------------------------------------- //--------------------CALLBACK/HANDLER FUNCTIONS--------------------- /** - * @brief Handle for starting receive. - * @param hRS - указатель на хендлер RS. - * @param RS_msg - указатель на структуру сообщения. - * @return RS_RES - статус о состоянии RS после инициализации приема или окончания общения. - * @note Определяет начинать прием команды/ответа или нет. - */ + * @brief Handle for starting receive. + * @param hRS - указатель на хендлер RS. + * @param RS_msg - указатель на структуру сообщения. + * @return RS_RES - статус о состоянии RS после инициализации приема или окончания общения. + * @note Определяет начинать прием команды/ответа или нет. + */ RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) -{ - RS_StatusTypeDef RS_RES = 0; - - switch(hRS->sRS_Mode) - { - case SLAVE_ALWAYS_WAIT: // in slave mode with permanent waiting - RS_RES = RS_Receive_IT(hRS, RS_msg); break; // start receiving again - case SLAVE_TIMEOUT_WAIT: // in slave mode with timeout waiting (start receiving cmd by request) - RS_Set_Free(hRS); RS_RES = RS_OK; break; // end RS communication (set RS unbusy) - } +{ + RS_StatusTypeDef RS_RES = 0; + + switch(hRS->sRS_Mode) + { + case SLAVE_ALWAYS_WAIT: // in slave mode with permanent waiting + RS_RES = RS_Receive_IT(hRS, RS_msg); break; // start receiving again + case SLAVE_TIMEOUT_WAIT: // in slave mode with timeout waiting (start receiving cmd by request) + RS_Set_Free(hRS); RS_RES = RS_OK; break; // end RS communication (set RS unbusy) + } if(RS_RES != RS_OK) { + TrackerCnt_Err(hRS->rs_err); } - - return RS_RES; + + return RS_RES; } /** - * @brief Handle for starting transmit. - * @param hRS - указатель на хендлер RS. - * @param RS_msg - указатель на структуру сообщения. - * @return RS_RES - статус о состоянии RS после инициализации передачи. - * @note Определяет отвечать ли на команду или нет. - */ + * @brief Handle for starting transmit. + * @param hRS - указатель на хендлер RS. + * @param RS_msg - указатель на структуру сообщения. + * @return RS_RES - статус о состоянии RS после инициализации передачи. + * @note Определяет отвечать ли на команду или нет. + */ RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) -{ - RS_StatusTypeDef RS_RES = 0; - - switch(hRS->sRS_Mode) - { - case SLAVE_ALWAYS_WAIT: // in slave mode always response - case SLAVE_TIMEOUT_WAIT: // transmit response - RS_RES = RS_Transmit_IT(hRS, RS_msg); break; - } +{ + RS_StatusTypeDef RS_RES = 0; + + switch(hRS->sRS_Mode) + { + case SLAVE_ALWAYS_WAIT: // in slave mode always response + case SLAVE_TIMEOUT_WAIT: // transmit response + RS_RES = RS_Transmit_IT(hRS, RS_msg); break; + } if(RS_RES != RS_OK) { + TrackerCnt_Err(hRS->rs_err); } - return RS_RES; + return RS_RES; } /** - * @brief UART RX Callback: define behaviour after receiving parts of message. - * @param hRS - указатель на хендлер RS. - * @return RS_RES - статус о состоянии RS после обработки приема. - * @note Контролирует прием сообщения: определяет размер принимаемой посылки и обрабатывает его. - */ + * @brief UART RX Callback: define behaviour after receiving parts of message. + * @param hRS - указатель на хендлер RS. + * @return RS_RES - статус о состоянии RS после обработки приема. + * @note Контролирует прием сообщения: определяет размер принимаемой посылки и обрабатывает его. + */ RS_StatusTypeDef RS_UART_RxCpltCallback(RS_HandleTypeDef *hRS) { - RS_StatusTypeDef RS_RES = 0; - HAL_StatusTypeDef uart_res = 0; - - // if we had received bytes before ByteCnt - if((hRS->sRS_RX_Size_Mode == RS_RX_Size_NotConst) && (hRS->f.RX_Half == 0)) // if data size isnt constant and its first half, and - { // First receive part of message, then define size of rest of message, and start receive it - hRS->f.RX_Half = 1; - //---------------FIND DATA SIZE----------------- - uint32_t NuRS_of_Rest_Bytes = 0xFFFF; - RS_RES = RS_Define_Size_of_RX_Message(hRS, &NuRS_of_Rest_Bytes); - - - // if we need to skip this message - restart receive - if(RS_RES == RS_SKIP || NuRS_of_Rest_Bytes == 0xFFFF) - { - RS_Abort(hRS, ABORT_RX); - RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); - return RS_RES; - } + RS_StatusTypeDef RS_RES = 0; + HAL_StatusTypeDef uart_res = 0; + int flag_to_response = 0; + + // if we had received bytes before ByteCnt + if((hRS->sRS_RX_Size_Mode == RS_RX_Size_NotConst) && (hRS->f.RX_Half == 0)) // if data size isnt constant and its first half, and + { // First receive part of message, then define size of rest of message, and start receive it + hRS->f.RX_Half = 1; + //---------------FIND DATA SIZE----------------- + uint32_t NuRS_of_Rest_Bytes = 0xFFFF; + RS_RES = RS_Define_Size_of_RX_Message(hRS, &NuRS_of_Rest_Bytes); - // if there is no bytes to receive - if(NuRS_of_Rest_Bytes == 0) - { - hRS->f.RX_Half = 0; - //---------PROCESS DATA & ENDING RECEIVING-------- - RS_Set_RX_End(hRS); - - if(hRS->sRS_Timeout) // if timeout setted - HAL_TIM_Base_Stop_IT(hRS->htim); // stop timeout - - // parse received data - RS_RES = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr); // parse message - - // RESPONSE - RS_RES = RS_Response(hRS, hRS->pMessagePtr); + + // if we need to skip this message - restart receive + if(RS_RES == RS_SKIP || NuRS_of_Rest_Bytes == 0xFFFF) + { + RS_Abort(hRS, ABORT_RX); + RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); return RS_RES; } - - //-------------START UART RECEIVE--------------- - uart_res = HAL_UART_Receive_IT(hRS->huart, (hRS->pBufferPtr + RX_FIRST_PART_SIZE), NuRS_of_Rest_Bytes); - - if(uart_res != HAL_OK) - {// need uart status, so doesnt write abort to RS_RES - RS_RES = RS_Abort(hRS, ABORT_RS); - } - else - RS_RES = RS_OK; - } - else // if we had received whole message - { - hRS->f.RX_Half = 0; - - //---------PROCESS DATA & ENDING RECEIVING-------- - RS_Set_RX_End(hRS); - - if(hRS->sRS_Timeout) // if timeout setted - HAL_TIM_Base_Stop_IT(hRS->htim); // stop timeout - - // parse received data - RS_RES = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr); // parse message + // if there is no bytes to receive + if(NuRS_of_Rest_Bytes != 0) + { + //-------------START UART RECEIVE--------------- + uart_res = HAL_UART_Receive_IT(hRS->huart, (hRS->pBufferPtr + RX_FIRST_PART_SIZE), NuRS_of_Rest_Bytes); - // RESPONSE - RS_RES = RS_Response(hRS, hRS->pMessagePtr); + if(uart_res != HAL_OK) + {// need uart status, so doesnt write abort to RS_RES + TrackerCnt_Err(hRS->rs_err); + RS_RES = RS_Abort(hRS, ABORT_RS); + } + else + RS_RES = RS_OK; + } + else + { + hRS->f.RX_Half = 0; + flag_to_response = 1; + } + } + else // if we had received whole message + { + hRS->f.RX_Half = 0; + flag_to_response = 1; } - return RS_RES; + + if(flag_to_response) + { + //---------PROCESS DATA & ENDING RECEIVING-------- + RS_Set_RX_End(hRS); + + if(hRS->sRS_Timeout) // if timeout setted + HAL_TIM_Base_Stop_IT(hRS->htim); // stop timeout + + // parse received data + RS_RES = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr); // parse message + + // RESPONSE + if(RS_RES != RS_SKIP) // if message not for us + { + hRS->lastPacketTick = uwTick; + RS_RES = RS_Response(hRS, hRS->pMessagePtr); + } + else + { + RS_Abort(hRS, ABORT_RX); + RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); + } + } + + return RS_RES; } /** - * @brief UART TX Callback: define behaviour after transmiting message. - * @param hRS - указатель на хендлер RS. - * @return RS_RES - статус о состоянии RS после обработки приема. - * @note Определяет поведение RS после передачи сообщения. - */ + * @brief UART TX Callback: define behaviour after transmiting message. + * @param hRS - указатель на хендлер RS. + * @return RS_RES - статус о состоянии RS после обработки приема. + * @note Определяет поведение RS после передачи сообщения. + */ RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS) { - RS_StatusTypeDef RS_RES = RS_OK; - HAL_StatusTypeDef uart_res = 0; - - //--------------ENDING TRANSMITTING------------- - RS_Set_TX_End(hRS); - RS_EnableReceive(); + RS_StatusTypeDef RS_RES = RS_OK; + HAL_StatusTypeDef uart_res = 0; + + //--------------ENDING TRANSMITTING------------- + RS_Set_TX_End(hRS); + RS_EnableReceive(); // for(int i = 0; i < hRS->sRS_Timeout; i++); - - //-----------START RECEIVING or END RS---------- - RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); - - return RS_RES; + + //-----------START RECEIVING or END RS---------- + RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); + + return RS_RES; } /** - * @brief Handler for UART. - * @param hRS - указатель на хендлер RS. - * @note Обрабатывает ошибки если есть и вызывает RS Коллбеки. - * Добавить вызов этой функции в UARTx_IRQHandler() после HAL_UART_IRQHandler(). - */ + * @brief Handler for UART. + * @param hRS - указатель на хендлер RS. + * @note Обрабатывает ошибки если есть и вызывает RS Коллбеки. + * Добавить вызов этой функции в UARTx_IRQHandler() после HAL_UART_IRQHandler(). + */ void RS_UART_Handler(RS_HandleTypeDef *hRS) { - //-------------CALL RS CALLBACKS------------ - /* IF NO ERROR OCCURS */ - if(hRS->huart->ErrorCode == 0) - { - hRS->htim->Instance->CNT = 0; // reset cnt; - /* Start timeout */ - if(hRS->sRS_Timeout) // if timeout setted - if((hRS->huart->RxXferCount+1 == hRS->huart->RxXferSize) && RS_Is_RX_Busy(hRS)) // if first byte is received and receive is active + //-------------CHECK IDLE FLAG FIRST------------- + /* Проверяем флаг IDLE в первую очередь - это гарантирует обработку только после idle */ + if(__HAL_UART_GET_FLAG(hRS->huart, UART_FLAG_IDLE) && __HAL_UART_GET_IT_SOURCE(hRS->huart, UART_IT_IDLE)) + { + __HAL_UART_CLEAR_IDLEFLAG(hRS->huart); // Важно: очистить флаг IDLE + + // Если прием активен и мы получили IDLE - это конец фрейма + if(RS_Is_RX_Busy(hRS) && hRS->f.RX_Ongoing) + { + // Останавливаем таймаут + if(hRS->sRS_Timeout) + HAL_TIM_Base_Stop_IT(hRS->htim); + + // Получаем количество фактически принятых байтов + uint16_t received_bytes = hRS->huart->RxXferSize - hRS->huart->RxXferCount; + + if(received_bytes > 0) { - hRS->htim->Instance->ARR = hRS->sRS_Timeout; // reset cnt; - HAL_TIM_Base_Start_IT(hRS->htim); + // Принудительно завершаем прием (IDLE прервал наш прием) + RS_Abort(hRS, ABORT_RX); + + // Устанавливаем фактический размер данных + hRS->RS_Message_Size = received_bytes; + + // Завершаем прием в нашей структуре + RS_Set_RX_End(hRS); + + // Проверяем адрес Modbus перед обработкой + if(hRS->pBufferPtr[0] != hRS->ID) + { + // Чужое сообщение - игнорируем и начинаем новый прием + RS_Abort(hRS, ABORT_RX); + RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); + return; + } + + // Парсим наше сообщение + RS_StatusTypeDef parse_res = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr); + + // RESPONSE + if(parse_res != RS_SKIP) + { + hRS->lastPacketTick = uwTick; + RS_Response(hRS, hRS->pMessagePtr); + } + else + { + RS_Abort(hRS, ABORT_RX); + RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); + } + } + else + { + // IDLE без данных - просто перезапускаем прием + RS_Abort(hRS, ABORT_RX); + RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); + } + } + return; // Выходим после обработки IDLE + } + + //-------------STANDARD UART HANDLING------------- + HAL_UART_IRQHandler(hRS->huart); + + //-------------CALL RS CALLBACKS------------ + /* IF NO ERROR OCCURS */ + if(hRS->huart->ErrorCode == 0) + { + hRS->htim->Instance->CNT = 0; // reset cnt; + + /* Start timeout при получении первого байта */ + if(hRS->sRS_Timeout) // if timeout setted + if((hRS->huart->RxXferCount+1 == hRS->huart->RxXferSize) && RS_Is_RX_Busy(hRS)) // if first byte is received and receive is active + { + HAL_TIM_Base_Start_IT(hRS->htim); RS_Set_RX_Active_Flags(hRS); } - - /* RX Callback */ - if (( hRS->huart->RxXferCount == 0U) && RS_Is_RX_Busy(hRS) && // if all bytes are received and receive is active - hRS->huart->RxState != HAL_UART_STATE_BUSY_RX) // also check that receive "REALLY" isnt busy - RS_UART_RxCpltCallback(hRS); - - /* TX Callback */ - if (( hRS->huart->TxXferCount == 0U) && RS_Is_TX_Busy(hRS) && // if all bytes are transmited and transmit is active - hRS->huart->gState != HAL_UART_STATE_BUSY_TX) // also check that receive "REALLY" isnt busy - RS_UART_TxCpltCallback(hRS); - } - //----------------ERRORS HANDLER---------------- - else - { - /* de-init uart transfer */ - RS_Abort(hRS, ABORT_RS); - RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); - // later, maybe, will be added specific handlers for err - } + + /* RX Callback - теперь НЕ вызываем здесь, ждем IDLE */ + + /* TX Callback - оставляем без изменений */ + if ((hRS->huart->TxXferCount == 0U) && RS_Is_TX_Busy(hRS) && // if all bytes are transmited and transmit is active + hRS->huart->gState != HAL_UART_STATE_BUSY_TX) // also check that receive "REALLY" isnt busy + RS_UART_TxCpltCallback(hRS); + + /* NOTE: RX Callback больше не вызывается здесь - ждем IDLE для гарантии конца фрейма */ + } + //----------------ERRORS HANDLER---------------- + else + { + //TrackerCnt_Err(hRS->rs_err); + /* de-init uart transfer */ + RS_Abort(hRS, ABORT_RS); + RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); + + // later, maybe, will be added specific handlers for err + } } /** - * @brief Handler for TIM. - * @param hRS - указатель на хендлер RS. - * @note Попадание сюда = таймаут и перезапуск RS приема - * Добавить вызов этой функции в TIMx_IRQHandler() после HAL_TIM_IRQHandler(). - */ + * @brief Handler for TIM. + * @param hRS - указатель на хендлер RS. + * @note Попадание сюда = таймаут и перезапуск RS приема + * Добавить вызов этой функции в TIMx_IRQHandler() после HAL_TIM_IRQHandler(). + */ void RS_TIM_Handler(RS_HandleTypeDef *hRS) { + HAL_TIM_IRQHandler(hRS->htim); + HAL_TIM_Base_Stop_IT(hRS->htim); - RS_Abort(hRS, ABORT_RS); - - RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); + RS_Abort(hRS, ABORT_RS); + if(hRS->pMessagePtr->MbAddr == hRS->ID) // ошибка если таймаут по нашему сообщению + TrackerCnt_Err(hRS->rs_err); + RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); } //--------------------CALLBACK/HANDLER FUNCTIONS--------------------- //------------------------------------------------------------------- @@ -494,57 +575,57 @@ void RS_TIM_Handler(RS_HandleTypeDef *hRS) //------------------------------------------------------------------- //--------------WEAK PROTOTYPES FOR PROCESSING MESSAGE--------------- /** - * @brief Respond accord to received message. - * @param hRS - указатель на хендлер RS. - * @param RS_msg - указатель на структуру сообщения. - * @return RS_RES - статус о результате ответа на комманду. - * @note Обработка принятой комманды и ответ на неё. - */ + * @brief Respond accord to received message. + * @param hRS - указатель на хендлер RS. + * @param RS_msg - указатель на структуру сообщения. + * @return RS_RES - статус о результате ответа на комманду. + * @note Обработка принятой комманды и ответ на неё. + */ __weak RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { - /* Redefine function for user purposes */ - return RS_ERR; + /* Redefine function for user purposes */ + return RS_ERR; } /** - * @brief Collect message in buffer to transmit it. - * @param hRS - указатель на хендлер RS. - * @param RS_msg - указатель на структуру сообщения. - * @param msg_uart_buff - указатель на буффер UART. - * @return RS_RES - статус о результате заполнения буфера. - * @note Заполнение буффера UART из структуры сообщения. - */ + * @brief Collect message in buffer to transmit it. + * @param hRS - указатель на хендлер RS. + * @param RS_msg - указатель на структуру сообщения. + * @param msg_uart_buff - указатель на буффер UART. + * @return RS_RES - статус о результате заполнения буфера. + * @note Заполнение буффера UART из структуры сообщения. + */ __weak RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff) { - /* Redefine function for user purposes */ - return RS_ERR; + /* Redefine function for user purposes */ + return RS_ERR; } /** - * @brief Parse message from buffer to process it. - * @param hRS - указатель на хендлер RS. - * @param RS_msg - указатель на структуру сообщения. - * @param msg_uart_buff - указатель на буффер UART. - * @return RS_RES - статус о результате заполнения структуры. - * @note Заполнение структуры сообщения из буффера UART. - */ + * @brief Parse message from buffer to process it. + * @param hRS - указатель на хендлер RS. + * @param RS_msg - указатель на структуру сообщения. + * @param msg_uart_buff - указатель на буффер UART. + * @return RS_RES - статус о результате заполнения структуры. + * @note Заполнение структуры сообщения из буффера UART. + */ __weak RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff) { - /* Redefine function for user purposes */ - return RS_ERR; + /* Redefine function for user purposes */ + return RS_ERR; } /** - * @brief Define size of RX Message that need to be received. - * @param hRS - указатель на хендлер RS. - * @param rx_data_size - указатель на переменную для записи кол-ва байт для принятия. - * @return RS_RES - статус о корректности рассчета кол-ва байт для принятия. - * @note Определение сколько байтов надо принять по протоколу. - */ + * @brief Define size of RX Message that need to be received. + * @param hRS - указатель на хендлер RS. + * @param rx_data_size - указатель на переменную для записи кол-ва байт для принятия. + * @return RS_RES - статус о корректности рассчета кол-ва байт для принятия. + * @note Определение сколько байтов надо принять по протоколу. + */ __weak RS_StatusTypeDef RS_Define_Size_of_RX_Message(RS_HandleTypeDef *hRS, uint32_t *rx_data_size) { - /* Redefine function for user purposes */ - return RS_ERR; + /* Redefine function for user purposes */ + return RS_ERR; } //--------------WEAK PROTOTYPES FOR PROCESSING MESSAGE--------------- //------------------------------------------------------------------- diff --git a/Modbus/rs_message.h b/Modbus/rs_message.h index 8131a52..62f0323 100644 --- a/Modbus/rs_message.h +++ b/Modbus/rs_message.h @@ -4,7 +4,7 @@ * @brief Заголовочный файл для модуля реализации протоколов по RS/UART. ************************************************************************** * @defgroup RS_TOOLS -* @brief Всякое для работы по UART/RS +* @brief Всякое для работы по UART/RS ************************************************************************** @details ************************************************************************** @@ -12,9 +12,9 @@ - Определить структуру сообщения RS_MsgTypeDef и дефайны RX_FIRST_PART_SIZE и MSG_SIZE_MAX. - Подключить этот файл в раздел rs_message.h. - - Определить функции для обработки сообщения: RS_Parse_Message(), + - Определить функции для обработки сообщения: RS_Parse_Message(), RS_Collect_Message(), RS_Response(), RS_Define_Size_of_RX_Message() - - Добавить UART/TIM Handler в Хендлер используемых UART/TIM. + - Добавить UART/TIM Handler в Хендлер используемых UART/TIM. Так же данный модуль использует счетчики ************************************************************************** @@ -27,9 +27,6 @@ #include "modbus.h" -#include "crc_algs.h" - - ///////////////////////////////////////////////////////////////////// ////////////////////////////---DEFINES---//////////////////////////// /* Check that all defines required by RS are defined */ @@ -43,43 +40,81 @@ /* Clear message-uart buffer */ -#define RS_Clear_Buff(_buff_) for(int i=0; if.RS_Busy = 0 -#define RS_Set_Busy(_hRS_) _hRS_->f.RS_Busy = 1 +#define RS_Set_Free(_hRS_) _hRS_->f.RS_Busy = 0 +#define RS_Set_Busy(_hRS_) _hRS_->f.RS_Busy = 1 -#define RS_Set_RX_Flags(_hRS_) _hRS_->f.RX_Busy = 1; _hRS_->f.RX_Done = 0; _hRS_->f.RX_Half = 0 +#define RS_Set_RX_Flags(_hRS_) _hRS_->f.RX_Busy = 1; _hRS_->f.RX_Done = 0; _hRS_->f.RX_Half = 0 #define RS_Set_RX_Active_Flags(_hRS_) _hRS_->f.RX_Ongoing = 1 -#define RS_Set_TX_Flags(_hRS_) _hRS_->f.TX_Busy = 1; _hRS_->f.TX_Done = 0 +#define RS_Set_TX_Flags(_hRS_) _hRS_->f.TX_Busy = 1; _hRS_->f.TX_Done = 0 #define RS_Reset_RX_Active_Flags(_hRS_) _hRS_->f.RX_Ongoing = 0 -#define RS_Reset_RX_Flags(_hRS_) RS_Reset_RX_Active_Flags(_hRS_); _hRS_->f.RX_Busy = 0; _hRS_->f.RX_Done = 0; _hRS_->f.RX_Half = 0 -#define RS_Reset_TX_Flags(_hRS_) _hRS_->f.TX_Busy = 0; _hRS_->f.TX_Done = 0 +#define RS_Reset_RX_Flags(_hRS_) RS_Reset_RX_Active_Flags(_hRS_); _hRS_->f.RX_Busy = 0; _hRS_->f.RX_Done = 0; _hRS_->f.RX_Half = 0 +#define RS_Reset_TX_Flags(_hRS_) _hRS_->f.TX_Busy = 0; _hRS_->f.TX_Done = 0 -#define RS_Set_RX_End_Flag(_hRS_) _hRS_->f.RX_Done = 1; -#define RS_Set_TX_End_Flag(_hRS_) _hRS_->f.TX_Done = 1 +#define RS_Set_RX_End_Flag(_hRS_) _hRS_->f.RX_Done = 1; +#define RS_Set_TX_End_Flag(_hRS_) _hRS_->f.TX_Done = 1 -#define RS_Set_RX_End(_hRS_) RS_Reset_RX_Flags(_hRS_); RS_Set_RX_End_Flag(_hRS_) -#define RS_Set_TX_End(_hRS_) RS_Reset_TX_Flags(_hRS_); RS_Set_TX_End_Flag(_hRS_) +#define RS_Set_RX_End(_hRS_) RS_Reset_RX_Flags(_hRS_); RS_Set_RX_End_Flag(_hRS_) +#define RS_Set_TX_End(_hRS_) RS_Reset_TX_Flags(_hRS_); RS_Set_TX_End_Flag(_hRS_) /* Clear all RS stuff */ -#define RS_Clear_All(_hRS_) RS_Clear_Buff(_hRS_->pBufferPtr); RS_Reset_RX_Flags(_hRS_); RS_Reset_TX_Flags(_hRS_); - -//#define MB_Is_RX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_RX) -//#define MB_Is_TX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_TX) -#define RS_Is_RX_Busy(_hRS_) (_hRS_->f.RX_Busy == 1) -#define RS_Is_TX_Busy(_hRS_) (_hRS_->f.TX_Busy == 1) +#define RS_Clear_All(_hRS_) RS_Clear_Buff(_hRS_->pBufferPtr); RS_Reset_RX_Flags(_hRS_); RS_Reset_TX_Flags(_hRS_); +//#define MB_Is_RX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_RX) +//#define MB_Is_TX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_TX) +#define RS_Is_RX_Busy(_hRS_) (_hRS_->f.RX_Busy == 1) +#define RS_Is_TX_Busy(_hRS_) (_hRS_->f.TX_Busy == 1) +// Заглушки +// направление передачи rs485 #ifndef RS_EnableReceive #define RS_EnableReceive() #endif #ifndef RS_EnableTransmit #define RS_EnableTransmit() #endif + +#ifndef __MYLIBS_INCLUDE_H_ +// дефайны из mylibs include +static int dummy; +#define TrackerTypeDef(num_user_vars) void * +#define num_of_usercnts(_user_) 0 +#define assert_tracecnt(_cntstruct_, _uservarnumb_) 0 +#define if_assert_usertracker(_cntstruct_, _uservarnumb_) if(0) +#define tern_assert_usertracker(_cntstruct_, _uservarnumb_) 0 +#define TrackerGet_Ok(_cntstruct_) dummy +#define TrackerGet_Err(_cntstruct_) dummy +#define TrackerGet_Warn(_cntstruct_) dummy +#define TrackerGet_User(_cntstruct_, _uservarnumb_) dummy +#define TrackerCnt_Ok(_cntstruct_) +#define TrackerCnt_Err(_cntstruct_) +#define TrackerCnt_Warn(_cntstruct_) +#define TrackerCnt_User(_cntstruct_, _uservarnumb_) +#define TrackerWrite_User(_cntstruct_, _uservarnumb_, _val_) +#define TrackerClear_All(_cntstruct_) +#define TrackerClear_Ok(_cntstruct_) +#define TrackerClear_Err(_cntstruct_) +#define TrackerClear_Warn(_cntstruct_) +#define TrackerClear_User(_cntstruct_) +#define TrackerClear_UserAll(_cntstruct_) + +#ifndef printf_rs_err +#define printf_rs_err(...) +#endif + +#ifndef printf_rs +#define printf_rs(...) +#endif +#endif + +#ifndef RS_USER_VARS_NUMB +#define RS_USER_VARS_NUMB 0 +#endif ////////////////////////////---DEFINES---//////////////////////////// @@ -88,52 +123,52 @@ ///////////////////////---STRUCTURES & ENUMS---////////////////////// //------------------ENUMERATIONS-------------------- /** @brief Enums for respond CMD about RS status */ -typedef enum // RS_StatusTypeDef +typedef enum // RS_StatusTypeDef { - /* IN-CODE STATUS (start from 0x01, and goes up)*/ - /*0x01*/ RS_OK = 0x01, - /*0x02*/ RS_ERR, - /*0x03*/ RS_ABORTED, - /*0x04*/ RS_BUSY, - /*0x05*/ RS_SKIP, - - /*0x06*/ RS_COLLECT_MSG_ERR, - /*0x07*/ RS_PARSE_MSG_ERR, - - // reserved values -// /*0x00*/ RS_UNKNOWN_ERR = 0x00, ///< reserved for case, if no one error founded (nothing changed response from zero) + /* IN-CODE STATUS (start from 0x01, and goes up)*/ + /*0x01*/ RS_OK = 0x01, + /*0x02*/ RS_ERR, + /*0x03*/ RS_ABORTED, + /*0x04*/ RS_BUSY, + /*0x05*/ RS_SKIP, + + /*0x06*/ RS_COLLECT_MSG_ERR, + /*0x07*/ RS_PARSE_MSG_ERR, + + // reserved values +// /*0x00*/ RS_UNKNOWN_ERR = 0x00, ///< reserved for case, if no one error founded (nothing changed response from zero) }RS_StatusTypeDef; /** @brief Enums for RS Modes */ -typedef enum // RS_ModeTypeDef +typedef enum // RS_ModeTypeDef { - SLAVE_ALWAYS_WAIT = 0x01, ///< Slave mode with infinity waiting - SLAVE_TIMEOUT_WAIT = 0x02, ///< Slave mode with waiting with timeout -// MASTER = 0x03, ///< Master mode + SLAVE_ALWAYS_WAIT = 0x01, ///< Slave mode with infinity waiting + SLAVE_TIMEOUT_WAIT = 0x02, ///< Slave mode with waiting with timeout +// MASTER = 0x03, ///< Master mode }RS_ModeTypeDef; /** @brief Enums for RS UART Modes */ -typedef enum // RS_ITModeTypeDef +typedef enum // RS_ITModeTypeDef { - BLCK_MODE = 0x00, ///< Blocking mode - IT_MODE = 0x01, ///< Interrupt mode + BLCK_MODE = 0x00, ///< Blocking mode + IT_MODE = 0x01, ///< Interrupt mode }RS_ITModeTypeDef; /** @brief Enums for Abort modes */ -typedef enum // RS_AbortTypeDef +typedef enum // RS_AbortTypeDef { - ABORT_TX = 0x01, ///< Abort transmit - ABORT_RX = 0x02, ///< Abort receive - ABORT_RX_TX = 0x03, ///< Abort receive and transmit - ABORT_RS = 0x04, ///< Abort uart and reset RS structure + ABORT_TX = 0x01, ///< Abort transmit + ABORT_RX = 0x02, ///< Abort receive + ABORT_RX_TX = 0x03, ///< Abort receive and transmit + ABORT_RS = 0x04, ///< Abort uart and reset RS structure }RS_AbortTypeDef; /** @brief Enums for RX Size modes */ -typedef enum // RS_RXSizeTypeDef +typedef enum // RS_RXSizeTypeDef { - RS_RX_Size_Const = 0x01, ///< size of receiving message is constant - RS_RX_Size_NotConst = 0x02, ///< size of receiving message isnt constant + RS_RX_Size_Const = 0x01, ///< size of receiving message is constant + RS_RX_Size_NotConst = 0x02, ///< size of receiving message isnt constant }RS_RXSizeTypeDef; @@ -141,51 +176,55 @@ typedef enum // RS_RXSizeTypeDef /** @brief Struct for flags RS */ typedef struct { - unsigned RX_Half:1; ///< flag: 0 - receiving msg before ByteCnt, 0 - receiving msg after ByteCnt - - unsigned RS_Busy:1; ///< flag: 1 - RS is busy, 0 - RS isnt busy - unsigned RX_Ongoing:1; ///< flag: 1 - receiving data right now, 0 - waiting for receiving data + unsigned RX_Half:1; ///< flag: 0 - receiving msg before ByteCnt, 0 - receiving msg after ByteCnt - unsigned RX_Busy:1; ///< flag: 1 - receiving is active, 0 - receiving isnt active - unsigned TX_Busy:1; ///< flag: 1 - transmiting is active, 0 - transmiting isnt active - - unsigned RX_Done:1; ///< flag: 1 - receiving is done, 0 - receiving isnt done - unsigned TX_Done:1; ///< flag: 1 - transmiting is done, 0 - transmiting isnt done - - // setted by user - unsigned MessageHandled:1; ///< flag: 1 - RS command is handled, 0 - RS command isnt handled yet - unsigned EchoResponse:1; ///< flag: 1 - response with received msg, 0 - response with own msg - unsigned DeferredResponse:1; ///< flag: 1 - response not in interrupt, 0 - response in interrupt - unsigned ReInit_UART:1; ///< flag: 1 - need to reinitialize uart, 0 - nothing + unsigned RS_Busy:1; ///< flag: 1 - RS is busy, 0 - RS isnt busy + unsigned RX_Ongoing:1; ///< flag: 1 - receiving data right now, 0 - waiting for receiving data + + unsigned RX_Busy:1; ///< flag: 1 - receiving is active, 0 - receiving isnt active + unsigned TX_Busy:1; ///< flag: 1 - transmiting is active, 0 - transmiting isnt active + + unsigned RX_Done:1; ///< flag: 1 - receiving is done, 0 - receiving isnt done + unsigned TX_Done:1; ///< flag: 1 - transmiting is done, 0 - transmiting isnt done + + // setted by user + unsigned MessageHandled:1; ///< flag: 1 - RS command is handled, 0 - RS command isnt handled yet + unsigned EchoResponse:1; ///< flag: 1 - response with received msg, 0 - response with own msg + unsigned DeferredResponse:1; ///< flag: 1 - response not in interrupt, 0 - response in interrupt + unsigned DataUpdated:1; ///< flag: 1 - Received command to write colis/resg + unsigned ReInit_UART:1; ///< flag: 1 - need to reinitialize uart, 0 - nothing }RS_FlagsTypeDef; /** - * @brief Handle for RS communication. - * @note Prefixes: h - handle, s - settings, f - flag - */ -typedef struct // RS_HandleTypeDef -{ - /* MESSAGE */ - uint8_t ID; ///< ID of RS "channel" - RS_MsgTypeDef *pMessagePtr; ///< pointer to message struct - uint8_t *pBufferPtr; ///< pointer to message buffer - uint32_t RS_Message_Size; ///< size of whole message, not only data - - /* HANDLERS and SETTINGS */ - UART_HandleTypeDef *huart; ///< handler for used uart - TIM_HandleTypeDef *htim; ///< handler for used tim - RS_ModeTypeDef sRS_Mode; ///< setting: slave or master @ref RS_ModeTypeDef - RS_ITModeTypeDef sRS_IT_Mode; ///< setting: 1 - IT mode, 0 - Blocking mode - uint16_t sRS_Timeout; ///< setting: timeout in ms - RS_RXSizeTypeDef sRS_RX_Size_Mode; ///< setting: 1 - not const, 0 - const - - /* FLAGS */ - RS_FlagsTypeDef f; ///< These flags for controling receive/transmit + * @brief Handle for RS communication. + * @note Prefixes: h - handle, s - settings, f - flag + */ +typedef struct // RS_HandleTypeDef +{ + /* MESSAGE */ + uint8_t ID; ///< ID of RS "channel" + RS_MsgTypeDef *pMessagePtr; ///< pointer to message struct + uint8_t *pBufferPtr; ///< pointer to message buffer + uint32_t RS_Message_Size; ///< size of whole message, not only data - /* RS STATUS */ - RS_StatusTypeDef RS_STATUS; ///< RS status + /* HANDLERS and SETTINGS */ + UART_HandleTypeDef *huart; ///< handler for used uart + TIM_HandleTypeDef *htim; ///< handler for used tim + RS_ModeTypeDef sRS_Mode; ///< setting: slave or master @ref RS_ModeTypeDef + RS_ITModeTypeDef sRS_IT_Mode; ///< setting: 1 - IT mode, 0 - Blocking mode + uint16_t sRS_Timeout; ///< setting: timeout in ms + RS_RXSizeTypeDef sRS_RX_Size_Mode; ///< setting: 1 - not const, 0 - const + + /* FLAGS */ + RS_FlagsTypeDef f; ///< These flags for controling receive/transmit + + /* RS STATUS */ + uint32_t lastPacketTick; + RS_StatusTypeDef RS_STATUS; ///< RS status + + TrackerTypeDef(RS_USER_VARS_NUMB) rs_err; }RS_HandleTypeDef; extern RS_HandleTypeDef hmodbus1; @@ -247,11 +286,5 @@ void RS_TIM_Handler(RS_HandleTypeDef *hRS); ///////////////////////////---FUNCTIONS---/////////////////////////// -#ifndef printf_rs_err -#define printf_rs_err(...) -#endif -#ifndef printf_rs -#define printf_rs(...) -#endif #endif // __RS_LIB_H_