сделан idle

This commit is contained in:
2025-11-03 13:36:38 +03:00
parent 1005dc0c8a
commit 52de3f9c08
10 changed files with 1811 additions and 1515 deletions

3
.gitignore vendored
View File

@@ -1 +1,2 @@
/STM32F103_Example/MDK-ARM/Modbus_example /STM32F103_Example/MDK-ARM/Modbus_example
/Modbus/.vs/

116
Modbus/__crc_algs.c Normal file
View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -1,8 +1,8 @@
/** /**
************************************************************************** **************************************************************************
* @file modbus.c * @file modbus.c
* @brief Модуль для реализации MODBUS. * @brief Модуль для реализации MODBUS.
************************************************************************** **************************************************************************
* @details Файл содержит реализацию функций работы с Modbus, включая: * @details Файл содержит реализацию функций работы с Modbus, включая:
* - доступ к coils и registers; * - доступ к coils и registers;
* - обработку команд протокола; * - обработку команд протокола;
@@ -24,11 +24,12 @@
* - MB_DefineCoilsAddress() — Определить начальный адрес coils. * - MB_DefineCoilsAddress() — Определить начальный адрес coils.
* - MB_Check_Address_For_Arr() — Проверить, принадлежит ли адрес массиву. * - MB_Check_Address_For_Arr() — Проверить, принадлежит ли адрес массиву.
* - Основные команды Modbus: * - Основные команды Modbus:
* - MB_Read_Coils() * - MB_Proccess_Read_Coils()
* - MB_Read_Hold_Regs() * - MB_Proccess_Read_Hold_Regs()
* - MB_Write_Single_Coil() * - MB_Proccess_Write_Single_Coil()
* - MB_Proccess_Write_Single_Reg()
* - MB_Write_Miltuple_Coils() * - MB_Write_Miltuple_Coils()
* - MB_Write_Miltuple_Regs() * - MB_Proccess_Write_Miltuple_Regs()
* *
* ### Функции для работы с RS (UART): * ### Функции для работы с RS (UART):
* - RS_Parse_Message() / RS_Collect_Message() — Парсинг и сборка сообщения. * - RS_Parse_Message() / RS_Collect_Message() — Парсинг и сборка сообщения.
@@ -42,11 +43,11 @@
* @section Структура данных Modbus * @section Структура данных Modbus
* *
* #### Holding/Input Registers: * #### Holding/Input Registers:
* - Регистры — 16-битные слова. Доступ к регистрам осуществляется через указатель. * - Регистры — 16-битные слова. Доступ к регистрам осуществляется через указатель.
* Таким образом, сами регистры могут представлять собой как массив так и структуру. * Таким образом, сами регистры могут представлять собой как массив так и структуру.
* *
* #### Coils: * #### Coils:
* - Coils — это биты, упакованные в 16-битные слова. Доступ к коилам осуществляется через указатель. * - Coils — это биты, упакованные в 16-битные слова. Доступ к коилам осуществляется через указатель.
* Таким образом, сами коилы могут представлять собой как массив так и структуру. * Таким образом, сами коилы могут представлять собой как массив так и структуру.
* *
* @section Инструкция по подключению * @section Инструкция по подключению
@@ -72,480 +73,486 @@ extern TIM_HandleTypeDef rs_htim;
RS_HandleTypeDef hmodbus1; RS_HandleTypeDef hmodbus1;
/* DEFINE REGISTERS/COILS */ /* DEFINE REGISTERS/COILS */
MB_DeviceIdentificationTypeDef MB_INFO; MB_DeviceIdentificationTypeDef MB_DEVID;
MB_DataStructureTypeDef MB_DATA; MB_DataStructureTypeDef MB_DATA = {0};;
RS_MsgTypeDef MODBUS_MSG; RS_MsgTypeDef MODBUS_MSG;
//------------------------------------------------------------------- //-------------------------------------------------------------------
//-----------------------------FOR USER------------------------------ //-----------------------------FOR USER------------------------------
/** /**
* @brief First set up of MODBUS. * @brief First set up of MODBUS.
* @details Первый инит модбас. Заполняет структуры и инициализирует таймер и юарт для общения по модбас. * @details Первый инит модбас. Заполняет структуры и инициализирует таймер и юарт для общения по модбас.
* @note This called from main * @note This called from main
*/ */
void MODBUS_FirstInit(void) void MODBUS_FirstInit(void)
{ {
MB_DevoceInentificationInit(); MB_DeviceInentificationInit();
//-----------SETUP MODBUS------------- //-----------SETUP MODBUS-------------
// set up modbus: MB_RX_Size_NotConst and Timeout enable // set up modbus: MB_RX_Size_NotConst and Timeout enable
hmodbus1.ID = MODBUS_DEVICE_ID; hmodbus1.ID = MODBUS_DEVICE_ID;
hmodbus1.sRS_Timeout = MODBUS_TIMEOUT; hmodbus1.sRS_Timeout = MODBUS_TIMEOUT;
hmodbus1.sRS_Mode = SLAVE_ALWAYS_WAIT; hmodbus1.sRS_Mode = SLAVE_ALWAYS_WAIT;
hmodbus1.sRS_RX_Size_Mode = RS_RX_Size_NotConst; hmodbus1.sRS_RX_Size_Mode = RS_RX_Size_NotConst;
// INIT // INIT
hmodbus1.RS_STATUS = RS_Init(&hmodbus1, &rs_huart, &rs_htim, 0); hmodbus1.RS_STATUS = RS_Init(&hmodbus1, &rs_huart, &rs_htim, 0);
RS_EnableReceive(); RS_EnableReceive();
} }
/** /**
* @brief Set or Reset Coil at its global address. * @brief Set or Reset Coil at its global address.
* @param Addr - адрес коила. * @param Addr - адрес коила.
* @param WriteVal - Что записать в коил: 0 или 1. * @param WriteVal - Что записать в коил: 0 или 1.
* @return ExceptionCode - Код исключения если коила по адресу не существует, и NO_ERRORS если все ок. * @return ExceptionCode - Код исключения если коила по адресу не существует, и NO_ERRORS если все ок.
* *
* @details Позволяет обратиться к любому коилу по его глобальному адрессу. * @details Позволяет обратиться к любому коилу по его глобальному адрессу.
Вне зависимости от того как коилы размещены в памяти. Вне зависимости от того как коилы размещены в памяти.
*/ */
MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal) MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal)
{ {
//---------CHECK FOR ERRORS---------- //---------CHECK FOR ERRORS----------
MB_ExceptionTypeDef Exception = NO_ERRORS; MB_ExceptionTypeDef Exception = NO_ERRORS;
uint16_t *coils; uint16_t *coils;
uint16_t start_shift = 0; // shift in coils register uint16_t start_shift = 0; // shift in coils register
//------------WRITE COIL------------- //------------WRITE COIL-------------
Exception = MB_DefineCoilsAddress(&coils, Addr, 1, &start_shift, 1); Exception = MB_DefineCoilsAddress(&coils, Addr, 1, &start_shift, 1);
if(Exception == NO_ERRORS) if(Exception == NO_ERRORS)
{ {
switch(WriteVal) switch(WriteVal)
{ {
case SET_COIL: case SET_COIL:
*coils |= (1<<start_shift); *coils |= (1<<start_shift);
break; break;
case RESET_COIL: case RESET_COIL:
*coils &= ~(1<<start_shift); *coils &= ~(1<<start_shift);
break; break;
case TOOGLE_COIL: case TOOGLE_COIL:
*coils ^= (1<<start_shift); *coils ^= (1<<start_shift);
break; break;
} }
} }
return Exception; return Exception;
} }
/** /**
* @brief Read Coil at its global address. * @brief Read Coil at its global address.
* @param Addr - адрес коила. * @param Addr - адрес коила.
* @param Exception - Указатель на переменную для кода исключения, в случа неудачи при чтении. * @param Exception - Указатель на переменную для кода исключения, в случа неудачи при чтении.
* @return uint16_t - Возвращает весь регистр с маской на запрошенном коиле. * @return uint16_t - Возвращает весь регистр с маской на запрошенном коиле.
* *
* @details Позволяет обратиться к любому коилу по его глобальному адрессу. * @details Позволяет обратиться к любому коилу по его глобальному адрессу.
Вне зависимости от того как коилы размещены в памяти. Вне зависимости от того как коилы размещены в памяти.
*/ */
uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception) uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
{ {
//---------CHECK FOR ERRORS---------- //---------CHECK FOR ERRORS----------
MB_ExceptionTypeDef Exception_tmp; MB_ExceptionTypeDef Exception_tmp;
if(Exception == NULL) // if exception is not given to func fill it if(Exception == NULL) // if exception is not given to func fill it
Exception = &Exception_tmp; Exception = &Exception_tmp;
uint16_t *coils; uint16_t *coils;
uint16_t start_shift = 0; // shift in coils register uint16_t start_shift = 0; // shift in coils register
//------------READ COIL-------------- //------------READ COIL--------------
*Exception = MB_DefineCoilsAddress(&coils, Addr, 1, &start_shift, 0); *Exception = MB_DefineCoilsAddress(&coils, Addr, 1, &start_shift, 0);
if(*Exception == NO_ERRORS) if(*Exception == NO_ERRORS)
{ {
return ((*coils)&(1<<start_shift)); return ((*coils)&(1<<start_shift));
} }
else else
{ {
return 0; return 0;
} }
} }
//------------------------------------------------------------------- //-------------------------------------------------------------------
//----------------FUNCTIONS FOR PROCESSING MESSAGE------------------- //----------------FUNCTIONS FOR PROCESSING MESSAGE-------------------
/** /**
* @brief Check is address valid for certain array. * @brief Check is address valid for certain array.
* @param Addr - начальный адресс. * @param Addr - начальный адресс.
* @param Qnt - количество запрашиваемых элементов. * @param Qnt - количество запрашиваемых элементов.
* @param R_ARR_ADDR - начальный адресс массива R_ARR. * @param R_ARR_ADDR - начальный адресс массива R_ARR.
* @param R_ARR_NUMB - количество элементов в массиве R_ARR. * @param R_ARR_NUMB - количество элементов в массиве R_ARR.
* @return ExceptionCode - ILLEGAL DATA ADRESS если адресс недействителен, и NO_ERRORS если все ок. * @return ExceptionCode - ILLEGAL DATA ADRESS если адресс недействителен, и NO_ERRORS если все ок.
* *
* @details Позволяет определить, принадлежит ли адресс Addr массиву R_ARR: * @details Позволяет определить, принадлежит ли адресс Addr массиву R_ARR:
* Если адресс Addr находится в диапазоне адрессов массива R_ARR, то возвращаем NO_ERROR. * Если адресс Addr находится в диапазоне адрессов массива R_ARR, то возвращаем NO_ERROR.
* Если адресс Addr находится за пределами адрессов массива R_ARR - ILLEGAL_DATA_ADDRESSю. * Если адресс Addr находится за пределами адрессов массива R_ARR - ILLEGAL_DATA_ADDRESSю.
*/ */
MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB) MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB)
{ {
// if address from this array // if address from this array
if(Addr >= R_ARR_ADDR) if(Addr >= R_ARR_ADDR)
{ {
// if quantity too big return error // if quantity too big return error
if ((Addr - R_ARR_ADDR) + Qnt > R_ARR_NUMB) if ((Addr - R_ARR_ADDR) + Qnt > R_ARR_NUMB)
{ {
return ILLEGAL_DATA_ADDRESS; // return exception code return ILLEGAL_DATA_ADDRESS; // return exception code
} }
// if all ok - return no errors // if all ok - return no errors
return NO_ERRORS; return NO_ERRORS;
} }
// if address isnt from this array return error // if address isnt from this array return error
else else
return ILLEGAL_DATA_ADDRESS; // return exception code return ILLEGAL_DATA_ADDRESS; // return exception code
} }
/** /**
* @brief Define Address Origin for Input/Holding Registers * @brief Define Address Origin for Input/Holding Registers
* @param pRegs - указатель на указатель регистров. * @param pRegs - указатель на указатель регистров.
* @param Addr - адрес начального регистра. * @param Addr - адрес начального регистра.
* @param Qnt - количество запрашиваемых регистров. * @param Qnt - количество запрашиваемых регистров.
* @param WriteFlag - флаг регистр нужны для чтения или записи. * @param WriteFlag - флаг регистр нужны для чтения или записи.
* @return ExceptionCode - Код исключения если есть, и NO_ERRORS если нет. * @return ExceptionCode - Код исключения если есть, и NO_ERRORS если нет.
* *
* @details Определение адреса начального регистра. * @details Определение адреса начального регистра.
* @note WriteFlag пока не используется. * @note WriteFlag пока не используется.
*/ */
MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType) MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType)
{ {
/* check quantity error */ /* check quantity error */
if (Qnt > 125) if (Qnt > 125)
{ {
return ILLEGAL_DATA_VALUE; // return exception code return ILLEGAL_DATA_VALUE; // return exception code
} }
if(RegisterType == RegisterType_Holding) if(RegisterType == RegisterType_Holding)
{ {
// Default holding registers // Default holding registers
if(MB_Check_Address_For_Arr(Addr, Qnt, R_HOLDING_ADDR, R_HOLDING_QNT) == NO_ERRORS) 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 регистр *pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr); // указатель на выбранный по Addr регистр
} }
// if address doesnt match any array - return illegal data address response // if address doesnt match any array - return illegal data address response
else else
{ {
return ILLEGAL_DATA_ADDRESS; return ILLEGAL_DATA_ADDRESS;
} }
} }
else if(RegisterType == RegisterType_Input) else if(RegisterType == RegisterType_Input)
{ {
// Default input registers // Default input registers
if(MB_Check_Address_For_Arr(Addr, Qnt, R_INPUT_ADDR, R_INPUT_QNT) == NO_ERRORS) 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 регистр *pRegs = MB_Set_Register_Ptr(&MB_DATA.InRegs, Addr); // указатель на выбранный по Addr регистр
} }
// if address doesnt match any array - return illegal data address response // if address doesnt match any array - return illegal data address response
else else
{ {
return ILLEGAL_DATA_ADDRESS; return ILLEGAL_DATA_ADDRESS;
} }
} }
else else
{ {
return ILLEGAL_FUNCTION; return ILLEGAL_FUNCTION;
} }
// if found requeried array return no err // if found requeried array return no err
return NO_ERRORS; // return no errors return NO_ERRORS; // return no errors
} }
/** /**
* @brief Define Address Origin for coils * @brief Define Address Origin for coils
* @param pCoils - указатель на указатель коилов. * @param pCoils - указатель на указатель коилов.
* @param Addr - адресс начального коила. * @param Addr - адресс начального коила.
* @param Qnt - количество запрашиваемых коилов. * @param Qnt - количество запрашиваемых коилов.
* @param start_shift - указатель на переменную содержащую сдвиг внутри регистра для начального коила. * @param start_shift - указатель на переменную содержащую сдвиг внутри регистра для начального коила.
* @param WriteFlag - флаг коилы нужны для чтения или записи. * @param WriteFlag - флаг коилы нужны для чтения или записи.
* @return ExceptionCode - Код исключения если есть, и NO_ERRORS если нет. * @return ExceptionCode - Код исключения если есть, и NO_ERRORS если нет.
* *
* @details Определение адреса начального регистра запрашиваемых коилов. * @details Определение адреса начального регистра запрашиваемых коилов.
* @note WriteFlag используется для определния регистров GPIO: ODR или IDR. * @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) MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag)
{ {
/* check quantity error */ /* check quantity error */
if (Qnt > 2000) if (Qnt > 2000)
{ {
return ILLEGAL_DATA_VALUE; // return exception code return ILLEGAL_DATA_VALUE; // return exception code
} }
// Default coils // Default coils
if(MB_Check_Address_For_Arr(Addr, Qnt, C_CONTROL_ADDR, C_CONTROL_QNT) == NO_ERRORS) 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 массив коилов *pCoils = MB_Set_Coil_Reg_Ptr(&MB_DATA.Coils, Addr); // указатель на выбранный по Addr массив коилов
} }
// if address doesnt match any array - return illegal data address response // if address doesnt match any array - return illegal data address response
else else
{ {
return ILLEGAL_DATA_ADDRESS; return ILLEGAL_DATA_ADDRESS;
} }
*start_shift = Addr % 16; // set shift to requested coil *start_shift = Addr % 16; // set shift to requested coil
// if found requeried array return no err // if found requeried array return no err
return NO_ERRORS; // return no errors return NO_ERRORS; // return no errors
} }
/** /**
* @brief Proccess command Read Coils (01 - 0x01). * @brief Proccess command Read Coils (01 - 0x01).
* @param modbus_msg - указатель на структуру собщения modbus. * @param modbus_msg - указатель на структуру собщения modbus.
* @return fMessageHandled - статус о результате обработки комманды. * @return fMessageHandled - статус о результате обработки комманды.
* @details Обработка команды Read Coils. * @details Обработка команды Read Coils.
*/ */
uint8_t MB_Read_Coils(RS_MsgTypeDef *modbus_msg) uint8_t MB_Proccess_Read_Coils(RS_MsgTypeDef *modbus_msg)
{ {
//---------CHECK FOR ERRORS---------- //---------CHECK FOR ERRORS----------
uint16_t *coils; uint16_t *coils;
uint16_t start_shift = 0; // shift in coils register 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); modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, modbus_msg->Qnt, &start_shift, 0);
if(modbus_msg->Except_Code != NO_ERRORS) if(modbus_msg->Except_Code != NO_ERRORS)
return 0; return 0;
//-----------READING COIL------------ //-----------READING COIL------------
// setup output message data size // setup output message data size
modbus_msg->ByteCnt = Divide_Up(modbus_msg->Qnt, 8); modbus_msg->ByteCnt = Divide_Up(modbus_msg->Qnt, 8);
// create mask for coils // create mask for coils
uint16_t mask_for_coils = 0; // mask for coils that've been chosen uint16_t mask_for_coils = 0; // mask for coils that've been chosen
uint16_t setted_coils = 0; // value of setted coils 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 temp_reg = 0; // temp register for saving coils that hasnt been chosen
uint16_t coil_cnt = 0; // counter for processed coils uint16_t coil_cnt = 0; // counter for processed coils
// cycle until all registers with requered coils would be processed // cycle until all registers with requered coils would be processed
int shift = start_shift; // set shift to first coil in first register int shift = start_shift; // set shift to first coil in first register
int ind = 0; // index for coils registers and data int ind = 0; // index for coils registers and data
for(; ind <= Divide_Up(start_shift + modbus_msg->Qnt, 16); ind++) for(; ind <= Divide_Up(start_shift + modbus_msg->Qnt, 16); ind++)
{ {
//----SET MASK FOR COILS REGISTER---- //----SET MASK FOR COILS REGISTER----
mask_for_coils = 0; mask_for_coils = 0;
for(; shift < 0x10; shift++) for(; shift < 0x10; shift++)
{ {
mask_for_coils |= 1<<(shift); // choose certain coil mask_for_coils |= 1<<(shift); // choose certain coil
if(++coil_cnt >= modbus_msg->Qnt) if(++coil_cnt >= modbus_msg->Qnt)
break; break;
} }
shift = 0; // set shift to zero for the next step shift = 0; // set shift to zero for the next step
//-----------READ COILS-------------- //-----------READ COILS--------------
modbus_msg->DATA[ind] = (*(coils+ind)&mask_for_coils) >> start_shift; modbus_msg->DATA[ind] = (*(coils+ind)&mask_for_coils) >> start_shift;
if(ind > 0) if(ind > 0)
modbus_msg->DATA[ind-1] |= ((*(coils+ind)&mask_for_coils) << 16) >> start_shift; modbus_msg->DATA[ind-1] |= ((*(coils+ind)&mask_for_coils) << 16) >> start_shift;
} }
// т.к. DATA 16-битная, для 8-битной передачи, надо поменять местами верхний и нижний байты // т.к. DATA 16-битная, для 8-битной передачи, надо поменять местами верхний и нижний байты
for(; ind >= 0; --ind) for(; ind >= 0; --ind)
modbus_msg->DATA[ind] = ByteSwap16(modbus_msg->DATA[ind]); modbus_msg->DATA[ind] = ByteSwap16(modbus_msg->DATA[ind]);
return 1; return 1;
} }
/** /**
* @brief Proccess command Read Holding Registers (03 - 0x03). * @brief Proccess command Read Holding Registers (03 - 0x03).
* @param modbus_msg - указатель на структуру собщения modbus. * @param modbus_msg - указатель на структуру собщения modbus.
* @return fMessageHandled - статус о результате обработки комманды. * @return fMessageHandled - статус о результате обработки комманды.
* @details Обработка команды Read Holding Registers. * @details Обработка команды Read Holding Registers.
*/ */
uint8_t MB_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg) uint8_t MB_Proccess_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg)
{ {
//---------CHECK FOR ERRORS---------- //---------CHECK FOR ERRORS----------
// get origin address for data // get origin address for data
uint16_t *pHoldRegs; uint16_t *pHoldRegs;
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров
if(modbus_msg->Except_Code != NO_ERRORS) if(modbus_msg->Except_Code != NO_ERRORS)
return 0; return 0;
//-----------READING REGS------------ //-----------READING REGS------------
// setup output message data size // setup output message data size
modbus_msg->ByteCnt = modbus_msg->Qnt*2; // *2 because we transmit 8 bits, not 16 bits modbus_msg->ByteCnt = modbus_msg->Qnt*2; // *2 because we transmit 8 bits, not 16 bits
// read data // read data
int i; int i;
for (i = 0; i<modbus_msg->Qnt; i++) for (i = 0; i<modbus_msg->Qnt; i++)
{ {
modbus_msg->DATA[i] = *(pHoldRegs++); modbus_msg->DATA[i] = *(pHoldRegs++);
} }
return 1; return 1;
} }
/** /**
* @brief Proccess command Read Input Registers (04 - 0x04). * @brief Proccess command Read Input Registers (04 - 0x04).
* @param modbus_msg - указатель на структуру собщения modbus. * @param modbus_msg - указатель на структуру собщения modbus.
* @return fMessageHandled - статус о результате обработки комманды. * @return fMessageHandled - статус о результате обработки комманды.
* @details Обработка команды Read Input Registers. * @details Обработка команды Read Input Registers.
*/ */
uint8_t MB_Read_Input_Regs(RS_MsgTypeDef *modbus_msg) uint8_t MB_Proccess_Read_Input_Regs(RS_MsgTypeDef *modbus_msg)
{ {
//---------CHECK FOR ERRORS---------- //---------CHECK FOR ERRORS----------
// get origin address for data // get origin address for data
uint16_t *pInRegs; uint16_t *pInRegs;
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pInRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Input); // определение адреса регистров modbus_msg->Except_Code = MB_DefineRegistersAddress(&pInRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Input); // определение адреса регистров
if(modbus_msg->Except_Code != NO_ERRORS) if(modbus_msg->Except_Code != NO_ERRORS)
return 0; return 0;
//-----------READING REGS------------ //-----------READING REGS------------
// setup output message data size // setup output message data size
modbus_msg->ByteCnt = modbus_msg->Qnt*2; // *2 because we transmit 8 bits, not 16 bits modbus_msg->ByteCnt = modbus_msg->Qnt*2; // *2 because we transmit 8 bits, not 16 bits
// read data // read data
int i; int i;
for (i = 0; i<modbus_msg->Qnt; i++) for (i = 0; i<modbus_msg->Qnt; i++)
{ {
if(*((int16_t *)pInRegs) > 0) if(*((int16_t *)pInRegs) > 0)
modbus_msg->DATA[i] = (*pInRegs++); modbus_msg->DATA[i] = (*pInRegs++);
else else
modbus_msg->DATA[i] = (*pInRegs++); modbus_msg->DATA[i] = (*pInRegs++);
} }
return 1; return 1;
} }
/** /**
* @brief Proccess command Write Single Coils (05 - 0x05). * @brief Proccess command Write Single Coils (05 - 0x05).
* @param modbus_msg - указатель на структуру собщения modbus. * @param modbus_msg - указатель на структуру собщения modbus.
* @return fMessageHandled - статус о результате обработки комманды. * @return fMessageHandled - статус о результате обработки комманды.
* @details Обработка команды Write Single Coils. * @details Обработка команды Write Single Coils.
*/ */
uint8_t MB_Write_Single_Coil(RS_MsgTypeDef *modbus_msg) uint8_t MB_Proccess_Write_Single_Coil(RS_MsgTypeDef *modbus_msg)
{ {
//---------CHECK FOR ERRORS---------- //---------CHECK FOR ERRORS----------
if ((modbus_msg->Qnt != 0x0000) && (modbus_msg->Qnt != 0xFF00)) if ((modbus_msg->Qnt != 0x0000) && (modbus_msg->Qnt != 0xFF00))
{ {
modbus_msg->Except_Code = ILLEGAL_DATA_VALUE; modbus_msg->Except_Code = ILLEGAL_DATA_VALUE;
return 0; return 0;
} }
// define position of coil // define position of coil
uint16_t *coils; uint16_t *coils;
uint16_t start_shift = 0; // shift in coils register uint16_t start_shift = 0; // shift in coils register
modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, 0, &start_shift, 1); modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, 0, &start_shift, 1);
if(modbus_msg->Except_Code != NO_ERRORS) if(modbus_msg->Except_Code != NO_ERRORS)
return 0; return 0;
//----------WRITTING COIL------------ //----------WRITTING COIL------------
if(modbus_msg->Qnt == 0xFF00) if(modbus_msg->Qnt == 0xFF00)
*(coils) |= 1<<start_shift; // write flags corresponding to received data *(coils) |= 1<<start_shift; // write flags corresponding to received data
else else
*(coils) &= ~(1<<start_shift); // write flags corresponding to received data *(coils) &= ~(1<<start_shift); // write flags corresponding to received data
return 1; return 1;
} }
/** /**
* @brief Proccess command Write Single Register (06 - 0x06). * @brief Proccess command Write Single Register (06 - 0x06).
* @param modbus_msg - указатель на структуру собщения modbus. * @param modbus_msg - указатель на структуру собщения modbus.
* @return fMessageHandled - статус о результате обработки комманды. * @return fMessageHandled - статус о результате обработки комманды.
* @details Обработка команды Write Single Register. * @details Обработка команды Write Single Register.
*/ */
uint8_t MB_Write_Single_Reg(RS_MsgTypeDef *modbus_msg) uint8_t MB_Proccess_Write_Single_Reg(RS_MsgTypeDef *modbus_msg)
{ {
// get origin address for data // get origin address for data
uint16_t *pHoldRegs; uint16_t *pHoldRegs;
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, 1, RegisterType_Holding); // определение адреса регистров modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, 1, RegisterType_Holding); // определение адреса регистров
if(modbus_msg->Except_Code != NO_ERRORS) if(modbus_msg->Except_Code != NO_ERRORS)
return 0; return 0;
//-----------WRITTING REG------------ //-----------WRITTING REG------------
*(pHoldRegs) = modbus_msg->Qnt; *(pHoldRegs) = modbus_msg->Qnt;
return 1; return 1;
} }
/** /**
* @brief Proccess command Write Multiple Coils (15 - 0x0F). * @brief Proccess command Write Multiple Coils (15 - 0x0F).
* @param modbus_msg - указатель на структуру собщения modbus. * @param modbus_msg - указатель на структуру собщения modbus.
* @return fMessageHandled - статус о результате обработки комманды. * @return fMessageHandled - статус о результате обработки комманды.
* @details Обработка команды Write Multiple Coils. * @details Обработка команды Write Multiple Coils.
*/ */
uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg) uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg)
{ {
//---------CHECK FOR ERRORS---------- //---------CHECK FOR ERRORS----------
if (modbus_msg->ByteCnt != Divide_Up(modbus_msg->Qnt, 8)) if (modbus_msg->ByteCnt != Divide_Up(modbus_msg->Qnt, 8))
{ // if quantity too large OR if quantity and bytes count arent match { // if quantity too large OR if quantity and bytes count arent match
modbus_msg->Except_Code = ILLEGAL_DATA_VALUE; modbus_msg->Except_Code = ILLEGAL_DATA_VALUE;
return 0; return 0;
} }
// define position of coil // define position of coil
uint16_t *coils; // pointer to coils uint16_t *coils; // pointer to coils
uint16_t start_shift = 0; // shift in coils register 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); modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, modbus_msg->Qnt, &start_shift, 1);
if(modbus_msg->Except_Code != NO_ERRORS) if(modbus_msg->Except_Code != NO_ERRORS)
return 0; return 0;
//----------WRITTING COILS----------- //----------WRITTING COILS-----------
// create mask for coils // create mask for coils
uint16_t mask_for_coils = 0; // mask for coils that've been chosen uint16_t mask_for_coils = 0; // mask for coils that've been chosen
uint32_t setted_coils = 0; // value of setted coils 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 temp_reg = 0; // temp register for saving coils that hasnt been chosen
uint16_t coil_cnt = 0; // counter for processed coils uint16_t coil_cnt = 0; // counter for processed coils
// cycle until all registers with requered coils would be processed // cycle until all registers with requered coils would be processed
int shift = start_shift; // set shift to first coil in first register 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++) for(int ind = 0; ind <= Divide_Up(start_shift + modbus_msg->Qnt, 16); ind++)
{ {
//----SET MASK FOR COILS REGISTER---- //----SET MASK FOR COILS REGISTER----
mask_for_coils = 0; mask_for_coils = 0;
for(; shift < 0x10; shift++) for(; shift < 0x10; shift++)
{ {
mask_for_coils |= 1<<(shift); // choose certain coil mask_for_coils |= 1<<(shift); // choose certain coil
if(++coil_cnt >= modbus_msg->Qnt) if(++coil_cnt >= modbus_msg->Qnt)
break; break;
} }
shift = 0; // set shift to zero for the next step shift = 0; // set shift to zero for the next step
//-----------WRITE COILS------------- //-----------WRITE COILS-------------
// get current coils // get current coils
temp_reg = *(coils+ind); temp_reg = *(coils+ind);
// set coils // set coils
setted_coils = ByteSwap16(modbus_msg->DATA[ind]) << start_shift; setted_coils = ByteSwap16(modbus_msg->DATA[ind]) << start_shift;
if(ind > 0) if(ind > 0)
{ {
setted_coils |= ((ByteSwap16(modbus_msg->DATA[ind-1]) << start_shift) >> 16); setted_coils |= ((ByteSwap16(modbus_msg->DATA[ind-1]) << start_shift) >> 16);
} }
// write coils // write coils
*(coils+ind) = setted_coils & mask_for_coils; *(coils+ind) = setted_coils & mask_for_coils;
// restore untouched coils // restore untouched coils
*(coils+ind) |= temp_reg&(~mask_for_coils); *(coils+ind) |= temp_reg&(~mask_for_coils);
if(coil_cnt >= modbus_msg->Qnt) // if all coils written - break cycle if(coil_cnt >= modbus_msg->Qnt) // if all coils written - break cycle
break; // *kind of unnecessary break; // *kind of unnecessary
} }
return 1; return 1;
} }
/** /**
* @brief Proccess command Write Multiple Registers (16 - 0x10). * @brief Proccess command Write Multiple Registers (16 - 0x10).
* @param modbus_msg - указатель на структуру собщения modbus. * @param modbus_msg - указатель на структуру собщения modbus.
* @return fMessageHandled - статус о результате обработки комманды. * @return fMessageHandled - статус о результате обработки комманды.
* @details Обработка команды Write Multiple Registers. * @details Обработка команды Write Multiple Registers.
*/ */
uint8_t MB_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg) uint8_t MB_Proccess_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg)
{ {
//---------CHECK FOR ERRORS---------- //---------CHECK FOR ERRORS----------
if (modbus_msg->Qnt*2 != modbus_msg->ByteCnt) if (modbus_msg->Qnt*2 != modbus_msg->ByteCnt)
{ // if quantity and bytes count arent match { // if quantity and bytes count arent match
modbus_msg->Except_Code = 3; modbus_msg->Except_Code = 3;
return 0; return 0;
} }
// get origin address for data // get origin address for data
uint16_t *pHoldRegs; uint16_t *pHoldRegs;
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров
if(modbus_msg->Except_Code != NO_ERRORS) if(modbus_msg->Except_Code != NO_ERRORS)
return 0; return 0;
//-----------WRITTING REGS----------- //-----------WRITTING REGS-----------
for (int i = 0; i<modbus_msg->Qnt; i++) for (int i = 0; i<modbus_msg->Qnt; i++)
{ {
*(pHoldRegs++) = modbus_msg->DATA[i]; *(pHoldRegs++) = modbus_msg->DATA[i];
} }
return 1; 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; mbdata[(*ind)++] = obj->length;
for (int i = 0; i < obj->length; i++) 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]; mbdata[(*ind)++] = obj->name[i];
} }
} }
/** /**
* @brief Proccess command Read Device Identification (43/14 - 0x2B/0E). * @brief Write Object of Device Identification to MessageData
* @param modbus_msg - указатель на структуру собщения modbus. * @param mbdata - указатель на массив данных в структуре RS_MsgTypeDef.
* @return fMessageHandled - статус о результате обработки комманды. * @return obj - объект для записи.
* @details Обработка команды Write Single Register.
*/ */
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 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) switch(modbus_msg->DevId.ReadDevId)
{ {
case MB_BASIC_IDENTIFICATION: case MB_BASIC_IDENTIFICATION:
mbdata[ind++] = 0x00; if (modbus_msg->DevId.NextObjId == 0)
MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.VendorName); {
mbdata[ind++] = 0x01; modbus_msg->DevId.NextObjId = 0;
MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.ProductCode); }
mbdata[ind++] = 0x02;
MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.Revision); MB_WriteObjectsToMessage(modbus_msg, 2);
modbus_msg->DevId.NumbOfObj = 3; modbus_msg->DevId.NumbOfObj = 3;
break; break;
case MB_REGULAR_IDENTIFICATION: case MB_REGULAR_IDENTIFICATION:
mbdata[ind++] = 0x03; if (modbus_msg->DevId.NextObjId == 0)
MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.VendorUrl); {
mbdata[ind++] = 0x04; modbus_msg->DevId.NextObjId = 3;
MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.ProductName); }
mbdata[ind++] = 0x05;
MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.ModelName); MB_WriteObjectsToMessage(modbus_msg, 6);
mbdata[ind++] = 0x06;
MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.UserApplicationName);
modbus_msg->DevId.NumbOfObj = 4; modbus_msg->DevId.NumbOfObj = 4;
break; 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: default:
return 0; return 0;
} }
modbus_msg->ByteCnt = ind;
return 1; return 1;
} }
/** /**
* @brief Respond accord to received message. * @brief Respond accord to received message.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @param RS_msg - указатель на структуру сообщения. * @param RS_msg - указатель на структуру сообщения.
* @return RS_RES - статус о результате ответа на комманду. * @return RS_RES - статус о результате ответа на комманду.
* @details Обработка принятой комманды и ответ на неё. * @details Обработка принятой комманды и ответ на неё.
*/ */
RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
{ {
RS_StatusTypeDef MB_RES = 0; RS_StatusTypeDef MB_RES = 0;
hmodbus->f.MessageHandled = 0; hmodbus->f.MessageHandled = 0;
hmodbus->f.EchoResponse = 0; hmodbus->f.EchoResponse = 0;
RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit
if(modbus_msg->Func_Code < ERR_VALUES_START)// if no errors after parsing if(hmodbus->ID == 0)
{ {
switch (modbus_msg->Func_Code) hmodbus->RS_STATUS = RS_SKIP;
{ return MB_RES;
// Read Coils }
case MB_R_COILS:
hmodbus->f.MessageHandled = MB_Read_Coils(hmodbus->pMessagePtr); if(modbus_msg->Func_Code < ERR_VALUES_START)// if no errors after parsing
break; {
switch (modbus_msg->Func_Code)
// Read Hodling Registers {
case MB_R_HOLD_REGS: // Read Coils
hmodbus->f.MessageHandled = MB_Read_Hold_Regs(hmodbus->pMessagePtr); case MB_R_COILS:
break; hmodbus->f.MessageHandled = MB_Proccess_Read_Coils(hmodbus->pMessagePtr);
case MB_R_IN_REGS: break;
hmodbus->f.MessageHandled = MB_Read_Input_Regs(hmodbus->pMessagePtr);
break; // Read Hodling Registers
case MB_R_HOLD_REGS:
hmodbus->f.MessageHandled = MB_Proccess_Read_Hold_Regs(hmodbus->pMessagePtr);
// Write Single Coils break;
case MB_W_COIL: case MB_R_IN_REGS:
hmodbus->f.MessageHandled = MB_Write_Single_Coil(hmodbus->pMessagePtr); hmodbus->f.MessageHandled = MB_Proccess_Read_Input_Regs(hmodbus->pMessagePtr);
if(hmodbus->f.MessageHandled) break;
{
hmodbus->f.EchoResponse = 1;
hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes) // Write Single Coils
} case MB_W_COIL:
break; hmodbus->f.MessageHandled = MB_Proccess_Write_Single_Coil(hmodbus->pMessagePtr);
if(hmodbus->f.MessageHandled)
case MB_W_HOLD_REG: {
hmodbus->f.MessageHandled = MB_Write_Single_Reg(hmodbus->pMessagePtr); hmodbus->f.DataUpdated = 1;
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)
hmodbus->f.EchoResponse = 1; }
hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes) break;
}
break; case MB_W_HOLD_REG:
hmodbus->f.MessageHandled = MB_Proccess_Write_Single_Reg(hmodbus->pMessagePtr);
// Write Multiple Coils if(hmodbus->f.MessageHandled)
case MB_W_COILS: {
hmodbus->f.MessageHandled = MB_Write_Miltuple_Coils(hmodbus->pMessagePtr); hmodbus->f.DataUpdated = 1;
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)
hmodbus->f.EchoResponse = 1; }
hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes) break;
}
break; // Write Multiple Coils
case MB_W_COILS:
// Write Multiple Registers hmodbus->f.MessageHandled = MB_Write_Miltuple_Coils(hmodbus->pMessagePtr);
case MB_W_HOLD_REGS: if(hmodbus->f.MessageHandled)
hmodbus->f.MessageHandled = MB_Write_Miltuple_Regs(hmodbus->pMessagePtr); {
if(hmodbus->f.MessageHandled) hmodbus->f.DataUpdated = 1;
{ hmodbus->f.EchoResponse = 1;
hmodbus->f.EchoResponse = 1; hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes)
hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes) }
} break;
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: 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; break;
/* unknown func code */
/* unknown func code */ default: modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */
default: modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */ }
}
if(hmodbus->f.MessageHandled == 0)
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 else
{ {
TrackerCnt_Ok(hmodbus->rs_err);
} }
} }
// if we need response - check that transmit isnt busy // if we need response - check that transmit isnt busy
if( RS_Is_TX_Busy(hmodbus) ) if( RS_Is_TX_Busy(hmodbus) )
RS_Abort(hmodbus, ABORT_TX); // if tx busy - set it free RS_Abort(hmodbus, ABORT_TX); // if tx busy - set it free
// Transmit right there, or sets (fDeferredResponse) to transmit response in main code // Transmit right there, or sets (fDeferredResponse) to transmit response in main code
MB_RES = RS_Handle_Transmit_Start(hmodbus, modbus_msg); if(hmodbus->f.DeferredResponse == 0)
{
hmodbus->RS_STATUS = MB_RES; MB_RES = RS_Handle_Transmit_Start(hmodbus, modbus_msg);
return MB_RES; }
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. * @brief Collect message in buffer to transmit it.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @param RS_msg - указатель на структуру сообщения. * @param RS_msg - указатель на структуру сообщения.
* @param msg_uart_buff - указатель на буффер UART. * @param msg_uart_buff - указатель на буффер UART.
* @return RS_RES - статус о результате заполнения буфера. * @return RS_RES - статус о результате заполнения буфера.
* @details Заполнение буффера UART из структуры сообщения. * @details Заполнение буффера UART из структуры сообщения.
*/ */
RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) 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 int ind = 0; // ind for modbus-uart buffer
if(hmodbus->f.EchoResponse && hmodbus->f.MessageHandled) // if echo response need if(hmodbus->f.EchoResponse && hmodbus->f.MessageHandled) // if echo response need
ind = hmodbus->RS_Message_Size; ind = hmodbus->RS_Message_Size;
else else
{ {
//------INFO ABOUT DATA/MESSAGE------ //------INFO ABOUT DATA/MESSAGE------
//-----------[first bytes]----------- //-----------[first bytes]-----------
// set ID of message/user // set ID of message/user
modbus_uart_buff[ind++] = modbus_msg->MbAddr; modbus_uart_buff[ind++] = modbus_msg->MbAddr;
// set dat or err response // set dat or err response
modbus_uart_buff[ind++] = modbus_msg->Func_Code; 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 // fill modbus header
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // devide identification 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 if (modbus_msg->ByteCnt > DATA_SIZE*2) // if ByteCnt less than DATA_SIZE
{ {
TrackerCnt_Err(hmodbus->rs_err);
return RS_COLLECT_MSG_ERR; return RS_COLLECT_MSG_ERR;
} }
@@ -742,7 +832,7 @@ RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mo
//-----------[data bytes]------------ //-----------[data bytes]------------
uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA; uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA;
for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with 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; modbus_uart_buff[ind++] = *tmp_data_addr;
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 // set size of received data
if (modbus_msg->ByteCnt <= DATA_SIZE*2) // if ByteCnt less than DATA_SIZE if (modbus_msg->ByteCnt <= DATA_SIZE*2) // if ByteCnt less than DATA_SIZE
modbus_uart_buff[ind++] = modbus_msg->ByteCnt; 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; return RS_COLLECT_MSG_ERR;
} }
@@ -762,10 +853,10 @@ RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mo
//-----------[data bytes]------------ //-----------[data bytes]------------
uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA; uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA;
for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data
{ // set data { // set data
if (i%2 == 0) // HI byte if (i%2 == 0) // HI byte
modbus_uart_buff[ind++] = (*tmp_data_addr)>>8; modbus_uart_buff[ind++] = (*tmp_data_addr)>>8;
else // LO byte else // LO byte
{ {
modbus_uart_buff[ind++] = *tmp_data_addr; modbus_uart_buff[ind++] = *tmp_data_addr;
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 else // if some error occur
{ // send expection code { // send expection code
modbus_uart_buff[ind++] = modbus_msg->Except_Code; modbus_uart_buff[ind++] = modbus_msg->Except_Code;
} }
} }
//---------------CRC---------------- //---------------CRC----------------
//---------[last 16 bytes]---------- //---------[last 16 bytes]----------
// calc crc of received data // calc crc of received data
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind); uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
// write crc to message structure and modbus-uart buffer // write crc to message structure and modbus-uart buffer
modbus_msg->MB_CRC = CRC_VALUE; modbus_msg->MB_CRC = CRC_VALUE;
modbus_uart_buff[ind++] = CRC_VALUE; modbus_uart_buff[ind++] = CRC_VALUE;
modbus_uart_buff[ind++] = CRC_VALUE >> 8; modbus_uart_buff[ind++] = CRC_VALUE >> 8;
hmodbus->RS_Message_Size = ind; hmodbus->RS_Message_Size = ind;
return RS_OK; // returns ok return RS_OK; // returns ok
} }
/** /**
* @brief Parse message from buffer to process it. * @brief Parse message from buffer to process it.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @param RS_msg - указатель на структуру сообщения. * @param RS_msg - указатель на структуру сообщения.
* @param msg_uart_buff - указатель на буффер UART. * @param msg_uart_buff - указатель на буффер UART.
* @return RS_RES - статус о результате заполнения структуры. * @return RS_RES - статус о результате заполнения структуры.
* @details Заполнение структуры сообщения из буффера UART. * @details Заполнение структуры сообщения из буффера UART.
*/ */
RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
{ {
uint32_t check_empty_buff; uint32_t check_empty_buff;
int ind = 0; // ind for modbus-uart buffer int ind = 0; // ind for modbus-uart buffer
//-----INFO ABOUT DATA/MESSAGE------- //-----INFO ABOUT DATA/MESSAGE-------
//-----------[first bits]------------ //-----------[first bits]------------
// get ID of message/user // 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++]; 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++];
// get func code if(modbus_msg->Func_Code & ERR_VALUES_START) // явная херня
modbus_msg->Func_Code = modbus_uart_buff[ind++]; {
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // if it device identification request 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.MEI_Type = modbus_uart_buff[ind++];
modbus_msg->DevId.ReadDevId = 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 else // if its classic modbus request
{ {
// get address from CMD // get address from CMD
modbus_msg->Addr = modbus_uart_buff[ind++] << 8; modbus_msg->Addr = modbus_uart_buff[ind++] << 8;
modbus_msg->Addr |= modbus_uart_buff[ind++]; modbus_msg->Addr |= modbus_uart_buff[ind++];
// get address from CMD // get address from CMD
modbus_msg->Qnt = modbus_uart_buff[ind++] << 8; modbus_msg->Qnt = modbus_uart_buff[ind++] << 8;
modbus_msg->Qnt |= modbus_uart_buff[ind++]; modbus_msg->Qnt |= modbus_uart_buff[ind++];
} }
if(hmodbus->f.RX_Half == 0) // if all message received
{ if((hmodbus->pMessagePtr->Func_Code == 0x0F) || (hmodbus->pMessagePtr->Func_Code == 0x10))
//---------------DATA---------------- hmodbus->pMessagePtr->ByteCnt = modbus_uart_buff[ind++];
// (optional) else
if (modbus_msg->ByteCnt != 0) hmodbus->pMessagePtr->ByteCnt = 0;
{ //---------------DATA----------------
ind++; // increment ind for data_size byte // (optional)
//check that data size is correct if (modbus_msg->ByteCnt != 0)
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)
{ {
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
//---------------CRC----------------
// check is buffer empty //----------[last 16 bits]----------
check_empty_buff = 0; // calc crc of received data
for(int i=0; i<ind;i++) uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
check_empty_buff += modbus_uart_buff[i]; // get crc of received data
// if(check_empty_buff == 0) modbus_msg->MB_CRC = modbus_uart_buff[ind++];
// hmodbus->MB_RESPONSE = MB_EMPTY_MSG; // modbus_msg->MB_CRC |= modbus_uart_buff[ind++] << 8;
} // compare crc
if (modbus_msg->MB_CRC != CRC_VALUE)
return RS_OK; {
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; i<ind;i++)
check_empty_buff += modbus_uart_buff[i];
// if(check_empty_buff == 0)
// hmodbus->MB_RESPONSE = MB_EMPTY_MSG; //
return RS_OK;
} }
/** /**
* @brief Define size of RX Message that need to be received. * @brief Define size of RX Message that need to be received.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @param rx_data_size - указатель на переменную для записи кол-ва байт для принятия. * @param rx_data_size - указатель на переменную для записи кол-ва байт для принятия.
* @return RS_RES - статус о корректности рассчета кол-ва байт для принятия. * @return RS_RES - статус о корректности рассчета кол-ва байт для принятия.
* @details Определение сколько байтов надо принять по протоколу. * @details Определение сколько байтов надо принять по протоколу.
*/ */
RS_StatusTypeDef RS_Define_Size_of_RX_Message(RS_HandleTypeDef *hmodbus, uint32_t *rx_data_size) RS_StatusTypeDef RS_Define_Size_of_RX_Message(RS_HandleTypeDef *hmodbus, uint32_t *rx_data_size)
{ {
RS_StatusTypeDef MB_RES = 0; 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
if ((hmodbus->pMessagePtr->Func_Code & ~ERR_VALUES_START) < 0x0F) MB_RES = RS_Parse_Message(hmodbus, hmodbus->pMessagePtr, hmodbus->pBufferPtr);
{ // if(MB_RES == RS_SKIP) // if message not for us
hmodbus->pMessagePtr->ByteCnt = 0; // return MB_RES; // return
*rx_data_size = 1;
if ((hmodbus->pMessagePtr->Func_Code & ~ERR_VALUES_START) < 0x0F)
{
hmodbus->pMessagePtr->ByteCnt = 0;
*rx_data_size = 1;
} }
else else
{ {
hmodbus->pMessagePtr->ByteCnt = hmodbus->pBufferPtr[RX_FIRST_PART_SIZE-1]; // get numb of data in command hmodbus->pMessagePtr->ByteCnt = hmodbus->pBufferPtr[RX_FIRST_PART_SIZE-1]; // get numb of data in command
// +1 because that defines is size, not ind. // +1 because that defines is size, not ind.
*rx_data_size = hmodbus->pMessagePtr->ByteCnt + 2; *rx_data_size = hmodbus->pMessagePtr->ByteCnt + 2;
} }
if(hmodbus->pMessagePtr->Func_Code == MB_R_DEVICE_INFO) 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 hmodbus->RS_Message_Size = RX_FIRST_PART_SIZE + *rx_data_size; // size of whole message
return RS_OK; return RS_OK;
} }
//-----------------------------FOR USER------------------------------
//-------------------------------------------------------------------
void MB_DeviceInentificationInit(void)
void MB_DevoceInentificationInit(void)
{ {
MB_INFO.VendorName.name = MODBUS_VENDOR_NAME; MB_ObjectInit(&MB_DEVID.VendorName, MODBUS_VENDOR_NAME);
MB_INFO.ProductCode.name = MODBUS_PRODUCT_CODE; MB_ObjectInit(&MB_DEVID.ProductCode, MODBUS_PRODUCT_CODE);
MB_INFO.Revision.name = MODBUS_REVISION; MB_ObjectInit(&MB_DEVID.Revision, MODBUS_REVISION);
MB_INFO.VendorUrl.name = MODBUS_VENDOR_URL; MB_ObjectInit(&MB_DEVID.VendorUrl, MODBUS_VENDOR_URL);
MB_INFO.ProductName.name = MODBUS_PRODUCT_NAME; MB_ObjectInit(&MB_DEVID.ProductName, MODBUS_PRODUCT_NAME);
MB_INFO.ModelName.name = MODBUS_MODEL_NAME; MB_ObjectInit(&MB_DEVID.ModelName, 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);
} }

View File

@@ -1,286 +1,400 @@
/** /**
************************************************************************** **************************************************************************
* @file modbus.h * @file modbus.h
* @brief Заголовочный файл модуля MODBUS. * @brief Заголовочный файл модуля MODBUS.
* @details Данный файл необходимо подключить в rs_message.h. После подключать * @details Данный файл необходимо подключить в rs_message.h. После подключать
* rs_message.h к основному проекту. * rs_message.h к основному проекту.
* *
* @defgroup MODBUS * @defgroup MODBUS
* @brief Modbus stuff * @brief Modbus stuff
* *
*************************************************************************/ *************************************************************************/
#ifndef __MODBUS_H_ #ifndef __MODBUS_H_
#define __MODBUS_H_ #define __MODBUS_H_
#include "modbus_config.h" #include "modbus_config.h"
#include "modbus_data.h" #include "modbus_data.h"
//#include "settings.h" // for modbus settings #include "__crc_algs.h"
/** /**
* @addtogroup MODBUS_SETTINGS * @addtogroup MODBUS_SETTINGS
* @ingroup MODBUS * @ingroup MODBUS
* @brief Some defines for modbus * @brief Some defines for modbus
@{ @{
*/ */
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
//////////////////////////---SETTINGS---///////////////////////////// //////////////////////////---SETTINGS---/////////////////////////////
// USER SETTINGS FOR MODBUS IN interface_config.h // 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---///////////////////////////// //////////////////////////---SETTINGS---/////////////////////////////
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
/////////////////////---USER MESSAGE DEFINES---////////////////////// ////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
//-------------DEFINES FOR STRUCTURE---------------- //-------------DEFINES FOR STRUCTURE----------------
/* defines for structure of modbus message */ /* defines for structure of modbus message */
#define MbAddr_SIZE 1 ///< size of (MbAddr) #define MbAddr_SIZE 1 ///< size of (MbAddr)
#define Func_Code_SIZE 1 ///< size of (Func_Code) #define Func_Code_SIZE 1 ///< size of (Func_Code)
#define Addr_SIZE 2 ///< size of (Addr) #define Addr_SIZE 2 ///< size of (Addr)
#define Qnt_SIZE 2 ///< size of (Qnt) #define Qnt_SIZE 2 ///< size of (Qnt)
#define ByteCnt_SIZE 1 ///< size of (ByteCnt) #define ByteCnt_SIZE 1 ///< size of (ByteCnt)
#define DATA_SIZE 125 ///< maximum number of data: DWORD (NOT MESSAGE SIZE) #define DATA_SIZE 125 ///< maximum number of data: DWORD (NOT MESSAGE SIZE)
#define CRC_SIZE 2 ///< size of (MB_CRC) in bytes #define CRC_SIZE 2 ///< size of (MB_CRC) in bytes
/** @brief Size of whole message */ /** @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 /** @brief Size of first part of message that will be received
first receive info part of message, than defines size of rest message*/ 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 */ /** @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 */ /** @brief Structure for modbus exception codes */
typedef enum //MB_ExceptionTypeDef typedef enum //MB_ExceptionTypeDef
{ {
// reading // reading
NO_ERRORS = 0x00, ///< no errors NO_ERRORS = 0x00, ///< no errors
ILLEGAL_FUNCTION = 0x01, ///< Принятый код функции не может быть обработан ILLEGAL_FUNCTION = 0x01, ///< Принятый код функции не может быть обработан
ILLEGAL_DATA_ADDRESS = 0x02, ///< Адрес данных, указанный в запросе, недоступен ILLEGAL_DATA_ADDRESS = 0x02, ///< Адрес данных, указанный в запросе, недоступен
ILLEGAL_DATA_VALUE = 0x03, ///< Значение, содержащееся в поле данных запроса, является недопустимой величиной ILLEGAL_DATA_VALUE = 0x03, ///< Значение, содержащееся в поле данных запроса, является недопустимой величиной
SLAVE_DEVICE_FAILURE = 0x04, ///< Невосстанавливаемая ошибка имела место, пока ведомое устройство пыталось выполнить затребованное действие SLAVE_DEVICE_FAILURE = 0x04, ///< Невосстанавливаемая ошибка имела место, пока ведомое устройство пыталось выполнить затребованное действие
// ACKNOWLEDGE = 0x05, ///< idk // ACKNOWLEDGE = 0x05, ///< idk
// SLAVE_DEVICE_BUSY = 0x06, ///< idk // SLAVE_DEVICE_BUSY = 0x06, ///< idk
// MEMORY_PARITY_ERROR = 0x08, ///< idk // MEMORY_PARITY_ERROR = 0x08, ///< idk
}MB_ExceptionTypeDef; }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 */ /** @brief Structure for modbus func codes */
typedef enum //MB_FunctonTypeDef typedef enum //MB_FunctonTypeDef
{ {
/* COMMANDS */ /* COMMANDS */
// reading // reading
MB_R_COILS = 0x01, ///< Чтение битовых ячеек MB_R_COILS = 0x01, ///< Чтение битовых ячеек
MB_R_DISC_IN = 0x02, ///< Чтение дискретных входов MB_R_DISC_IN = 0x02, ///< Чтение дискретных входов
#ifndef MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS #ifndef MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS
MB_R_HOLD_REGS = 0x03, ///< Чтение входных регистров MB_R_HOLD_REGS = 0x03, ///< Чтение входных регистров
MB_R_IN_REGS = 0x04, ///< Чтение регистров хранения MB_R_IN_REGS = 0x04, ///< Чтение регистров хранения
#else #else
MB_R_HOLD_REGS = 0x04, ///< Чтение входных регистров MB_R_HOLD_REGS = 0x04, ///< Чтение входных регистров
MB_R_IN_REGS = 0x03, ///< Чтение регистров хранения MB_R_IN_REGS = 0x03, ///< Чтение регистров хранения
#endif #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 */ /* ERRORS */
// error reading // error reading
MB_ERR_R_COILS = MB_R_COILS + ERR_VALUES_START, ///< Ошибка чтения битовых ячеек 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_DISC_IN = MB_R_DISC_IN + ERR_VALUES_START, ///< Ошибка чтения дискретных входов
MB_ERR_R_IN_REGS = MB_R_IN_REGS + 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, ///< Ошибка чтения входных регистров MB_ERR_R_HOLD_REGS = MB_R_HOLD_REGS + ERR_VALUES_START, ///< Ошибка чтения входных регистров
// error writting // error writting
MB_ERR_W_COIL = MB_W_COIL + ERR_VALUES_START, ///< Ошибка записи битовой ячейки 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_HOLD_REG = MB_W_HOLD_REG + ERR_VALUES_START, ///< Ошибка записи одиночного регистра
MB_ERR_W_COILS = MB_W_COILS + 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_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; }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 */ /** @brief Structure for MEI func codes */
typedef enum //MB_FunctonTypeDef typedef enum //MB_FunctonTypeDef
{ {
MEI_DEVICE_IDENTIFICATION = 0x0E, MEI_DEVICE_IDENTIFICATION = 0x0E,
}MB_MEITypeDef; }MB_MEITypeDef;
/** @brief Structure for MEI func codes */ /** @brief Structure for comformity */
typedef enum //MB_FunctonTypeDef typedef enum //MB_FunctonTypeDef
{ {
MB_BASIC_IDENTIFICATION = 0x01, MB_BASIC_IDENTIFICATION = 0x01, /*!< @brief Basic Device Identification.
MB_REGULAR_IDENTIFICATION = 0x02, @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 */ /* ERRORS */
MB_ERR_BASIC_IDENTIFICATION = MB_BASIC_IDENTIFICATION + ERR_VALUES_START, MB_ERR_BASIC_IDENTIFICATION = MB_BASIC_IDENTIFICATION + ERR_VALUES_START,
MB_ERR_REGULAR_IDENTIFICATION = MB_REGULAR_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; }MB_ConformityTypeDef;
/** @brief Structure for decive identification message type */ /** @brief Structure for decive identification message type */
typedef struct 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 ReadDevId;
MB_ConformityTypeDef Conformity; MB_ConformityTypeDef Conformity;
uint8_t MoreFollows; ///< in this library always a zero uint8_t MoreFollows;
uint8_t NextObjId; uint8_t NextObjId;
uint8_t NumbOfObj; uint8_t NumbOfObj;
}MB_DevIdMsgTypeDef; }MB_DevIdMsgTypeDef;
/** @brief Structure for modbus messsage */ /** @brief Structure for modbus messsage */
typedef struct // RS_MsgTypeDef typedef struct // RS_MsgTypeDef
{ {
uint8_t MbAddr; ///< Modbus Slave Address uint8_t MbAddr; ///< Modbus Slave Address
MB_FunctonTypeDef Func_Code; ///< Modbus Function Code MB_FunctonTypeDef Func_Code; ///< Modbus Function Code
MB_DevIdMsgTypeDef DevId; ///< Read Device Identification Header struct MB_DevIdMsgTypeDef DevId; ///< Read Device Identification Header struct
uint16_t Addr; ///< Modbus Address of data uint16_t Addr; ///< Modbus Address of data
uint16_t Qnt; ///< Quantity of modbus data uint16_t Qnt; ///< Quantity of modbus data
uint8_t ByteCnt; ///< Quantity of bytes of data in message to transmit/receive uint8_t ByteCnt; ///< Quantity of bytes of data in message to transmit/receive
uint16_t DATA[DATA_SIZE]; ///< Modbus Data uint16_t DATA[DATA_SIZE]; ///< Modbus Data
MB_ExceptionTypeDef Except_Code; ///< Exception Code for the command MB_ExceptionTypeDef Except_Code; ///< Exception Code for the command
uint16_t MB_CRC; ///< Modbus CRC uint16_t MB_CRC; ///< Modbus CRC
}RS_MsgTypeDef; }RS_MsgTypeDef;
//-------------------------------------------------- //--------------------------------------------------
extern RS_MsgTypeDef MODBUS_MSG; 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_SETTINGS
* @} * @}
*/ */
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
////////////////////---MODBUS MESSAGE DEFINES---///////////////////// ////////////////////---MODBUS FUNCTION DEFINES---////////////////////
/** /**
* @addtogroup MODBUS_MESSAGE_DEFINES * @addtogroup MODBUS_MESSAGE_DEFINES
* @ingroup MODBUS * @ingroup MODBUS
* @brief Some defines for modbus * @brief Some defines for modbus
@{ @{
*/ */
/** @brief Structure for coils operation */ /** @brief Structure for coils operation */
typedef enum typedef enum
{ {
SET_COIL, SET_COIL,
RESET_COIL, RESET_COIL,
TOOGLE_COIL, TOOGLE_COIL,
}MB_CoilsOpTypeDef; }MB_CoilsOpTypeDef;
//-------------------------------------------------- //--------------------------------------------------
/** /**
* @brief Macros to set pointer to 16-bit array * @brief Macros to set pointer to 16-bit array
* @param _arr_ - массив регистров (16-бит). * @param _arr_ - массив регистров (16-бит).
*/ */
#define MB_Set_Arr16_Ptr(_arr_) ((uint16_t*)(&(_arr_))) #define MB_Set_Arr16_Ptr(_arr_) ((uint16_t*)(&(_arr_)))
/** /**
* @brief Macros to set pointer to register * @brief Macros to set pointer to register
* @param _parr_ - массив регистров. * @param _parr_ - массив регистров.
* @param _addr_ - Номер регистра (его индекс) от начала массива _arr_. * @param _addr_ - Номер регистра (его индекс) от начала массива _arr_.
*/ */
#define MB_Set_Register_Ptr(_parr_, _addr_) ((uint16_t *)(_parr_)+(_addr_)) #define MB_Set_Register_Ptr(_parr_, _addr_) ((uint16_t *)(_parr_)+(_addr_))
/** /**
* @brief Macros to set pointer to a certain register that contains certain coil * @brief Macros to set pointer to a certain register that contains certain coil
* @param _parr_ - массив коилов. * @param _parr_ - массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_. * @param _coil_ - Номер коила от начала массива _arr_.
* @note Используется вместе с @ref MB_Set_Coil_Mask * @note Используется вместе с @ref MB_Set_Coil_Mask
@verbatim Пояснение выражений @verbatim Пояснение выражений
(_coil_/16) - get index (address shift) of register that contain certain coil (_coil_/16) - get index (address shift) of register that contain certain coil
Visual explanation: 30th coil in coils registers array Visual explanation: 30th coil in coils registers array
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
|register[0]----| |register[1]----| |register[0]----| |register[1]----|
|skip this------| |get this-------| |skip this------| |get this-------|
|shift to 14 bit| |shift to 14 bit|
@endverbatim @endverbatim
*/ */
#define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16)) #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 * @brief Macros to set mask to a certain bit in coils register
* @param _coil_ - Номер коила от начала массива _arr_. * @param _coil_ - Номер коила от начала массива _arr_.
* @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr * @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr
@verbatim Пояснение выражений @verbatim Пояснение выражений
(16*(_coil_/16) - how many coils we need to skip. e.g. (16*30/16) - skip 16 coils from first register (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 _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) 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 Visual explanation: 30th coil in coils registers array
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
|register[0]----| |register[1]----| |register[0]----| |register[1]----|
|skip this------| |get this-------| |skip this------| |get this-------|
|shift to 14 bit| |shift to 14 bit|
@endverbatim @endverbatim
*/ */
#define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) )) #define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) ))
/** /**
* @brief Read Coil at its local address. * @brief Read Coil at its local address.
* @param _parr_ - массив коилов. * @param _parr_ - массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_. * @param _coil_ - Номер коила от начала массива _arr_.
* @return uint16_t - Возвращает запрошенный коил на 0м бите. * @return uint16_t - Возвращает запрошенный коил на 0м бите.
* *
* @details Позволяет обратиться к коилу по адресу относительно _arr_. * @details Позволяет обратиться к коилу по адресу относительно _arr_.
*/ */
#define MB_Read_Coil_Local(_parr_, _coil_) (( *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) & MB_Set_Coil_Mask(_coil_) ) >> (_coil_)) #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. * @brief Set Coil at its local address.
* @param _parr_ - указатель на массив коилов. * @param _parr_ - указатель на массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_. * @param _coil_ - Номер коила от начала массива _arr_.
* *
* @details Позволяет обратиться к коилу по адресу относительно _arr_. * @details Позволяет обратиться к коилу по адресу относительно _arr_.
*/ */
#define MB_Set_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) |= MB_Set_Coil_Mask(_coil_) #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. * @brief Reset Coil at its local address.
* @param _parr_ - указатель на массив коилов. * @param _parr_ - указатель на массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_. * @param _coil_ - Номер коила от начала массива _arr_.
* *
* @details Позволяет обратиться к коилу по адресу относительно _arr_. * @details Позволяет обратиться к коилу по адресу относительно _arr_.
*/ */
#define MB_Reset_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) &= ~(MB_Set_Coil_Mask(_coil_)) #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. * @brief Set Coil at its local address.
* @param _parr_ - указатель на массив коилов. * @param _parr_ - указатель на массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_. * @param _coil_ - Номер коила от начала массива _arr_.
* *
* @details Позволяет обратиться к коилу по адресу относительно _arr_. * @details Позволяет обратиться к коилу по адресу относительно _arr_.
*/ */
#define MB_Toogle_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ^= MB_Set_Coil_Mask(_coil_) #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------------------- //------------------OTHER DEFINES-------------------
#define RegisterType_Holding 0 #define RegisterType_Holding 0
#define RegisterType_Input 1 #define RegisterType_Input 1
#define RegisterType_Discrete 2 #define RegisterType_Discrete 2
// create hadnles and settings for uart, tim, rs with _modbus_ name // create hadnles and settings for uart, tim, rs with _modbus_ name
//-------------------------------------------------- //--------------------------------------------------
#ifndef Divide_Up #ifndef Divide_Up
/** /**
* @brief Calc dividing including remainder * @brief Calc dividing including remainder
* @param _val_ - делимое. * @param _val_ - делимое.
* @param _div_ - делитель. * @param _div_ - делитель.
* @details Если результат деления без остатка: он возвращается как есть * @details Если результат деления без остатка: он возвращается как есть
Если с остатком - округляется вверх Если с остатком - округляется вверх
*/ */
//#define Divide_Up(_val_, _div_) (((_val_)%(_div_))? (_val_)/(_div_)+1 : (_val_)/_div_) /* через тернарный оператор */ //#define Divide_Up(_val_, _div_) (((_val_)%(_div_))? (_val_)/(_div_)+1 : (_val_)/_div_) /* через тернарный оператор */
#define Divide_Up(_val_, _div_) ((_val_ - 1) / _div_) + 1 /* через мат выражение */ #define Divide_Up(_val_, _div_) ((_val_ - 1) / _div_) + 1 /* через мат выражение */
#endif #endif
#ifndef ByteSwap16 #ifndef ByteSwap16
/** /**
* @brief Swap between Little Endian and Big Endian * @brief Swap between Little Endian and Big Endian
* @param v - Переменная для свапа. * @param v - Переменная для свапа.
* @return v (new) - Свапнутая переменная. * @return v (new) - Свапнутая переменная.
* @details Переключения между двумя типами хранения слова: HI-LO байты и LO-HI байты. * @details Переключения между двумя типами хранения слова: HI-LO байты и LO-HI байты.
*/ */
#define ByteSwap16(v) (((v&0xFF00) >> (8)) | ((v&0x00FF) << (8))) #define ByteSwap16(v) (((v&0xFF00) >> (8)) | ((v&0x00FF) << (8)))
#endif #endif
/** GENERAL_MODBUS_STUFF /** GENERAL_MODBUS_STUFF
* @} * @}
@@ -292,18 +406,18 @@ typedef enum
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
/** /**
* @addtogroup MODBUS_FUNCTIONS * @addtogroup MODBUS_FUNCTIONS
* @ingroup MODBUS * @ingroup MODBUS
* @brief Function for controling modbus communication * @brief Function for controling modbus communication
*/ */
//----------------FUNCTIONS FOR USER---------------- //----------------FUNCTIONS FOR USER----------------
/** /**
* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS * @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS
* @ingroup MODBUS_FUNCTIONS * @ingroup MODBUS_FUNCTIONS
* @brief Function for user use * @brief Function for user use
@{ @{
*/ */
/* First set up of MODBUS */ /* First set up of MODBUS */
void MODBUS_FirstInit(void); void MODBUS_FirstInit(void);
/* Set or Reset Coil at its global address */ /* 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 /** MODBUS_DATA_ACCESS_FUNCTIONS
* @} * @}
*/ */
//---------PROCESS MODBUS COMMAND FUNCTIONS--------- //---------PROCESS MODBUS COMMAND FUNCTIONS---------
/** /**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
* @ingroup MODBUS_FUNCTIONS * @ingroup MODBUS_FUNCTIONS
* @brief Function process commands * @brief Function process commands
@{ @{
*/ */
/* Check is address valid for certain array */ /* 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); 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 */ /* 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 */ /* 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); 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) */ /* 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) */ /* 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) */ /* Proccess command Read Input Registers (04 - 0x04) */
uint8_t MB_Read_Input_Regs(RS_MsgTypeDef *modbus_msg); uint8_t MB_Proccess_Read_Input_Regs(RS_MsgTypeDef *modbus_msg);
/* Proccess command Write Single Coils (05 - 0x05) */ /* Proccess command Write Single Coils (05 - 0x05) */
uint8_t MB_Write_Single_Coil(RS_MsgTypeDef *modbus_msg); 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) */ /* Proccess command Write Multiple Coils (15 - 0x0F) */
uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg); uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg);
/* Proccess command Write Multiple Register (16 - 0x10) */ /* 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 /** MODBUS_DATA_ACCESS_FUNCTIONS
* @} * @}
*/ */
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
/////////////////////////---CALC DEFINES---////////////////////////// /////////////////////////---CALC DEFINES---//////////////////////////
@@ -356,7 +472,7 @@ uint8_t MB_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg);
#ifndef Trace_MB_UART_Enter #ifndef Trace_MB_UART_Enter
#define Trace_MB_UART_Enter() #define Trace_MB_UART_Enter()
#endif //Trace_MB_UART_Enter #endif //Trace_MB_UART_Enter
#ifndef Trace_MB_UART_Exit #ifndef Trace_MB_UART_Exit
#define Trace_MB_UART_Exit() #define Trace_MB_UART_Exit()
#endif //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 #ifndef Trace_MB_TIM_Enter
#define Trace_MB_TIM_Enter() #define Trace_MB_TIM_Enter()
#endif //Trace_MB_TIM_Enter #endif //Trace_MB_TIM_Enter
#ifndef Trace_MB_TIM_Exit #ifndef Trace_MB_TIM_Exit
#define Trace_MB_TIM_Exit() #define Trace_MB_TIM_Exit()
#endif //Trace_MB_TIM_Exit #endif //Trace_MB_TIM_Exit

View File

@@ -8,8 +8,8 @@
#include "stm32f1xx_hal.h" #include "stm32f1xx_hal.h"
// MODBUS PARAMS // MODBUS PARAMS
#define MODBUS_DEVICE_ID 1 ///< девайс текущего устройства #define MODBUS_DEVICE_ID 1 ///< девайс текущего устройства
#define MODBUS_TIMEOUT 5000 ///< максимальнйы тайтаут MB в тиках таймера #define MODBUS_TIMEOUT 5000 ///< максимальнйы тайтаут MB в тиках таймера
// STRING OBJECTS MODBUS // STRING OBJECTS MODBUS
#define MODBUS_VENDOR_NAME "NIO-12" #define MODBUS_VENDOR_NAME "NIO-12"
@@ -19,14 +19,15 @@
#define MODBUS_PRODUCT_NAME "" #define MODBUS_PRODUCT_NAME ""
#define MODBUS_MODEL_NAME "STM32F103" #define MODBUS_MODEL_NAME "STM32F103"
#define MODBUS_USER_APPLICATION_NAME "" #define MODBUS_USER_APPLICATION_NAME ""
#define MODBUS_NUMB_OF_USEROBJECTS 0
// PERIPH FUNCTIONS AND HANDLERS // PERIPH FUNCTIONS AND HANDLERS
#define RS_UART_Init MX_USART1_UART_Init //инициализация uart #define RS_UART_Init MX_USART1_UART_Init //инициализация uart
#define RS_UART_DeInit HAL_UART_MspDeInit //деинициализация uart #define RS_UART_DeInit HAL_UART_MspDeInit //деинициализация uart
#define RS_TIM_Init MX_TIM3_Init //инициализация таймера #define RS_TIM_Init MX_TIM3_Init //инициализация таймера
#define RS_TIM_DeInit HAL_TIM_Base_MspDeInit//деинициализация таймера #define RS_TIM_DeInit HAL_TIM_Base_MspDeInit//деинициализация таймера
#define rs_huart huart1 //используемый uart #define rs_huart huart1 //используемый uart
#define rs_htim htim3 //используемый таймера #define rs_htim htim3 //используемый таймера
/** /**

View File

@@ -29,10 +29,10 @@
При добавлении новых массивов регистров, необходимо их добавить в функцию MB_DefineRegistersAddress При добавлении новых массивов регистров, необходимо их добавить в функцию MB_DefineRegistersAddress
if(MB_Check_Address_For_Arr(Addr, Qnt, R_<NEW_ARRAY>_ADDR, R_<NEW_ARRAY>_QNT) == NO_ERRORS) if(MB_Check_Address_For_Arr(Addr, Qnt, R_<NEW_ARRAY>_ADDR, R_<NEW_ARRAY>_QNT) == NO_ERRORS)
{ {
*pRegs = MB_Set_Register_Ptr(&<NEW_ARRAY>, Addr); // начало регистров хранения/входных *pRegs = MB_Set_Register_Ptr(&<NEW_ARRAY>, Addr); // начало регистров хранения/входных
} }
@endverbatim @endverbatim
* @{ * @{
*/ */
@@ -43,7 +43,7 @@
*/ */
typedef struct //MB_DataInRegsTypeDef typedef struct //MB_DataInRegsTypeDef
{ {
uint16_t in[16];
}MB_DataInRegsTypeDef; }MB_DataInRegsTypeDef;
@@ -52,17 +52,17 @@ typedef struct //MB_DataInRegsTypeDef
*/ */
typedef struct //MB_DataInRegsTypeDef typedef struct //MB_DataInRegsTypeDef
{ {
uint16_t out[16];
}MB_DataHoldRegsTypeDef; }MB_DataHoldRegsTypeDef;
// DEFINES FOR INPUT REGISTERS ARRAYS // DEFINES FOR INPUT REGISTERS ARRAYS
#define R_INPUT_ADDR 0 #define R_INPUT_ADDR 0
#define R_INPUT_QNT 0 #define R_INPUT_QNT 16
// DEFINES FOR HOLDING REGISTERS ARRAYS // DEFINES FOR HOLDING REGISTERS ARRAYS
#define R_HOLDING_ADDR 0 #define R_HOLDING_ADDR 0
#define R_HOLDING_QNT 0 #define R_HOLDING_QNT 16
/** MODBUS_DATA_RERISTERS_DEFINES /** MODBUS_DATA_RERISTERS_DEFINES
@@ -128,32 +128,6 @@ typedef struct // tester modbus data
extern MB_DataStructureTypeDef MB_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_ #endif //_MODBUS_DATA_H_
///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////

View File

@@ -27,27 +27,27 @@
@verbatim @verbatim
//-------------------Функции-------------------// //-------------------Функции-------------------//
Functions: users Functions: users
- RS_Parse_Message/RS_Collect_Message Заполнение структуры сообщения и буфера - RS_Parse_Message/RS_Collect_Message Заполнение структуры сообщения и буфера
- RS_Response Ответ на сообщение - RS_Response Ответ на сообщение
- RS_Define_Size_of_RX_Message Определение размера принимаемых данных - RS_Define_Size_of_RX_Message Определение размера принимаемых данных
Functions: general Functions: general
- RS_Receive_IT Ожидание комманды и ответ на неё - RS_Receive_IT Ожидание комманды и ответ на неё
- RS_Transmit_IT Отправление комманды и ожидание ответа - RS_Transmit_IT Отправление комманды и ожидание ответа
- RS_Init Инициализация переферии и структуры для RS - RS_Init Инициализация переферии и структуры для RS
- RS_ReInit_UART Реинициализация UART для RS - RS_ReInit_UART Реинициализация UART для RS
- RS_Abort Отмена приема/передачи по ЮАРТ - RS_Abort Отмена приема/передачи по ЮАРТ
- RS_Init Инициализация периферии и modbus handler - RS_Init Инициализация периферии и modbus handler
Functions: callback/handler Functions: callback/handler
- RS_Handle_Receive_Start Функция для запуска приема или остановки RS - RS_Handle_Receive_Start Функция для запуска приема или остановки RS
- RS_Handle_Transmit_Start Функция для запуска передачи или остановки RS - RS_Handle_Transmit_Start Функция для запуска передачи или остановки RS
- RS_UART_RxCpltCallback Коллбек при окончании приема или передачи - RS_UART_RxCpltCallback Коллбек при окончании приема или передачи
RS_UART_TxCpltCallback RS_UART_TxCpltCallback
- RS_UART_Handler Обработчик прерывания для UART - RS_UART_Handler Обработчик прерывания для UART
- RS_TIM_Handler Обработчик прерывания для TIM - RS_TIM_Handler Обработчик прерывания для TIM
@endverbatim @endverbatim
*************************************************************************/ *************************************************************************/
@@ -63,213 +63,218 @@ extern void RS_TIM_DeInit(TIM_HandleTypeDef *htim);
//------------------------------------------------------------------- //-------------------------------------------------------------------
//-------------------------GENERAL FUNCTIONS------------------------- //-------------------------GENERAL FUNCTIONS-------------------------
/** /**
* @brief Start receive IT. * @brief Start receive IT.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @param RS_msg - указатель на структуру сообщения. * @param RS_msg - указатель на структуру сообщения.
* @return RS_RES - статус о состоянии RS после инициализации приема. * @return RS_RES - статус о состоянии RS после инициализации приема.
*/ */
RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
{ {
RS_StatusTypeDef RS_RES = 0; RS_StatusTypeDef RS_RES = 0;
HAL_StatusTypeDef uart_res = 0; HAL_StatusTypeDef uart_res = 0;
//-------------CHECK RS LINE---------------- //-------------CHECK RS LINE----------------
// check that receive isnt busy // check that receive isnt busy
if( RS_Is_RX_Busy(hRS) ) // if tx busy - return busy status if( RS_Is_RX_Busy(hRS) ) // if tx busy - return busy status
return RS_BUSY; return RS_BUSY;
//-----------INITIALIZE RECEIVE------------- //-----------INITIALIZE RECEIVE-------------
// if all OK: start receiving // if all OK: start receiving
RS_EnableReceive(); RS_EnableReceive();
RS_Set_Busy(hRS); // set RS busy RS_Set_Busy(hRS); // set RS busy
RS_Set_RX_Flags(hRS); // initialize flags for receive RS_Set_RX_Flags(hRS); // initialize flags for receive
hRS->pMessagePtr = RS_msg; // set pointer to message structire for filling it from UARTHandler fucntions hRS->pMessagePtr = RS_msg; // set pointer to message structire for filling it from UARTHandler fucntions
// start receiving // start receiving
uart_res = HAL_UART_Receive_IT(hRS->huart, hRS->pBufferPtr, RX_FIRST_PART_SIZE); // receive until ByteCnt+1 byte, __HAL_UART_ENABLE_IT(hRS->huart, UART_IT_IDLE);
// then in Callback restart receive for rest bytes 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) // 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_RES = RS_OK; RS_RES = RS_Abort(hRS, ABORT_RS);
printf_rs("\n%d: RS: Start Receiving...", uwTick); printf_rs_err("Failed to start RS receiving...");
TrackerCnt_Err(hRS->rs_err);
} }
else
hRS->RS_STATUS = RS_RES; {
return RS_RES; // returns result of receive init 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. * @brief Start transmit IT.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @param RS_msg - указатель на структуру сообщения. * @param RS_msg - указатель на структуру сообщения.
* @return RS_RES - статус о состоянии RS после инициализации передачи. * @return RS_RES - статус о состоянии RS после инициализации передачи.
*/ */
RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
{ {
RS_StatusTypeDef RS_RES = 0; RS_StatusTypeDef RS_RES = 0;
HAL_StatusTypeDef uart_res = 0; HAL_StatusTypeDef uart_res = 0;
//-------------CHECK RS LINE---------------- //-------------CHECK RS LINE----------------
// check that transmit isnt busy // check that transmit isnt busy
if( RS_Is_TX_Busy(hRS) ) // if tx busy - return busy status if( RS_Is_TX_Busy(hRS) ) // if tx busy - return busy status
return RS_BUSY; return RS_BUSY;
// check receive line // check receive line
//------------COLLECT MESSAGE--------------- //------------COLLECT MESSAGE---------------
RS_RES = RS_Collect_Message(hRS, RS_msg, hRS->pBufferPtr); 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 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 {// need collect message status, so doesnt write abort to RS_RES
RS_Abort(hRS, ABORT_RS); RS_Abort(hRS, ABORT_RS);
RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); // restart receive RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); // restart receive
} }
else // if collect successful else // if collect successful
{ {
//----------INITIALIZE TRANSMIT------------- //----------INITIALIZE TRANSMIT-------------
RS_EnableTransmit(); RS_EnableTransmit();
// for(int i = 0; i < hRS->sRS_Timeout; i++); // for(int i = 0; i < hRS->sRS_Timeout; i++);
RS_Set_Busy(hRS); // set RS busy RS_Set_Busy(hRS); // set RS busy
RS_Set_TX_Flags(hRS); // initialize flags for transmit IT RS_Set_TX_Flags(hRS); // initialize flags for transmit IT
hRS->pMessagePtr = RS_msg; // set pointer for filling given structure from UARTHandler fucntion hRS->pMessagePtr = RS_msg; // set pointer for filling given structure from UARTHandler fucntion
// if all OK: start transmitting // if all OK: start transmitting
uart_res = HAL_UART_Transmit_IT(hRS->huart, hRS->pBufferPtr, hRS->RS_Message_Size); uart_res = HAL_UART_Transmit_IT(hRS->huart, hRS->pBufferPtr, hRS->RS_Message_Size);
// if transmit isnt started - abort RS // if transmit isnt started - abort RS
if(uart_res != HAL_OK) if(uart_res != HAL_OK)
{ {
RS_RES = RS_Abort(hRS, ABORT_RS); RS_RES = RS_Abort(hRS, ABORT_RS);
printf_rs_err("\n%d: Error RS: Failed to start RS transmitting...", uwTick); printf_rs_err("Failed to start RS transmitting...");
TrackerCnt_Err(hRS->rs_err);
} }
else else
{ {
RS_RES = RS_OK; 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; hRS->RS_STATUS = RS_RES;
return RS_RES; // returns result of transmit init return RS_RES; // returns result of transmit init
} }
/** /**
* @brief Initialize UART and handle RS stucture. * @brief Initialize UART and handle RS stucture.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @param suart - указатель на структуру с настройками UART. * @param suart - указатель на структуру с настройками UART.
* @param stim - указатель на структуру с настройками таймера. * @param stim - указатель на структуру с настройками таймера.
* @param pRS_BufferPtr - указатель на буффер для приема-передачи по UART. Если он NULL, то поставиться библиотечный буфер. * @param pRS_BufferPtr - указатель на буффер для приема-передачи по UART. Если он NULL, то поставиться библиотечный буфер.
* @return RS_RES - статус о состоянии RS после инициализации. * @return RS_RES - статус о состоянии RS после инициализации.
* @note Инициализация перефирии и структуры для приема-передачи по RS. * @note Инициализация перефирии и структуры для приема-передачи по RS.
*/ */
RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr) RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr)
{ {
// check that hRS is defined // check that hRS is defined
if (hRS == NULL) if (hRS == NULL)
return RS_ERR; return RS_ERR;
// check that huart is defined // check that huart is defined
if (huart == NULL) if (huart == NULL)
return RS_ERR; return RS_ERR;
// init uart // init uart
// RS_UART_Init(); // RS_UART_Init();
hRS->huart = huart; hRS->huart = huart;
// RS_TIM_Init(); // RS_TIM_Init();
hRS->htim = htim; hRS->htim = htim;
if (hRS->sRS_RX_Size_Mode == NULL) if (hRS->sRS_RX_Size_Mode == NULL)
return RS_ERR; return RS_ERR;
// check that buffer is defined // check that buffer is defined
if (hRS->pBufferPtr == NULL) if (hRS->pBufferPtr == NULL)
{ {
hRS->pBufferPtr = RS_Buffer; // if no - set default hRS->pBufferPtr = RS_Buffer; // if no - set default
} }
else else
hRS->pBufferPtr = pRS_BufferPtr; // if yes - set by user hRS->pBufferPtr = pRS_BufferPtr; // if yes - set by user
return RS_OK; return RS_OK;
} }
/** /**
* @brief ReInitialize UART and RS receive. * @brief ReInitialize UART and RS receive.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @param suart - указатель на структуру с настройками UART. * @param suart - указатель на структуру с настройками UART.
* @return RS_RES - статус о состоянии RS после инициализации. * @return RS_RES - статус о состоянии RS после инициализации.
* @note Реинициализация UART и приема по RS. * @note Реинициализация UART и приема по RS.
*/ */
HAL_StatusTypeDef RS_ReInit_UART(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart) HAL_StatusTypeDef RS_ReInit_UART(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart)
{ {
HAL_StatusTypeDef RS_RES; HAL_StatusTypeDef RS_RES;
hRS->f.ReInit_UART = 0; hRS->f.ReInit_UART = 0;
// // check is settings are valid
// if(Check_UART_Init_Struct(suart) != HAL_OK)
// return HAL_ERROR;
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_UART_Init();
RS_Receive_IT(hRS, hRS->pMessagePtr); RS_Receive_IT(hRS, hRS->pMessagePtr);
return RS_RES; return RS_RES;
} }
/** /**
* @brief Abort RS/UART. * @brief Abort RS/UART.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @param AbortMode - выбор, что надо отменить. * @param AbortMode - выбор, что надо отменить.
- ABORT_TX: Отмена передачи по ЮАРТ, с очищением флагов TX, - ABORT_TX: Отмена передачи по ЮАРТ, с очищением флагов TX,
- ABORT_RX: Отмена приема по ЮАРТ, с очищением флагов RX, - ABORT_RX: Отмена приема по ЮАРТ, с очищением флагов RX,
- ABORT_RX_TX: Отмена приема и передачи по ЮАРТ, - ABORT_RX_TX: Отмена приема и передачи по ЮАРТ,
- ABORT_RS: Отмена приема-передачи RS, с очищением всей структуры. - ABORT_RS: Отмена приема-передачи RS, с очищением всей структуры.
* @return RS_RES - статус о состоянии RS после аборта. * @return RS_RES - статус о состоянии RS после аборта.
* @note Отмена работы UART в целом или отмена приема/передачи RS. * @note Отмена работы UART в целом или отмена приема/передачи RS.
Также очищается хендл hRS. Также очищается хендл hRS.
*/ */
RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode) 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; hRS->htim->Instance->CNT = 0;
__HAL_TIM_CLEAR_IT(hRS->htim, TIM_IT_UPDATE); __HAL_TIM_CLEAR_IT(hRS->htim, TIM_IT_UPDATE);
if(hRS->sRS_Timeout) // if timeout setted if((AbortMode&ABORT_RS) == 0x00)
HAL_TIM_Base_Stop_IT(hRS->htim); // stop timeout {
if((AbortMode&ABORT_RX) == ABORT_RX)
if((AbortMode&ABORT_RS) == 0x00) {
{ uart_res = HAL_UART_AbortReceive(hRS->huart); // abort receive
if((AbortMode&ABORT_RX) == ABORT_RX) RS_Reset_RX_Flags(hRS);
{ }
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
if((AbortMode&ABORT_TX) == ABORT_TX) RS_Reset_TX_Flags(hRS);
{ }
uart_res = HAL_UART_AbortTransmit(hRS->huart); // abort transmit }
RS_Reset_TX_Flags(hRS); else
} {
} uart_res = HAL_UART_Abort(hRS->huart);
else RS_Clear_All(hRS);
{ }
uart_res = HAL_UART_Abort(hRS->huart); hRS->RS_STATUS = RS_ABORTED;
RS_Clear_All(hRS); return RS_ABORTED;
}
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--------------------- //--------------------CALLBACK/HANDLER FUNCTIONS---------------------
/** /**
* @brief Handle for starting receive. * @brief Handle for starting receive.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @param RS_msg - указатель на структуру сообщения. * @param RS_msg - указатель на структуру сообщения.
* @return RS_RES - статус о состоянии RS после инициализации приема или окончания общения. * @return RS_RES - статус о состоянии RS после инициализации приема или окончания общения.
* @note Определяет начинать прием команды/ответа или нет. * @note Определяет начинать прием команды/ответа или нет.
*/ */
RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
{ {
RS_StatusTypeDef RS_RES = 0; RS_StatusTypeDef RS_RES = 0;
switch(hRS->sRS_Mode) switch(hRS->sRS_Mode)
{ {
case SLAVE_ALWAYS_WAIT: // in slave mode with permanent waiting case SLAVE_ALWAYS_WAIT: // in slave mode with permanent waiting
RS_RES = RS_Receive_IT(hRS, RS_msg); break; // start receiving again 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) 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_Set_Free(hRS); RS_RES = RS_OK; break; // end RS communication (set RS unbusy)
} }
if(RS_RES != RS_OK) if(RS_RES != RS_OK)
{ {
TrackerCnt_Err(hRS->rs_err);
} }
return RS_RES; return RS_RES;
} }
/** /**
* @brief Handle for starting transmit. * @brief Handle for starting transmit.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @param RS_msg - указатель на структуру сообщения. * @param RS_msg - указатель на структуру сообщения.
* @return RS_RES - статус о состоянии RS после инициализации передачи. * @return RS_RES - статус о состоянии RS после инициализации передачи.
* @note Определяет отвечать ли на команду или нет. * @note Определяет отвечать ли на команду или нет.
*/ */
RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
{ {
RS_StatusTypeDef RS_RES = 0; RS_StatusTypeDef RS_RES = 0;
switch(hRS->sRS_Mode) switch(hRS->sRS_Mode)
{ {
case SLAVE_ALWAYS_WAIT: // in slave mode always response case SLAVE_ALWAYS_WAIT: // in slave mode always response
case SLAVE_TIMEOUT_WAIT: // transmit response case SLAVE_TIMEOUT_WAIT: // transmit response
RS_RES = RS_Transmit_IT(hRS, RS_msg); break; RS_RES = RS_Transmit_IT(hRS, RS_msg); break;
} }
if(RS_RES != RS_OK) 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. * @brief UART RX Callback: define behaviour after receiving parts of message.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @return RS_RES - статус о состоянии RS после обработки приема. * @return RS_RES - статус о состоянии RS после обработки приема.
* @note Контролирует прием сообщения: определяет размер принимаемой посылки и обрабатывает его. * @note Контролирует прием сообщения: определяет размер принимаемой посылки и обрабатывает его.
*/ */
RS_StatusTypeDef RS_UART_RxCpltCallback(RS_HandleTypeDef *hRS) RS_StatusTypeDef RS_UART_RxCpltCallback(RS_HandleTypeDef *hRS)
{ {
RS_StatusTypeDef RS_RES = 0; RS_StatusTypeDef RS_RES = 0;
HAL_StatusTypeDef uart_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 // if we had received bytes before ByteCnt
{ // First receive part of message, then define size of rest of message, and start receive it 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
hRS->f.RX_Half = 1; { // First receive part of message, then define size of rest of message, and start receive it
//---------------FIND DATA SIZE----------------- hRS->f.RX_Half = 1;
uint32_t NuRS_of_Rest_Bytes = 0xFFFF; //---------------FIND DATA SIZE-----------------
RS_RES = RS_Define_Size_of_RX_Message(hRS, &NuRS_of_Rest_Bytes); 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;
}
// 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 we need to skip this message - restart receive
if(RS_RES == RS_SKIP || NuRS_of_Rest_Bytes == 0xFFFF)
if(hRS->sRS_Timeout) // if timeout setted {
HAL_TIM_Base_Stop_IT(hRS->htim); // stop timeout RS_Abort(hRS, ABORT_RX);
RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
// parse received data
RS_RES = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr); // parse message
// RESPONSE
RS_RES = RS_Response(hRS, hRS->pMessagePtr);
return RS_RES; return RS_RES;
} }
// if there is no bytes to receive
//-------------START UART RECEIVE--------------- if(NuRS_of_Rest_Bytes != 0)
uart_res = HAL_UART_Receive_IT(hRS->huart, (hRS->pBufferPtr + RX_FIRST_PART_SIZE), NuRS_of_Rest_Bytes); {
//-------------START UART RECEIVE---------------
if(uart_res != HAL_OK) uart_res = HAL_UART_Receive_IT(hRS->huart, (hRS->pBufferPtr + RX_FIRST_PART_SIZE), NuRS_of_Rest_Bytes);
{// 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
// RESPONSE if(uart_res != HAL_OK)
RS_RES = RS_Response(hRS, hRS->pMessagePtr); {// 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. * @brief UART TX Callback: define behaviour after transmiting message.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @return RS_RES - статус о состоянии RS после обработки приема. * @return RS_RES - статус о состоянии RS после обработки приема.
* @note Определяет поведение RS после передачи сообщения. * @note Определяет поведение RS после передачи сообщения.
*/ */
RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS) RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS)
{ {
RS_StatusTypeDef RS_RES = RS_OK; RS_StatusTypeDef RS_RES = RS_OK;
HAL_StatusTypeDef uart_res = 0; HAL_StatusTypeDef uart_res = 0;
//--------------ENDING TRANSMITTING------------- //--------------ENDING TRANSMITTING-------------
RS_Set_TX_End(hRS); RS_Set_TX_End(hRS);
RS_EnableReceive(); RS_EnableReceive();
// for(int i = 0; i < hRS->sRS_Timeout; i++); // for(int i = 0; i < hRS->sRS_Timeout; i++);
//-----------START RECEIVING or END RS---------- //-----------START RECEIVING or END RS----------
RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
return RS_RES; return RS_RES;
} }
/** /**
* @brief Handler for UART. * @brief Handler for UART.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @note Обрабатывает ошибки если есть и вызывает RS Коллбеки. * @note Обрабатывает ошибки если есть и вызывает RS Коллбеки.
* Добавить вызов этой функции в UARTx_IRQHandler() после HAL_UART_IRQHandler(). * Добавить вызов этой функции в UARTx_IRQHandler() после HAL_UART_IRQHandler().
*/ */
void RS_UART_Handler(RS_HandleTypeDef *hRS) void RS_UART_Handler(RS_HandleTypeDef *hRS)
{ {
//-------------CALL RS CALLBACKS------------ //-------------CHECK IDLE FLAG FIRST-------------
/* IF NO ERROR OCCURS */ /* Проверяем флаг IDLE в первую очередь - это гарантирует обработку только после idle */
if(hRS->huart->ErrorCode == 0) if(__HAL_UART_GET_FLAG(hRS->huart, UART_FLAG_IDLE) && __HAL_UART_GET_IT_SOURCE(hRS->huart, UART_IT_IDLE))
{ {
hRS->htim->Instance->CNT = 0; // reset cnt; __HAL_UART_CLEAR_IDLEFLAG(hRS->huart); // Важно: очистить флаг IDLE
/* Start timeout */
if(hRS->sRS_Timeout) // if timeout setted // Если прием активен и мы получили IDLE - это конец фрейма
if((hRS->huart->RxXferCount+1 == hRS->huart->RxXferSize) && RS_Is_RX_Busy(hRS)) // if first byte is received and receive is active 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; // Принудительно завершаем прием (IDLE прервал наш прием)
HAL_TIM_Base_Start_IT(hRS->htim); 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); RS_Set_RX_Active_Flags(hRS);
} }
/* RX Callback */ /* RX Callback - теперь НЕ вызываем здесь, ждем IDLE */
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 /* TX Callback - оставляем без изменений */
RS_UART_RxCpltCallback(hRS); 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
/* TX Callback */ RS_UART_TxCpltCallback(hRS);
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 /* NOTE: RX Callback больше не вызывается здесь - ждем IDLE для гарантии конца фрейма */
RS_UART_TxCpltCallback(hRS); }
} //----------------ERRORS HANDLER----------------
//----------------ERRORS HANDLER---------------- else
else {
{ //TrackerCnt_Err(hRS->rs_err);
/* de-init uart transfer */ /* de-init uart transfer */
RS_Abort(hRS, ABORT_RS); RS_Abort(hRS, ABORT_RS);
RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
// later, maybe, will be added specific handlers for err
} // later, maybe, will be added specific handlers for err
}
} }
/** /**
* @brief Handler for TIM. * @brief Handler for TIM.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @note Попадание сюда = таймаут и перезапуск RS приема * @note Попадание сюда = таймаут и перезапуск RS приема
* Добавить вызов этой функции в TIMx_IRQHandler() после HAL_TIM_IRQHandler(). * Добавить вызов этой функции в TIMx_IRQHandler() после HAL_TIM_IRQHandler().
*/ */
void RS_TIM_Handler(RS_HandleTypeDef *hRS) void RS_TIM_Handler(RS_HandleTypeDef *hRS)
{ {
HAL_TIM_IRQHandler(hRS->htim);
HAL_TIM_Base_Stop_IT(hRS->htim); HAL_TIM_Base_Stop_IT(hRS->htim);
RS_Abort(hRS, ABORT_RS); RS_Abort(hRS, ABORT_RS);
if(hRS->pMessagePtr->MbAddr == hRS->ID) // ошибка если таймаут по нашему сообщению
RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); TrackerCnt_Err(hRS->rs_err);
RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
} }
//--------------------CALLBACK/HANDLER FUNCTIONS--------------------- //--------------------CALLBACK/HANDLER FUNCTIONS---------------------
//------------------------------------------------------------------- //-------------------------------------------------------------------
@@ -494,57 +575,57 @@ void RS_TIM_Handler(RS_HandleTypeDef *hRS)
//------------------------------------------------------------------- //-------------------------------------------------------------------
//--------------WEAK PROTOTYPES FOR PROCESSING MESSAGE--------------- //--------------WEAK PROTOTYPES FOR PROCESSING MESSAGE---------------
/** /**
* @brief Respond accord to received message. * @brief Respond accord to received message.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @param RS_msg - указатель на структуру сообщения. * @param RS_msg - указатель на структуру сообщения.
* @return RS_RES - статус о результате ответа на комманду. * @return RS_RES - статус о результате ответа на комманду.
* @note Обработка принятой комманды и ответ на неё. * @note Обработка принятой комманды и ответ на неё.
*/ */
__weak RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) __weak RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
{ {
/* Redefine function for user purposes */ /* Redefine function for user purposes */
return RS_ERR; return RS_ERR;
} }
/** /**
* @brief Collect message in buffer to transmit it. * @brief Collect message in buffer to transmit it.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @param RS_msg - указатель на структуру сообщения. * @param RS_msg - указатель на структуру сообщения.
* @param msg_uart_buff - указатель на буффер UART. * @param msg_uart_buff - указатель на буффер UART.
* @return RS_RES - статус о результате заполнения буфера. * @return RS_RES - статус о результате заполнения буфера.
* @note Заполнение буффера UART из структуры сообщения. * @note Заполнение буффера UART из структуры сообщения.
*/ */
__weak RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff) __weak RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff)
{ {
/* Redefine function for user purposes */ /* Redefine function for user purposes */
return RS_ERR; return RS_ERR;
} }
/** /**
* @brief Parse message from buffer to process it. * @brief Parse message from buffer to process it.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @param RS_msg - указатель на структуру сообщения. * @param RS_msg - указатель на структуру сообщения.
* @param msg_uart_buff - указатель на буффер UART. * @param msg_uart_buff - указатель на буффер UART.
* @return RS_RES - статус о результате заполнения структуры. * @return RS_RES - статус о результате заполнения структуры.
* @note Заполнение структуры сообщения из буффера UART. * @note Заполнение структуры сообщения из буффера UART.
*/ */
__weak RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff) __weak RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff)
{ {
/* Redefine function for user purposes */ /* Redefine function for user purposes */
return RS_ERR; return RS_ERR;
} }
/** /**
* @brief Define size of RX Message that need to be received. * @brief Define size of RX Message that need to be received.
* @param hRS - указатель на хендлер RS. * @param hRS - указатель на хендлер RS.
* @param rx_data_size - указатель на переменную для записи кол-ва байт для принятия. * @param rx_data_size - указатель на переменную для записи кол-ва байт для принятия.
* @return RS_RES - статус о корректности рассчета кол-ва байт для принятия. * @return RS_RES - статус о корректности рассчета кол-ва байт для принятия.
* @note Определение сколько байтов надо принять по протоколу. * @note Определение сколько байтов надо принять по протоколу.
*/ */
__weak RS_StatusTypeDef RS_Define_Size_of_RX_Message(RS_HandleTypeDef *hRS, uint32_t *rx_data_size) __weak RS_StatusTypeDef RS_Define_Size_of_RX_Message(RS_HandleTypeDef *hRS, uint32_t *rx_data_size)
{ {
/* Redefine function for user purposes */ /* Redefine function for user purposes */
return RS_ERR; return RS_ERR;
} }
//--------------WEAK PROTOTYPES FOR PROCESSING MESSAGE--------------- //--------------WEAK PROTOTYPES FOR PROCESSING MESSAGE---------------
//------------------------------------------------------------------- //-------------------------------------------------------------------

View File

@@ -4,7 +4,7 @@
* @brief Заголовочный файл для модуля реализации протоколов по RS/UART. * @brief Заголовочный файл для модуля реализации протоколов по RS/UART.
************************************************************************** **************************************************************************
* @defgroup RS_TOOLS * @defgroup RS_TOOLS
* @brief Всякое для работы по UART/RS * @brief Всякое для работы по UART/RS
************************************************************************** **************************************************************************
@details @details
************************************************************************** **************************************************************************
@@ -12,9 +12,9 @@
- Определить структуру сообщения RS_MsgTypeDef и - Определить структуру сообщения RS_MsgTypeDef и
дефайны RX_FIRST_PART_SIZE и MSG_SIZE_MAX. дефайны RX_FIRST_PART_SIZE и MSG_SIZE_MAX.
- Подключить этот файл в раздел rs_message.h. - Подключить этот файл в раздел rs_message.h.
- Определить функции для обработки сообщения: RS_Parse_Message(), - Определить функции для обработки сообщения: RS_Parse_Message(),
RS_Collect_Message(), RS_Response(), RS_Define_Size_of_RX_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 "modbus.h"
#include "crc_algs.h"
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
////////////////////////////---DEFINES---//////////////////////////// ////////////////////////////---DEFINES---////////////////////////////
/* Check that all defines required by RS are defined */ /* Check that all defines required by RS are defined */
@@ -43,43 +40,81 @@
/* Clear message-uart buffer */ /* Clear message-uart buffer */
#define RS_Clear_Buff(_buff_) for(int i=0; i<MSG_SIZE_MAX;i++) _buff_[i] = NULL #define RS_Clear_Buff(_buff_) for(int i=0; i<MSG_SIZE_MAX;i++) _buff_[i] = NULL
/* Set/Reset flags */ /* Set/Reset flags */
#define RS_Set_Free(_hRS_) _hRS_->f.RS_Busy = 0 #define RS_Set_Free(_hRS_) _hRS_->f.RS_Busy = 0
#define RS_Set_Busy(_hRS_) _hRS_->f.RS_Busy = 1 #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_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_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_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_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_RX_End_Flag(_hRS_) _hRS_->f.RX_Done = 1;
#define RS_Set_TX_End_Flag(_hRS_) _hRS_->f.TX_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_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_TX_End(_hRS_) RS_Reset_TX_Flags(_hRS_); RS_Set_TX_End_Flag(_hRS_)
/* Clear all RS stuff */ /* 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 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 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 #ifndef RS_EnableReceive
#define RS_EnableReceive() #define RS_EnableReceive()
#endif #endif
#ifndef RS_EnableTransmit #ifndef RS_EnableTransmit
#define RS_EnableTransmit() #define RS_EnableTransmit()
#endif #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---//////////////////////////// ////////////////////////////---DEFINES---////////////////////////////
@@ -88,52 +123,52 @@
///////////////////////---STRUCTURES & ENUMS---////////////////////// ///////////////////////---STRUCTURES & ENUMS---//////////////////////
//------------------ENUMERATIONS-------------------- //------------------ENUMERATIONS--------------------
/** @brief Enums for respond CMD about RS status */ /** @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)*/ /* IN-CODE STATUS (start from 0x01, and goes up)*/
/*0x01*/ RS_OK = 0x01, /*0x01*/ RS_OK = 0x01,
/*0x02*/ RS_ERR, /*0x02*/ RS_ERR,
/*0x03*/ RS_ABORTED, /*0x03*/ RS_ABORTED,
/*0x04*/ RS_BUSY, /*0x04*/ RS_BUSY,
/*0x05*/ RS_SKIP, /*0x05*/ RS_SKIP,
/*0x06*/ RS_COLLECT_MSG_ERR, /*0x06*/ RS_COLLECT_MSG_ERR,
/*0x07*/ RS_PARSE_MSG_ERR, /*0x07*/ RS_PARSE_MSG_ERR,
// reserved values // reserved values
// /*0x00*/ RS_UNKNOWN_ERR = 0x00, ///< reserved for case, if no one error founded (nothing changed response from zero) // /*0x00*/ RS_UNKNOWN_ERR = 0x00, ///< reserved for case, if no one error founded (nothing changed response from zero)
}RS_StatusTypeDef; }RS_StatusTypeDef;
/** @brief Enums for RS Modes */ /** @brief Enums for RS Modes */
typedef enum // RS_ModeTypeDef typedef enum // RS_ModeTypeDef
{ {
SLAVE_ALWAYS_WAIT = 0x01, ///< Slave mode with infinity waiting SLAVE_ALWAYS_WAIT = 0x01, ///< Slave mode with infinity waiting
SLAVE_TIMEOUT_WAIT = 0x02, ///< Slave mode with waiting with timeout SLAVE_TIMEOUT_WAIT = 0x02, ///< Slave mode with waiting with timeout
// MASTER = 0x03, ///< Master mode // MASTER = 0x03, ///< Master mode
}RS_ModeTypeDef; }RS_ModeTypeDef;
/** @brief Enums for RS UART Modes */ /** @brief Enums for RS UART Modes */
typedef enum // RS_ITModeTypeDef typedef enum // RS_ITModeTypeDef
{ {
BLCK_MODE = 0x00, ///< Blocking mode BLCK_MODE = 0x00, ///< Blocking mode
IT_MODE = 0x01, ///< Interrupt mode IT_MODE = 0x01, ///< Interrupt mode
}RS_ITModeTypeDef; }RS_ITModeTypeDef;
/** @brief Enums for Abort modes */ /** @brief Enums for Abort modes */
typedef enum // RS_AbortTypeDef typedef enum // RS_AbortTypeDef
{ {
ABORT_TX = 0x01, ///< Abort transmit ABORT_TX = 0x01, ///< Abort transmit
ABORT_RX = 0x02, ///< Abort receive ABORT_RX = 0x02, ///< Abort receive
ABORT_RX_TX = 0x03, ///< Abort receive and transmit ABORT_RX_TX = 0x03, ///< Abort receive and transmit
ABORT_RS = 0x04, ///< Abort uart and reset RS structure ABORT_RS = 0x04, ///< Abort uart and reset RS structure
}RS_AbortTypeDef; }RS_AbortTypeDef;
/** @brief Enums for RX Size modes */ /** @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_Const = 0x01, ///< size of receiving message is constant
RS_RX_Size_NotConst = 0x02, ///< size of receiving message isnt constant RS_RX_Size_NotConst = 0x02, ///< size of receiving message isnt constant
}RS_RXSizeTypeDef; }RS_RXSizeTypeDef;
@@ -141,51 +176,55 @@ typedef enum // RS_RXSizeTypeDef
/** @brief Struct for flags RS */ /** @brief Struct for flags RS */
typedef struct typedef struct
{ {
unsigned RX_Half:1; ///< flag: 0 - receiving msg before ByteCnt, 0 - receiving msg after ByteCnt 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_Busy:1; ///< flag: 1 - receiving is active, 0 - receiving isnt active unsigned RS_Busy:1; ///< flag: 1 - RS is busy, 0 - RS isnt busy
unsigned TX_Busy:1; ///< flag: 1 - transmiting is active, 0 - transmiting isnt active unsigned RX_Ongoing:1; ///< flag: 1 - receiving data right now, 0 - waiting for receiving data
unsigned RX_Done:1; ///< flag: 1 - receiving is done, 0 - receiving isnt done unsigned RX_Busy:1; ///< flag: 1 - receiving is active, 0 - receiving isnt active
unsigned TX_Done:1; ///< flag: 1 - transmiting is done, 0 - transmiting isnt done unsigned TX_Busy:1; ///< flag: 1 - transmiting is active, 0 - transmiting isnt active
// setted by user unsigned RX_Done:1; ///< flag: 1 - receiving is done, 0 - receiving isnt done
unsigned MessageHandled:1; ///< flag: 1 - RS command is handled, 0 - RS command isnt handled yet unsigned TX_Done:1; ///< flag: 1 - transmiting is done, 0 - transmiting isnt done
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 // setted by user
unsigned ReInit_UART:1; ///< flag: 1 - need to reinitialize uart, 0 - nothing 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; }RS_FlagsTypeDef;
/** /**
* @brief Handle for RS communication. * @brief Handle for RS communication.
* @note Prefixes: h - handle, s - settings, f - flag * @note Prefixes: h - handle, s - settings, f - flag
*/ */
typedef struct // RS_HandleTypeDef typedef struct // RS_HandleTypeDef
{ {
/* MESSAGE */ /* MESSAGE */
uint8_t ID; ///< ID of RS "channel" uint8_t ID; ///< ID of RS "channel"
RS_MsgTypeDef *pMessagePtr; ///< pointer to message struct RS_MsgTypeDef *pMessagePtr; ///< pointer to message struct
uint8_t *pBufferPtr; ///< pointer to message buffer uint8_t *pBufferPtr; ///< pointer to message buffer
uint32_t RS_Message_Size; ///< size of whole message, not only data 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
/* RS STATUS */ /* HANDLERS and SETTINGS */
RS_StatusTypeDef RS_STATUS; ///< RS status 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; }RS_HandleTypeDef;
extern RS_HandleTypeDef hmodbus1; extern RS_HandleTypeDef hmodbus1;
@@ -247,11 +286,5 @@ void RS_TIM_Handler(RS_HandleTypeDef *hRS);
///////////////////////////---FUNCTIONS---/////////////////////////// ///////////////////////////---FUNCTIONS---///////////////////////////
#ifndef printf_rs_err
#define printf_rs_err(...)
#endif
#ifndef printf_rs
#define printf_rs(...)
#endif
#endif // __RS_LIB_H_ #endif // __RS_LIB_H_