Пока не рабоатет
This commit is contained in:
		
						commit
						2317b904ba
					
				
							
								
								
									
										23
									
								
								Arduino_Modbus.ino
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								Arduino_Modbus.ino
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					#include "rs_message.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void setup() {
 | 
				
			||||||
 | 
					  // put your setup code here, to run once:
 | 
				
			||||||
 | 
					  // Пример: RX=16, TX=17, скорость 115200
 | 
				
			||||||
 | 
					  rs_huart.begin(115200, SERIAL_8N1, 8, 9);
 | 
				
			||||||
 | 
					  rs_huart.println("start1");
 | 
				
			||||||
 | 
					  MODBUS_FirstInit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Serial.begin(115200); // для отладки
 | 
				
			||||||
 | 
					  Serial.println("start");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void loop() {
 | 
				
			||||||
 | 
					  // put your main code here, to run repeatedly:
 | 
				
			||||||
 | 
					  RS_UART_Handler(&hmodbus1); // нужно вызывать периодически
 | 
				
			||||||
 | 
					  RS_TIM_Handler(&hmodbus1);  // проверка таймаута
 | 
				
			||||||
 | 
					  //delay(500);
 | 
				
			||||||
 | 
					  //Serial.println("start");
 | 
				
			||||||
 | 
					  //rs_huart.println("start1");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										116
									
								
								crc_algs.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								crc_algs.cpp
									
									
									
									
									
										Normal 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;
 | 
				
			||||||
 | 
					} 
 | 
				
			||||||
							
								
								
									
										14
									
								
								crc_algs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								crc_algs.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CRC_ALGS_H
 | 
				
			||||||
 | 
					#define CRC_ALGS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern uint32_t CRC_calc;
 | 
				
			||||||
 | 
					extern uint32_t CRC_ref;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint16_t crc16(uint8_t *data, uint32_t data_size);
 | 
				
			||||||
 | 
					uint32_t crc32(uint8_t *data, uint32_t data_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										954
									
								
								modbus.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										954
									
								
								modbus.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,954 @@
 | 
				
			|||||||
 | 
					/** 
 | 
				
			||||||
 | 
					**************************************************************************
 | 
				
			||||||
 | 
					* @file 	modbus.c
 | 
				
			||||||
 | 
					* @brief 	Модуль для реализации MODBUS.
 | 
				
			||||||
 | 
					**************************************************************************	
 | 
				
			||||||
 | 
					* @details Файл содержит реализацию функций работы с Modbus, включая:
 | 
				
			||||||
 | 
					*          - доступ к coils и registers;
 | 
				
			||||||
 | 
					*          - обработку команд протокола;
 | 
				
			||||||
 | 
					*          - взаимодействие с RS (UART);
 | 
				
			||||||
 | 
					*          - инициализацию.
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* @section Функции и макросы
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* ### Доступ к coils:
 | 
				
			||||||
 | 
					* - MB_Set_Coil_Local()        — Установить coil по локальному адресу.
 | 
				
			||||||
 | 
					* - MB_Reset_Coil_Local()      — Сбросить coil по локальному адресу.
 | 
				
			||||||
 | 
					* - MB_Toogle_Coil_Local()     — Инвертировать coil по локальному адресу.
 | 
				
			||||||
 | 
					* - MB_Read_Coil_Local()       — Прочитать coil по локальному адресу.
 | 
				
			||||||
 | 
					* - MB_Write_Coil_Global()     — Установить/сбросить coil по глобальному адресу.
 | 
				
			||||||
 | 
					* - MB_Read_Coil_Global()      — Прочитать coil по глобальному адресу.
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* ### Обработка команд Modbus:
 | 
				
			||||||
 | 
					* - MB_DefineRegistersAddress() — Определить начальный адрес регистра.
 | 
				
			||||||
 | 
					* - MB_DefineCoilsAddress()     — Определить начальный адрес coils.
 | 
				
			||||||
 | 
					* - MB_Check_Address_For_Arr()  — Проверить, принадлежит ли адрес массиву.
 | 
				
			||||||
 | 
					* - Основные команды Modbus:
 | 
				
			||||||
 | 
					*    - MB_Read_Coils()
 | 
				
			||||||
 | 
					*    - MB_Read_Hold_Regs()
 | 
				
			||||||
 | 
					*    - MB_Write_Single_Coil()
 | 
				
			||||||
 | 
					*    - MB_Write_Miltuple_Coils()
 | 
				
			||||||
 | 
					*    - MB_Write_Miltuple_Regs()
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* ### Функции для работы с RS (UART):
 | 
				
			||||||
 | 
					* - RS_Parse_Message() / RS_Collect_Message() — Парсинг и сборка сообщения.
 | 
				
			||||||
 | 
					* - RS_Response()                             — Отправка ответа.
 | 
				
			||||||
 | 
					* - RS_Define_Size_of_RX_Message()            — Определение размера принимаемого сообщения.
 | 
				
			||||||
 | 
					* - RS_Init()                                 — Инициализация UART.
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* ### Инициализация:
 | 
				
			||||||
 | 
					* - MODBUS_FirstInit()                        — Инициализация модуля Modbus.
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* @section Структура данных Modbus
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* #### Holding/Input Registers:
 | 
				
			||||||
 | 
					* - Регистры — 16-битные слова. Доступ к регистрам осуществляется через указатель.	
 | 
				
			||||||
 | 
					* Таким образом, сами регистры могут представлять собой как массив так и структуру.
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* #### Coils:
 | 
				
			||||||
 | 
					* - Coils — это биты, упакованные в 16-битные слова. Доступ к коилам осуществляется через указатель.	
 | 
				
			||||||
 | 
					* Таким образом, сами коилы могут представлять собой как массив так и структуру.
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* @section Инструкция по подключению
 | 
				
			||||||
 | 
					* Для корректной работы надо подключить обработчики RS_UART_Handler(), RS_TIM_Handler(),
 | 
				
			||||||
 | 
					* в соответствубщие низкоуровневые прерывания UART_IRQHandler, TIM_IRQHandler. После HAL'овского обработчика
 | 
				
			||||||
 | 
					* 
 | 
				
			||||||
 | 
					* Также необходимо в modbus_config.h настроить дефайны для нужной работы UART
 | 
				
			||||||
 | 
					* После для запуска Modbus:
 | 
				
			||||||
 | 
					* @verbatim
 | 
				
			||||||
 | 
					  //----------------Прием модбас----------------//
 | 
				
			||||||
 | 
					  #include "rs_message.h"
 | 
				
			||||||
 | 
					  MODBUS_FirstInit();
 | 
				
			||||||
 | 
					  RS_Receive_IT(&hmodbus1, &MODBUS_MSG);
 | 
				
			||||||
 | 
					* @endverbatim
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					******************************************************************************/
 | 
				
			||||||
 | 
					#include "crc_algs.h"
 | 
				
			||||||
 | 
					#include "rs_message.h"
 | 
				
			||||||
 | 
					uint32_t dbg_temp, dbg_temp2, dbg_temp3; // for debug
 | 
				
			||||||
 | 
					RS_HandleTypeDef hmodbus1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* DEFINE REGISTERS/COILS */
 | 
				
			||||||
 | 
					MB_DeviceIdentificationTypeDef MB_INFO;
 | 
				
			||||||
 | 
					MB_DataStructureTypeDef MB_DATA;
 | 
				
			||||||
 | 
					RS_MsgTypeDef MODBUS_MSG;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//-------------------------------------------------------------------
 | 
				
			||||||
 | 
					//-----------------------------FOR USER------------------------------
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 		First set up of MODBUS.
 | 
				
			||||||
 | 
						* @details 	Первый инит модбас. Заполняет структуры и инициализирует таймер и юарт для общения по модбас.
 | 
				
			||||||
 | 
						* @note			This called from main
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					void MODBUS_FirstInit(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  MB_DevoceInentificationInit();
 | 
				
			||||||
 | 
						//-----------SETUP MODBUS-------------
 | 
				
			||||||
 | 
						// set up modbus: MB_RX_Size_NotConst and Timeout enable
 | 
				
			||||||
 | 
						hmodbus1.ID = MODBUS_DEVICE_ID;
 | 
				
			||||||
 | 
					  hmodbus1.sRS_Timeout = MODBUS_TIMEOUT;
 | 
				
			||||||
 | 
						hmodbus1.sRS_Mode = SLAVE_ALWAYS_WAIT;
 | 
				
			||||||
 | 
						hmodbus1.sRS_RX_Size_Mode = RS_RX_Size_NotConst;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// INIT
 | 
				
			||||||
 | 
						hmodbus1.RS_STATUS = RS_Init(&hmodbus1, &rs_huart, 0);	
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RS_EnableReceive();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 		Set or Reset Coil at its global address.
 | 
				
			||||||
 | 
						* @param 		Addr 					- адрес коила.
 | 
				
			||||||
 | 
						* @param 		WriteVal 			- Что записать в коил: 0 или 1.
 | 
				
			||||||
 | 
						* @return 	ExceptionCode	- Код исключения если коила по адресу не существует, и NO_ERRORS если все ок.
 | 
				
			||||||
 | 
						*
 | 
				
			||||||
 | 
					  * @details 	Позволяет обратиться к любому коилу по его глобальному адрессу.
 | 
				
			||||||
 | 
												Вне зависимости от того как коилы размещены в памяти.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//---------CHECK FOR ERRORS----------
 | 
				
			||||||
 | 
						MB_ExceptionTypeDef Exception = NO_ERRORS;
 | 
				
			||||||
 | 
						uint16_t *coils;
 | 
				
			||||||
 | 
						uint16_t start_shift = 0; // shift in coils register
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//------------WRITE COIL-------------
 | 
				
			||||||
 | 
						Exception = MB_DefineCoilsAddress(&coils, Addr, 1, &start_shift, 1);
 | 
				
			||||||
 | 
						if(Exception == NO_ERRORS)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							switch(WriteVal)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								case SET_COIL:
 | 
				
			||||||
 | 
									*coils |= (1<<start_shift);				
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
								case RESET_COIL:
 | 
				
			||||||
 | 
									*coils &= ~(1<<start_shift);					
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
								case TOOGLE_COIL:
 | 
				
			||||||
 | 
									*coils ^= (1<<start_shift);						
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							}		
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return Exception;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 		Read Coil at its global address.
 | 
				
			||||||
 | 
						* @param 		Addr 					- адрес коила.
 | 
				
			||||||
 | 
						* @param 		Exception 		- Указатель на переменную для кода исключения, в случа неудачи при чтении.
 | 
				
			||||||
 | 
						* @return 	uint16_t			- Возвращает весь регистр с маской на запрошенном коиле.
 | 
				
			||||||
 | 
						*
 | 
				
			||||||
 | 
					  * @details 	Позволяет обратиться к любому коилу по его глобальному адрессу.
 | 
				
			||||||
 | 
												Вне зависимости от того как коилы размещены в памяти.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//---------CHECK FOR ERRORS----------
 | 
				
			||||||
 | 
						MB_ExceptionTypeDef Exception_tmp;
 | 
				
			||||||
 | 
						if(Exception == NULL)							// if exception is not given to func fill it
 | 
				
			||||||
 | 
							Exception = &Exception_tmp;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						uint16_t *coils;
 | 
				
			||||||
 | 
						uint16_t start_shift = 0; // shift in coils register
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//------------READ COIL--------------
 | 
				
			||||||
 | 
						*Exception = MB_DefineCoilsAddress(&coils, Addr, 1, &start_shift, 0);	
 | 
				
			||||||
 | 
						if(*Exception == NO_ERRORS)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return ((*coils)&(1<<start_shift));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//-------------------------------------------------------------------
 | 
				
			||||||
 | 
					//----------------FUNCTIONS FOR PROCESSING MESSAGE-------------------
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 		Check is address valid for certain array.
 | 
				
			||||||
 | 
						* @param 		Addr 					- начальный адресс.
 | 
				
			||||||
 | 
						* @param 		Qnt 					- количество запрашиваемых элементов.
 | 
				
			||||||
 | 
						* @param 		R_ARR_ADDR 		- начальный адресс массива R_ARR.
 | 
				
			||||||
 | 
						* @param 		R_ARR_NUMB 		- количество элементов в массиве R_ARR.
 | 
				
			||||||
 | 
						* @return 	ExceptionCode	- ILLEGAL DATA ADRESS если адресс недействителен, и NO_ERRORS если все ок.
 | 
				
			||||||
 | 
						*
 | 
				
			||||||
 | 
						* @details 	Позволяет определить, принадлежит ли адресс Addr массиву R_ARR:
 | 
				
			||||||
 | 
						*						Если адресс Addr находится в диапазоне адрессов массива R_ARR, то возвращаем NO_ERROR.
 | 
				
			||||||
 | 
						*						Если адресс 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)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// if address from this array
 | 
				
			||||||
 | 
						if(Addr >= R_ARR_ADDR) 
 | 
				
			||||||
 | 
						{		
 | 
				
			||||||
 | 
							// if quantity too big return error
 | 
				
			||||||
 | 
							if ((Addr - R_ARR_ADDR) + Qnt > R_ARR_NUMB) 
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return ILLEGAL_DATA_ADDRESS;	// return exception code
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// if all ok - return no errors
 | 
				
			||||||
 | 
							return NO_ERRORS;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// if address isnt from this array return error
 | 
				
			||||||
 | 
						else 
 | 
				
			||||||
 | 
							return ILLEGAL_DATA_ADDRESS;	// return exception code		
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 		Define Address Origin for Input/Holding Registers
 | 
				
			||||||
 | 
						* @param 		pRegs 				- указатель на указатель регистров.
 | 
				
			||||||
 | 
						* @param 		Addr 					- адрес начального регистра.
 | 
				
			||||||
 | 
						* @param 		Qnt 					- количество запрашиваемых регистров.
 | 
				
			||||||
 | 
						* @param 		WriteFlag 		- флаг регистр нужны для чтения или записи.
 | 
				
			||||||
 | 
						* @return 	ExceptionCode	- Код исключения если есть, и NO_ERRORS если нет.
 | 
				
			||||||
 | 
						*
 | 
				
			||||||
 | 
					  * @details 	Определение адреса начального регистра.
 | 
				
			||||||
 | 
						* @note 		WriteFlag пока не используется.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType)
 | 
				
			||||||
 | 
					{	
 | 
				
			||||||
 | 
						/* check quantity error */
 | 
				
			||||||
 | 
						if (Qnt > 125)	
 | 
				
			||||||
 | 
						{		
 | 
				
			||||||
 | 
								return ILLEGAL_DATA_VALUE;	// return exception code
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if(RegisterType == RegisterType_Holding)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// Default holding registers
 | 
				
			||||||
 | 
							if(MB_Check_Address_For_Arr(Addr, Qnt, R_HOLDING_ADDR, R_HOLDING_QNT) == NO_ERRORS)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								*pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr);	// указатель на выбранный по Addr регистр
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// if address doesnt match any array - return illegal data address response
 | 
				
			||||||
 | 
							else	
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return ILLEGAL_DATA_ADDRESS;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if(RegisterType == RegisterType_Input)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// Default input registers
 | 
				
			||||||
 | 
							if(MB_Check_Address_For_Arr(Addr, Qnt, R_INPUT_ADDR, R_INPUT_QNT) == NO_ERRORS)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								*pRegs = MB_Set_Register_Ptr(&MB_DATA.InRegs, Addr);	// указатель на выбранный по Addr регистр
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// if address doesnt match any array - return illegal data address response
 | 
				
			||||||
 | 
							else	
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return ILLEGAL_DATA_ADDRESS;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return ILLEGAL_FUNCTION;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// if found requeried array return no err
 | 
				
			||||||
 | 
						return NO_ERRORS; // return no errors
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 		Define Address Origin for coils
 | 
				
			||||||
 | 
						* @param 		pCoils 				- указатель на указатель коилов.
 | 
				
			||||||
 | 
						* @param 		Addr 					- адресс начального коила.
 | 
				
			||||||
 | 
						* @param 		Qnt 					- количество запрашиваемых коилов.
 | 
				
			||||||
 | 
						* @param 		start_shift 	- указатель на переменную содержащую сдвиг внутри регистра для начального коила.
 | 
				
			||||||
 | 
						* @param 		WriteFlag 		- флаг коилы нужны для чтения или записи.
 | 
				
			||||||
 | 
						* @return 	ExceptionCode	- Код исключения если есть, и NO_ERRORS если нет.
 | 
				
			||||||
 | 
						*
 | 
				
			||||||
 | 
					  * @details	Определение адреса начального регистра запрашиваемых коилов.
 | 
				
			||||||
 | 
						* @note 		WriteFlag используется для определния регистров GPIO: ODR или IDR.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag)
 | 
				
			||||||
 | 
					{	
 | 
				
			||||||
 | 
						/* check quantity error */
 | 
				
			||||||
 | 
						if (Qnt > 2000)	
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return ILLEGAL_DATA_VALUE;	// return exception code
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						// Default coils
 | 
				
			||||||
 | 
						if(MB_Check_Address_For_Arr(Addr, Qnt, C_CONTROL_ADDR, C_CONTROL_QNT) == NO_ERRORS)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							*pCoils = MB_Set_Coil_Reg_Ptr(&MB_DATA.Coils, Addr);	// указатель на выбранный по Addr массив коилов
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// if address doesnt match any array - return illegal data address response
 | 
				
			||||||
 | 
						else	
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return ILLEGAL_DATA_ADDRESS;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						*start_shift = Addr % 16;	// set shift to requested coil
 | 
				
			||||||
 | 
						// if found requeried array return no err
 | 
				
			||||||
 | 
						return NO_ERRORS;	// return no errors
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 		Proccess command Read Coils (01 - 0x01).
 | 
				
			||||||
 | 
						* @param 		modbus_msg 				- указатель на структуру собщения modbus.
 | 
				
			||||||
 | 
						* @return 	fMessageHandled		- статус о результате обработки комманды.
 | 
				
			||||||
 | 
						* @details 	Обработка команды Read Coils.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					uint8_t MB_Read_Coils(RS_MsgTypeDef *modbus_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//---------CHECK FOR ERRORS----------
 | 
				
			||||||
 | 
						uint16_t *coils;
 | 
				
			||||||
 | 
						uint16_t start_shift = 0; // shift in coils register
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, modbus_msg->Qnt, &start_shift, 0);
 | 
				
			||||||
 | 
						if(modbus_msg->Except_Code != NO_ERRORS)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//-----------READING COIL------------
 | 
				
			||||||
 | 
						// setup output message data size	
 | 
				
			||||||
 | 
						modbus_msg->ByteCnt = Divide_Up(modbus_msg->Qnt, 8);
 | 
				
			||||||
 | 
						// create mask for coils
 | 
				
			||||||
 | 
						uint16_t mask_for_coils = 0;	// mask for coils that've been chosen
 | 
				
			||||||
 | 
						uint16_t setted_coils = 0;		// value of setted coils
 | 
				
			||||||
 | 
						uint16_t temp_reg = 0;				// temp register for saving coils that hasnt been chosen
 | 
				
			||||||
 | 
						uint16_t coil_cnt = 0;				// counter for processed coils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// cycle until all registers with requered coils would be processed
 | 
				
			||||||
 | 
						int shift = start_shift; 	// set shift to first coil in first register
 | 
				
			||||||
 | 
						int ind = 0;							// index for coils registers and data
 | 
				
			||||||
 | 
						for(; ind <= Divide_Up(start_shift + modbus_msg->Qnt, 16); ind++)
 | 
				
			||||||
 | 
						{ 
 | 
				
			||||||
 | 
							//----SET MASK FOR COILS REGISTER----
 | 
				
			||||||
 | 
							mask_for_coils = 0;
 | 
				
			||||||
 | 
							for(; shift < 0x10; shift++)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								mask_for_coils |= 1<<(shift); // choose certain coil
 | 
				
			||||||
 | 
								if(++coil_cnt >= modbus_msg->Qnt)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							shift = 0; // set shift to zero for the next step
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
							//-----------READ COILS--------------
 | 
				
			||||||
 | 
							modbus_msg->DATA[ind] = (*(coils+ind)&mask_for_coils) >> start_shift;
 | 
				
			||||||
 | 
							if(ind > 0)
 | 
				
			||||||
 | 
								modbus_msg->DATA[ind-1] |= ((*(coils+ind)&mask_for_coils) << 16) >> start_shift;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// т.к. DATA 16-битная, для 8-битной передачи, надо поменять местами верхний и нижний байты
 | 
				
			||||||
 | 
						for(; ind >= 0; --ind)	
 | 
				
			||||||
 | 
							modbus_msg->DATA[ind] = ByteSwap16(modbus_msg->DATA[ind]);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
						* @brief 		Proccess command Read Holding Registers (03 - 0x03).
 | 
				
			||||||
 | 
						* @param 		modbus_msg 				- указатель на структуру собщения modbus.
 | 
				
			||||||
 | 
						* @return 	fMessageHandled		- статус о результате обработки комманды.
 | 
				
			||||||
 | 
						* @details 	Обработка команды Read Holding Registers.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					uint8_t MB_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//---------CHECK FOR ERRORS----------	
 | 
				
			||||||
 | 
						// get origin address for data
 | 
				
			||||||
 | 
						uint16_t *pHoldRegs; 			
 | 
				
			||||||
 | 
						modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding);	// определение адреса регистров
 | 
				
			||||||
 | 
						if(modbus_msg->Except_Code != NO_ERRORS)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//-----------READING REGS------------
 | 
				
			||||||
 | 
						// setup output message data size	
 | 
				
			||||||
 | 
						modbus_msg->ByteCnt = modbus_msg->Qnt*2; // *2 because we transmit 8 bits, not 16 bits
 | 
				
			||||||
 | 
						// read data
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						for (i = 0; i<modbus_msg->Qnt; i++)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							modbus_msg->DATA[i]	= *(pHoldRegs++);
 | 
				
			||||||
 | 
						}	
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
						* @brief 		Proccess command Read Input Registers (04 - 0x04).
 | 
				
			||||||
 | 
						* @param 		modbus_msg 				- указатель на структуру собщения modbus.
 | 
				
			||||||
 | 
						* @return 	fMessageHandled		- статус о результате обработки комманды.
 | 
				
			||||||
 | 
						* @details 	Обработка команды Read Input Registers.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					uint8_t MB_Read_Input_Regs(RS_MsgTypeDef *modbus_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//---------CHECK FOR ERRORS----------	
 | 
				
			||||||
 | 
						// get origin address for data
 | 
				
			||||||
 | 
						uint16_t *pInRegs; 			
 | 
				
			||||||
 | 
						modbus_msg->Except_Code = MB_DefineRegistersAddress(&pInRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Input);	// определение адреса регистров
 | 
				
			||||||
 | 
						if(modbus_msg->Except_Code != NO_ERRORS)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//-----------READING REGS------------
 | 
				
			||||||
 | 
						// setup output message data size	
 | 
				
			||||||
 | 
						modbus_msg->ByteCnt = modbus_msg->Qnt*2; // *2 because we transmit 8 bits, not 16 bits
 | 
				
			||||||
 | 
						// read data
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						for (i = 0; i<modbus_msg->Qnt; i++)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
					    if(*((int16_t *)pInRegs) > 0)
 | 
				
			||||||
 | 
					      modbus_msg->DATA[i]	= (*pInRegs++);
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      modbus_msg->DATA[i]	= (*pInRegs++);
 | 
				
			||||||
 | 
						}	
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
						* @brief 		Proccess command Write Single Coils (05 - 0x05).
 | 
				
			||||||
 | 
						* @param 		modbus_msg 				- указатель на структуру собщения modbus.
 | 
				
			||||||
 | 
						* @return 	fMessageHandled		- статус о результате обработки комманды.
 | 
				
			||||||
 | 
						* @details 	Обработка команды Write Single Coils.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					uint8_t MB_Write_Single_Coil(RS_MsgTypeDef *modbus_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//---------CHECK FOR ERRORS----------
 | 
				
			||||||
 | 
						if ((modbus_msg->Qnt != 0x0000) && (modbus_msg->Qnt != 0xFF00))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							modbus_msg->Except_Code = ILLEGAL_DATA_VALUE;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}		
 | 
				
			||||||
 | 
						// define position of coil
 | 
				
			||||||
 | 
						uint16_t *coils;
 | 
				
			||||||
 | 
						uint16_t start_shift = 0; // shift in coils register
 | 
				
			||||||
 | 
						modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, 0, &start_shift, 1);
 | 
				
			||||||
 | 
						if(modbus_msg->Except_Code != NO_ERRORS)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//----------WRITTING COIL------------
 | 
				
			||||||
 | 
						if(modbus_msg->Qnt == 0xFF00)
 | 
				
			||||||
 | 
							*(coils) |= 1<<start_shift; // write flags corresponding to received data
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							*(coils) &= ~(1<<start_shift); // write flags corresponding to received data
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
						* @brief 		Proccess command Write Single Register (06 - 0x06).
 | 
				
			||||||
 | 
						* @param 		modbus_msg 				- указатель на структуру собщения modbus.
 | 
				
			||||||
 | 
						* @return 	fMessageHandled		- статус о результате обработки комманды.
 | 
				
			||||||
 | 
						* @details 	Обработка команды Write Single Register.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					uint8_t MB_Write_Single_Reg(RS_MsgTypeDef *modbus_msg)
 | 
				
			||||||
 | 
					{	
 | 
				
			||||||
 | 
						// get origin address for data
 | 
				
			||||||
 | 
						uint16_t *pHoldRegs; 			
 | 
				
			||||||
 | 
						modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, 1, RegisterType_Holding);	// определение адреса регистров
 | 
				
			||||||
 | 
						if(modbus_msg->Except_Code != NO_ERRORS)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//-----------WRITTING REG------------	
 | 
				
			||||||
 | 
						*(pHoldRegs) = modbus_msg->Qnt;
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
						* @brief 		Proccess command Write Multiple Coils (15 - 0x0F).
 | 
				
			||||||
 | 
						* @param 		modbus_msg 			- указатель на структуру собщения modbus.
 | 
				
			||||||
 | 
						* @return 	fMessageHandled	- статус о результате обработки комманды.
 | 
				
			||||||
 | 
						* @details 	Обработка команды Write Multiple Coils.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//---------CHECK FOR ERRORS----------
 | 
				
			||||||
 | 
						if (modbus_msg->ByteCnt != Divide_Up(modbus_msg->Qnt, 8))
 | 
				
			||||||
 | 
						{ // if quantity too large OR if quantity and bytes count arent match
 | 
				
			||||||
 | 
							modbus_msg->Except_Code = ILLEGAL_DATA_VALUE;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}	
 | 
				
			||||||
 | 
						// define position of coil
 | 
				
			||||||
 | 
						uint16_t *coils;					// pointer to coils
 | 
				
			||||||
 | 
						uint16_t start_shift = 0; // shift in coils register
 | 
				
			||||||
 | 
						modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, modbus_msg->Qnt, &start_shift, 1);
 | 
				
			||||||
 | 
						if(modbus_msg->Except_Code != NO_ERRORS)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//----------WRITTING COILS-----------
 | 
				
			||||||
 | 
						// create mask for coils
 | 
				
			||||||
 | 
						uint16_t mask_for_coils = 0;	// mask for coils that've been chosen
 | 
				
			||||||
 | 
						uint32_t setted_coils = 0;		// value of setted coils
 | 
				
			||||||
 | 
						uint16_t temp_reg = 0;				// temp register for saving coils that hasnt been chosen
 | 
				
			||||||
 | 
						uint16_t coil_cnt = 0;				// counter for processed coils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// cycle until all registers with requered coils would be processed
 | 
				
			||||||
 | 
						int shift = start_shift; // set shift to first coil in first register
 | 
				
			||||||
 | 
						for(int ind = 0; ind <= Divide_Up(start_shift + modbus_msg->Qnt, 16); ind++)
 | 
				
			||||||
 | 
						{ 
 | 
				
			||||||
 | 
							//----SET MASK FOR COILS REGISTER----
 | 
				
			||||||
 | 
							mask_for_coils = 0;
 | 
				
			||||||
 | 
							for(; shift < 0x10; shift++)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								mask_for_coils |= 1<<(shift); // choose certain coil
 | 
				
			||||||
 | 
								if(++coil_cnt >= modbus_msg->Qnt)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							shift = 0; // set shift to zero for the next step
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//-----------WRITE COILS-------------
 | 
				
			||||||
 | 
							// get current coils
 | 
				
			||||||
 | 
							temp_reg = *(coils+ind);
 | 
				
			||||||
 | 
							// set coils
 | 
				
			||||||
 | 
							setted_coils = ByteSwap16(modbus_msg->DATA[ind]) << start_shift;
 | 
				
			||||||
 | 
							if(ind > 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								setted_coils |= ((ByteSwap16(modbus_msg->DATA[ind-1]) << start_shift) >> 16);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// write coils
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							*(coils+ind) = setted_coils & mask_for_coils;		
 | 
				
			||||||
 | 
							 // restore untouched coils
 | 
				
			||||||
 | 
							*(coils+ind) |= temp_reg&(~mask_for_coils);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(coil_cnt >= modbus_msg->Qnt) // if all coils written - break cycle
 | 
				
			||||||
 | 
								break;												// *kind of unnecessary
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
						* @brief 		Proccess command Write Multiple Registers (16 - 0x10).
 | 
				
			||||||
 | 
						* @param 		modbus_msg 				- указатель на структуру собщения modbus.
 | 
				
			||||||
 | 
						* @return 	fMessageHandled		- статус о результате обработки комманды.
 | 
				
			||||||
 | 
						* @details 	Обработка команды Write Multiple Registers.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					uint8_t MB_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//---------CHECK FOR ERRORS----------
 | 
				
			||||||
 | 
						if (modbus_msg->Qnt*2 != modbus_msg->ByteCnt)
 | 
				
			||||||
 | 
						{ // if quantity and bytes count arent match
 | 
				
			||||||
 | 
							modbus_msg->Except_Code = ILLEGAL_DATA_VALUE;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}	
 | 
				
			||||||
 | 
						// get origin address for data
 | 
				
			||||||
 | 
						uint16_t *pHoldRegs; 			
 | 
				
			||||||
 | 
						modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding);	// определение адреса регистров
 | 
				
			||||||
 | 
						if(modbus_msg->Except_Code != NO_ERRORS)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//-----------WRITTING REGS-----------	
 | 
				
			||||||
 | 
						for (int i = 0; i<modbus_msg->Qnt; i++)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							*(pHoldRegs++) = modbus_msg->DATA[i];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MB_WriteObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef *obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  mbdata[(*ind)++] = obj->length;
 | 
				
			||||||
 | 
					  for (int i = 0; i < obj->length; i++)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    mbdata[(*ind)++] = obj->name[i];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
						* @brief 		Proccess command Read Device Identification (43/14 - 0x2B/0E).
 | 
				
			||||||
 | 
						* @param 		modbus_msg 				- указатель на структуру собщения modbus.
 | 
				
			||||||
 | 
						* @return 	fMessageHandled		- статус о результате обработки комманды.
 | 
				
			||||||
 | 
						* @details 	Обработка команды Write Single Register.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					uint8_t MB_Read_Device_Identification(RS_MsgTypeDef *modbus_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  char *mbdata = (char *)modbus_msg->DATA;
 | 
				
			||||||
 | 
					  unsigned ind = 0;
 | 
				
			||||||
 | 
					  switch(modbus_msg->DevId.ReadDevId)
 | 
				
			||||||
 | 
					  { 
 | 
				
			||||||
 | 
					    case MB_BASIC_IDENTIFICATION:
 | 
				
			||||||
 | 
					      mbdata[ind++] = 0x00;
 | 
				
			||||||
 | 
					      MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.VendorName);
 | 
				
			||||||
 | 
					      mbdata[ind++] = 0x01;
 | 
				
			||||||
 | 
					      MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.ProductCode);
 | 
				
			||||||
 | 
					      mbdata[ind++] = 0x02;
 | 
				
			||||||
 | 
					      MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.Revision);
 | 
				
			||||||
 | 
					      modbus_msg->DevId.NumbOfObj = 3;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case MB_REGULAR_IDENTIFICATION:
 | 
				
			||||||
 | 
					      mbdata[ind++] = 0x03;
 | 
				
			||||||
 | 
					      MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.VendorUrl);
 | 
				
			||||||
 | 
					      mbdata[ind++] = 0x04;
 | 
				
			||||||
 | 
					      MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.ProductName);
 | 
				
			||||||
 | 
					      mbdata[ind++] = 0x05;
 | 
				
			||||||
 | 
					      MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.ModelName);
 | 
				
			||||||
 | 
					      mbdata[ind++] = 0x06;
 | 
				
			||||||
 | 
					      MB_WriteObjectToMessage(mbdata, &ind, &MB_INFO.UserApplicationName);
 | 
				
			||||||
 | 
					      modbus_msg->DevId.NumbOfObj = 4;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      return 0;
 | 
				
			||||||
 | 
					  }  
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  modbus_msg->ByteCnt = ind;
 | 
				
			||||||
 | 
					  return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 		Respond accord to received message.
 | 
				
			||||||
 | 
						* @param 		hRS 		- указатель на хендлер RS.
 | 
				
			||||||
 | 
						* @param 		RS_msg 	- указатель на структуру сообщения.
 | 
				
			||||||
 | 
						* @return 	RS_RES	- статус о результате ответа на комманду.
 | 
				
			||||||
 | 
						* @details		Обработка принятой комманды и ответ на неё.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						RS_StatusTypeDef MB_RES = RS_OK;
 | 
				
			||||||
 | 
						hmodbus->f.MessageHandled = 0;
 | 
				
			||||||
 | 
						hmodbus->f.EchoResponse = 0;
 | 
				
			||||||
 | 
						RS_Reset_TX_Flags(hmodbus);			// reset flag for correct transmit
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if(modbus_msg->Func_Code < ERR_VALUES_START)// if no errors after parsing
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							switch (modbus_msg->Func_Code)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// Read Coils
 | 
				
			||||||
 | 
								case MB_R_COILS: 
 | 
				
			||||||
 | 
									hmodbus->f.MessageHandled = 	MB_Read_Coils(hmodbus->pMessagePtr);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Read Hodling Registers
 | 
				
			||||||
 | 
								case MB_R_HOLD_REGS:
 | 
				
			||||||
 | 
									hmodbus->f.MessageHandled = 	MB_Read_Hold_Regs(hmodbus->pMessagePtr);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case MB_R_IN_REGS: 
 | 
				
			||||||
 | 
									hmodbus->f.MessageHandled = 	MB_Read_Input_Regs(hmodbus->pMessagePtr);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Write Single Coils
 | 
				
			||||||
 | 
								case MB_W_COIL: 
 | 
				
			||||||
 | 
									hmodbus->f.MessageHandled =	MB_Write_Single_Coil(hmodbus->pMessagePtr);	
 | 
				
			||||||
 | 
									if(hmodbus->f.MessageHandled) 
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										hmodbus->f.EchoResponse = 1; 
 | 
				
			||||||
 | 
										hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								case MB_W_HOLD_REG: 	
 | 
				
			||||||
 | 
									hmodbus->f.MessageHandled =	MB_Write_Single_Reg(hmodbus->pMessagePtr);	
 | 
				
			||||||
 | 
									if(hmodbus->f.MessageHandled) 
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										hmodbus->f.EchoResponse = 1;
 | 
				
			||||||
 | 
										hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Write Multiple Coils
 | 
				
			||||||
 | 
								case MB_W_COILS: 
 | 
				
			||||||
 | 
									hmodbus->f.MessageHandled = 	MB_Write_Miltuple_Coils(hmodbus->pMessagePtr);
 | 
				
			||||||
 | 
									if(hmodbus->f.MessageHandled) 
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										hmodbus->f.EchoResponse = 1; 
 | 
				
			||||||
 | 
										hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Write Multiple Registers
 | 
				
			||||||
 | 
								case MB_W_HOLD_REGS:
 | 
				
			||||||
 | 
									hmodbus->f.MessageHandled = 	MB_Write_Miltuple_Regs(hmodbus->pMessagePtr);
 | 
				
			||||||
 | 
									if(hmodbus->f.MessageHandled) 
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										hmodbus->f.EchoResponse = 1; 
 | 
				
			||||||
 | 
										hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
					      case MB_R_DEVICE_INFO:
 | 
				
			||||||
 | 
					        hmodbus->f.MessageHandled =   MB_Read_Device_Identification(hmodbus->pMessagePtr);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					       
 | 
				
			||||||
 | 
								/* unknown func code */
 | 
				
			||||||
 | 
								default: modbus_msg->Except_Code = ILLEGAL_FUNCTION; /* set exception code: illegal function */
 | 
				
			||||||
 | 
							}		
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
							if(hmodbus->f.MessageHandled == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
								modbus_msg->Func_Code = static_cast<MB_FunctonTypeDef>(
 | 
				
			||||||
 | 
					    		static_cast<int>(modbus_msg->Func_Code) + ERR_VALUES_START
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// if we need response - check that transmit isnt busy
 | 
				
			||||||
 | 
						if( RS_Is_TX_Busy(hmodbus) ) 
 | 
				
			||||||
 | 
							RS_Abort(hmodbus, ABORT_TX);		// if tx busy - set it free
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// Transmit right there, or sets (fDeferredResponse) to transmit response in main code	
 | 
				
			||||||
 | 
						MB_RES = RS_Handle_Transmit_Start(hmodbus, modbus_msg);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						hmodbus->RS_STATUS = MB_RES;
 | 
				
			||||||
 | 
						return MB_RES;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 		Collect message in buffer to transmit it.
 | 
				
			||||||
 | 
						* @param 		hRS 					- указатель на хендлер RS.
 | 
				
			||||||
 | 
						* @param 		RS_msg 				- указатель на структуру сообщения.
 | 
				
			||||||
 | 
						* @param 		msg_uart_buff	- указатель на буффер UART.
 | 
				
			||||||
 | 
						* @return 	RS_RES				- статус о результате заполнения буфера.
 | 
				
			||||||
 | 
						* @details		Заполнение буффера UART из структуры сообщения.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ind = 0; // ind for modbus-uart buffer
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if(hmodbus->f.EchoResponse && hmodbus->f.MessageHandled) 	// if echo response need
 | 
				
			||||||
 | 
							ind = hmodbus->RS_Message_Size;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//------INFO ABOUT DATA/MESSAGE------
 | 
				
			||||||
 | 
							//-----------[first bytes]-----------
 | 
				
			||||||
 | 
							// set ID of message/user
 | 
				
			||||||
 | 
							modbus_uart_buff[ind++] = modbus_msg->MbAddr;	
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// set dat or err response
 | 
				
			||||||
 | 
							modbus_uart_buff[ind++] = modbus_msg->Func_Code;	
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (modbus_msg->Func_Code < ERR_VALUES_START) // if no error occur
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
					      // fill modbus header
 | 
				
			||||||
 | 
					      if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // devide identification header
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        modbus_uart_buff[ind++] = modbus_msg->DevId.MEI_Type;
 | 
				
			||||||
 | 
					        modbus_uart_buff[ind++] = modbus_msg->DevId.ReadDevId;
 | 
				
			||||||
 | 
					        modbus_uart_buff[ind++] = modbus_msg->DevId.Conformity;
 | 
				
			||||||
 | 
					        modbus_uart_buff[ind++] = modbus_msg->DevId.MoreFollows;
 | 
				
			||||||
 | 
					        modbus_uart_buff[ind++] = modbus_msg->DevId.NextObjId;
 | 
				
			||||||
 | 
					        modbus_uart_buff[ind++] = modbus_msg->DevId.NumbOfObj;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (modbus_msg->ByteCnt > DATA_SIZE*2) // if ByteCnt less than DATA_SIZE
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          return RS_COLLECT_MSG_ERR;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        //---------------DATA----------------
 | 
				
			||||||
 | 
					        //-----------[data bytes]------------
 | 
				
			||||||
 | 
					        uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA;
 | 
				
			||||||
 | 
					        for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data
 | 
				
			||||||
 | 
					        {	// set data
 | 
				
			||||||
 | 
					          modbus_uart_buff[ind++] = *tmp_data_addr;
 | 
				
			||||||
 | 
					          tmp_data_addr++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else // modbus data header
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        // set size of received data
 | 
				
			||||||
 | 
					        if (modbus_msg->ByteCnt <= DATA_SIZE*2) // if ByteCnt less than DATA_SIZE
 | 
				
			||||||
 | 
					          modbus_uart_buff[ind++] = modbus_msg->ByteCnt;
 | 
				
			||||||
 | 
					        else																				// otherwise return data_size err
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          return RS_COLLECT_MSG_ERR;
 | 
				
			||||||
 | 
					        }        
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        //---------------DATA----------------
 | 
				
			||||||
 | 
					        //-----------[data bytes]------------
 | 
				
			||||||
 | 
					        uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA;
 | 
				
			||||||
 | 
					        for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data
 | 
				
			||||||
 | 
					        {	// set data
 | 
				
			||||||
 | 
					          if (i%2 == 0)		// HI byte
 | 
				
			||||||
 | 
					            modbus_uart_buff[ind++] = (*tmp_data_addr)>>8;
 | 
				
			||||||
 | 
					          else						// LO byte
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            modbus_uart_buff[ind++] = *tmp_data_addr;
 | 
				
			||||||
 | 
					            tmp_data_addr++;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else 	// if some error occur
 | 
				
			||||||
 | 
							{			// send expection code
 | 
				
			||||||
 | 
								modbus_uart_buff[ind++] = modbus_msg->Except_Code;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						//---------------CRC----------------
 | 
				
			||||||
 | 
						//---------[last 16 bytes]----------
 | 
				
			||||||
 | 
						// calc crc of received data
 | 
				
			||||||
 | 
						uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
 | 
				
			||||||
 | 
						// write crc to message structure and modbus-uart buffer
 | 
				
			||||||
 | 
						modbus_msg->MB_CRC = CRC_VALUE;
 | 
				
			||||||
 | 
						modbus_uart_buff[ind++] = CRC_VALUE;
 | 
				
			||||||
 | 
						modbus_uart_buff[ind++] = CRC_VALUE >> 8;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						hmodbus->RS_Message_Size = ind;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						return RS_OK; // returns ok
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 		Parse message from buffer to process it.
 | 
				
			||||||
 | 
						* @param 		hRS 					- указатель на хендлер RS.
 | 
				
			||||||
 | 
						* @param 		RS_msg 				- указатель на структуру сообщения.
 | 
				
			||||||
 | 
						* @param 		msg_uart_buff	- указатель на буффер UART.
 | 
				
			||||||
 | 
						* @return 	RS_RES				- статус о результате заполнения структуры.
 | 
				
			||||||
 | 
						* @details		Заполнение структуры сообщения из буффера UART.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint32_t check_empty_buff;
 | 
				
			||||||
 | 
						int ind = 0; // ind for modbus-uart buffer
 | 
				
			||||||
 | 
						//-----INFO ABOUT DATA/MESSAGE-------
 | 
				
			||||||
 | 
						//-----------[first bits]------------
 | 
				
			||||||
 | 
						// get ID of message/user
 | 
				
			||||||
 | 
						modbus_msg->MbAddr = modbus_uart_buff[ind++];
 | 
				
			||||||
 | 
						if(modbus_msg->MbAddr != hmodbus->ID)
 | 
				
			||||||
 | 
							return RS_SKIP;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// get func code
 | 
				
			||||||
 | 
						modbus_msg->Func_Code = static_cast<MB_FunctonTypeDef>(modbus_uart_buff[ind++]);
 | 
				
			||||||
 | 
						if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // if it device identification request
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    modbus_msg->DevId.MEI_Type = static_cast<MB_MEITypeDef>(modbus_uart_buff[ind++]);
 | 
				
			||||||
 | 
					    modbus_msg->DevId.ReadDevId = static_cast<MB_ConformityTypeDef>(modbus_uart_buff[ind++]);
 | 
				
			||||||
 | 
					    modbus_msg->DevId.NextObjId = modbus_uart_buff[ind++];
 | 
				
			||||||
 | 
					    modbus_msg->ByteCnt = 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else // if its classic modbus request
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
						// get address from CMD
 | 
				
			||||||
 | 
						modbus_msg->Addr = modbus_uart_buff[ind++] << 8;
 | 
				
			||||||
 | 
						modbus_msg->Addr |= modbus_uart_buff[ind++];
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// get address from CMD
 | 
				
			||||||
 | 
						modbus_msg->Qnt = modbus_uart_buff[ind++] << 8;
 | 
				
			||||||
 | 
						modbus_msg->Qnt |= modbus_uart_buff[ind++];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if(hmodbus->f.RX_Half == 0) // if all message received
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//---------------DATA----------------
 | 
				
			||||||
 | 
							// 					  (optional)
 | 
				
			||||||
 | 
							if (modbus_msg->ByteCnt != 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								ind++; // increment ind for data_size byte
 | 
				
			||||||
 | 
								//check that data size is correct
 | 
				
			||||||
 | 
								if (modbus_msg->ByteCnt > DATA_SIZE*2)
 | 
				
			||||||
 | 
								{				
 | 
				
			||||||
 | 
									modbus_msg->Func_Code = static_cast<MB_FunctonTypeDef>(
 | 
				
			||||||
 | 
										static_cast<int>(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 = static_cast<MB_FunctonTypeDef>(
 | 
				
			||||||
 | 
									static_cast<int>(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.
 | 
				
			||||||
 | 
						* @param 		hRS 					- указатель на хендлер RS.
 | 
				
			||||||
 | 
						* @param 		rx_data_size 	- указатель на переменную для записи кол-ва байт для принятия.
 | 
				
			||||||
 | 
						* @return 	RS_RES				- статус о корректности рассчета кол-ва байт для принятия.
 | 
				
			||||||
 | 
						* @details	Определение сколько байтов надо принять по протоколу.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Define_Size_of_RX_Message(RS_HandleTypeDef *hmodbus, uint32_t *rx_data_size)
 | 
				
			||||||
 | 
					{		
 | 
				
			||||||
 | 
						RS_StatusTypeDef MB_RES = RS_OK;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						MB_RES = RS_Parse_Message(hmodbus, hmodbus->pMessagePtr, hmodbus->pBufferPtr);
 | 
				
			||||||
 | 
						if(MB_RES == RS_SKIP) // if message not for us
 | 
				
			||||||
 | 
							return MB_RES;																// return 
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
						if ((hmodbus->pMessagePtr->Func_Code & ~ERR_VALUES_START) < 0x0F)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							hmodbus->pMessagePtr->ByteCnt = 0;
 | 
				
			||||||
 | 
							*rx_data_size = 1;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							hmodbus->pMessagePtr->ByteCnt = hmodbus->pBufferPtr[RX_FIRST_PART_SIZE-1]; // get numb of data in command
 | 
				
			||||||
 | 
						// +1 because that defines is size, not ind.
 | 
				
			||||||
 | 
							*rx_data_size = hmodbus->pMessagePtr->ByteCnt + 2;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  if(hmodbus->pMessagePtr->Func_Code == MB_R_DEVICE_INFO)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
							*rx_data_size = 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
						hmodbus->RS_Message_Size = RX_FIRST_PART_SIZE + *rx_data_size; // size of whole message
 | 
				
			||||||
 | 
						return RS_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//-----------------------------FOR USER------------------------------
 | 
				
			||||||
 | 
					//-------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MB_DevoceInentificationInit(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  MB_INFO.VendorName.name = MODBUS_VENDOR_NAME;
 | 
				
			||||||
 | 
					  MB_INFO.ProductCode.name = MODBUS_PRODUCT_CODE;
 | 
				
			||||||
 | 
					  MB_INFO.Revision.name = MODBUS_REVISION;
 | 
				
			||||||
 | 
					  MB_INFO.VendorUrl.name = MODBUS_VENDOR_URL;
 | 
				
			||||||
 | 
					  MB_INFO.ProductName.name = MODBUS_PRODUCT_NAME;
 | 
				
			||||||
 | 
					  MB_INFO.ModelName.name = MODBUS_MODEL_NAME;
 | 
				
			||||||
 | 
					  MB_INFO.UserApplicationName.name = MODBUS_USER_APPLICATION_NAME;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  MB_INFO.VendorName.length = sizeof(MODBUS_VENDOR_NAME);
 | 
				
			||||||
 | 
					  MB_INFO.ProductCode.length = sizeof(MODBUS_PRODUCT_CODE);
 | 
				
			||||||
 | 
					  MB_INFO.Revision.length = sizeof(MODBUS_REVISION);
 | 
				
			||||||
 | 
					  MB_INFO.VendorUrl.length = sizeof(MODBUS_VENDOR_URL);
 | 
				
			||||||
 | 
					  MB_INFO.ProductName.length = sizeof(MODBUS_PRODUCT_NAME);
 | 
				
			||||||
 | 
					  MB_INFO.ModelName.length = sizeof(MODBUS_MODEL_NAME);
 | 
				
			||||||
 | 
					  MB_INFO.UserApplicationName.length = sizeof(MODBUS_USER_APPLICATION_NAME);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										372
									
								
								modbus.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										372
									
								
								modbus.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,372 @@
 | 
				
			|||||||
 | 
					/** 
 | 
				
			||||||
 | 
						**************************************************************************
 | 
				
			||||||
 | 
						* @file 	modbus.h
 | 
				
			||||||
 | 
						* @brief 	Заголовочный файл модуля MODBUS.
 | 
				
			||||||
 | 
						* @details 	Данный файл необходимо подключить в rs_message.h. После подключать 
 | 
				
			||||||
 | 
						* rs_message.h к основному проекту.
 | 
				
			||||||
 | 
						* 
 | 
				
			||||||
 | 
						* @defgroup MODBUS
 | 
				
			||||||
 | 
						* @brief 		Modbus stuff
 | 
				
			||||||
 | 
						*
 | 
				
			||||||
 | 
						*************************************************************************/
 | 
				
			||||||
 | 
					#ifndef __MODBUS_H_
 | 
				
			||||||
 | 
					#define __MODBUS_H_
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					#include "modbus_config.h"
 | 
				
			||||||
 | 
					#include "modbus_data.h"
 | 
				
			||||||
 | 
					//#include "settings.h"		// for modbus settings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @addtogroup MODBUS_SETTINGS
 | 
				
			||||||
 | 
						* @ingroup 		MODBUS
 | 
				
			||||||
 | 
						* @brief 			Some defines for modbus
 | 
				
			||||||
 | 
						@{
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					/////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					//////////////////////////---SETTINGS---/////////////////////////////
 | 
				
			||||||
 | 
					// USER SETTINGS FOR MODBUS IN interface_config.h
 | 
				
			||||||
 | 
					//////////////////////////---SETTINGS---/////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					/////////////////////---USER MESSAGE DEFINES---//////////////////////
 | 
				
			||||||
 | 
					//-------------DEFINES FOR STRUCTURE----------------
 | 
				
			||||||
 | 
					/* defines for structure of modbus message */
 | 
				
			||||||
 | 
					#define MbAddr_SIZE 						1						///< size of (MbAddr)
 | 
				
			||||||
 | 
					#define Func_Code_SIZE					1						///< size of (Func_Code)
 | 
				
			||||||
 | 
					#define	Addr_SIZE								2						///< size of (Addr)
 | 
				
			||||||
 | 
					#define Qnt_SIZE								2						///< size of (Qnt)
 | 
				
			||||||
 | 
					#define ByteCnt_SIZE						1						///< size of (ByteCnt)
 | 
				
			||||||
 | 
					#define DATA_SIZE 							125 				///< maximum number of data: DWORD (NOT MESSAGE SIZE)
 | 
				
			||||||
 | 
					#define CRC_SIZE 								2 					///< size of (MB_CRC) in bytes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @brief Size of whole message */
 | 
				
			||||||
 | 
					#define INFO_SIZE_MAX 					(MbAddr_SIZE+Func_Code_SIZE+Addr_SIZE+Qnt_SIZE+ByteCnt_SIZE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @brief Size of first part of message that will be received
 | 
				
			||||||
 | 
					first receive info part of message, than defines size of rest message*/
 | 
				
			||||||
 | 
					#define RX_FIRST_PART_SIZE			INFO_SIZE_MAX
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @brief Structure for modbus exception codes */
 | 
				
			||||||
 | 
					typedef enum //MB_ExceptionTypeDef
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// reading
 | 
				
			||||||
 | 
						NO_ERRORS                 = 0x00,		///< no errors
 | 
				
			||||||
 | 
						ILLEGAL_FUNCTION          = 0x01,		///< Принятый код функции не может быть обработан
 | 
				
			||||||
 | 
						ILLEGAL_DATA_ADDRESS      = 0x02,		///< Адрес данных, указанный в запросе, недоступен
 | 
				
			||||||
 | 
						ILLEGAL_DATA_VALUE        = 0x03,		///< Значение, содержащееся в поле данных запроса, является недопустимой величиной
 | 
				
			||||||
 | 
						SLAVE_DEVICE_FAILURE      = 0x04,		///< Невосстанавливаемая ошибка имела место, пока ведомое устройство пыталось выполнить затребованное действие
 | 
				
			||||||
 | 
					//	ACKNOWLEDGE =						0x05,		///< idk
 | 
				
			||||||
 | 
					//	SLAVE_DEVICE_BUSY =			0x06,		///< idk
 | 
				
			||||||
 | 
					//	MEMORY_PARITY_ERROR =		0x08,		///< idk
 | 
				
			||||||
 | 
					}MB_ExceptionTypeDef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ERR_VALUES_START				0x80U				///< from this value starts error func codes
 | 
				
			||||||
 | 
					/** @brief Structure for modbus func codes */
 | 
				
			||||||
 | 
					typedef enum //MB_FunctonTypeDef
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  /* COMMANDS */
 | 
				
			||||||
 | 
						// reading
 | 
				
			||||||
 | 
						MB_R_COILS            = 0x01,			///< Чтение битовых ячеек
 | 
				
			||||||
 | 
						MB_R_DISC_IN          = 0x02,		  ///< Чтение дискретных входов
 | 
				
			||||||
 | 
					#ifndef MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS
 | 
				
			||||||
 | 
						MB_R_HOLD_REGS        = 0x03,			///< Чтение входных регистров
 | 
				
			||||||
 | 
						MB_R_IN_REGS          = 0x04,			///< Чтение регистров хранения
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						MB_R_HOLD_REGS        = 0x04,			///< Чтение входных регистров
 | 
				
			||||||
 | 
						MB_R_IN_REGS          = 0x03,			///< Чтение регистров хранения
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// writting
 | 
				
			||||||
 | 
						MB_W_COIL             = 0x05,			///< Запись битовой ячейки
 | 
				
			||||||
 | 
						MB_W_HOLD_REG         = 0x06,			///< Запись одиночного регистра
 | 
				
			||||||
 | 
						MB_W_COILS            = 0x0F,			///< Запись нескольких битовых ячеек
 | 
				
			||||||
 | 
						MB_W_HOLD_REGS        = 0x10,			///< Запись нескольких регистров
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  MB_R_DEVICE_INFO      = 0x2B,			///< Чтения информации об устройстве
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  /* ERRORS */
 | 
				
			||||||
 | 
						// error reading
 | 
				
			||||||
 | 
						MB_ERR_R_COILS        = MB_R_COILS + ERR_VALUES_START,			  ///< Ошибка чтения битовых ячеек
 | 
				
			||||||
 | 
						MB_ERR_R_DISC_IN      = MB_R_DISC_IN + ERR_VALUES_START,	    ///< Ошибка чтения дискретных входов
 | 
				
			||||||
 | 
						MB_ERR_R_IN_REGS      = MB_R_IN_REGS + ERR_VALUES_START,			///< Ошибка чтения регистров хранения
 | 
				
			||||||
 | 
						MB_ERR_R_HOLD_REGS    = MB_R_HOLD_REGS + ERR_VALUES_START,		///< Ошибка чтения входных регистров
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// error writting
 | 
				
			||||||
 | 
						MB_ERR_W_COIL         = MB_W_COIL + ERR_VALUES_START,			    ///< Ошибка записи битовой ячейки
 | 
				
			||||||
 | 
						MB_ERR_W_HOLD_REG     = MB_W_HOLD_REG + ERR_VALUES_START,			///< Ошибка записи одиночного регистра
 | 
				
			||||||
 | 
						MB_ERR_W_COILS        = MB_W_COILS + ERR_VALUES_START,			  ///< Ошибка записи нескольких битовых ячеек
 | 
				
			||||||
 | 
						MB_ERR_W_HOLD_REGS    = MB_W_HOLD_REGS + ERR_VALUES_START,	  ///< Ошибка записи нескольких регистров
 | 
				
			||||||
 | 
					}MB_FunctonTypeDef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @brief Structure for MEI func codes */
 | 
				
			||||||
 | 
					typedef enum //MB_FunctonTypeDef
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  MEI_DEVICE_IDENTIFICATION = 0x0E,
 | 
				
			||||||
 | 
					}MB_MEITypeDef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @brief Structure for MEI func codes */
 | 
				
			||||||
 | 
					typedef enum //MB_FunctonTypeDef
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  MB_BASIC_IDENTIFICATION = 0x01,
 | 
				
			||||||
 | 
					  MB_REGULAR_IDENTIFICATION = 0x02,
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  /* ERRORS */  
 | 
				
			||||||
 | 
					  MB_ERR_BASIC_IDENTIFICATION = MB_BASIC_IDENTIFICATION + ERR_VALUES_START,
 | 
				
			||||||
 | 
					  MB_ERR_REGULAR_IDENTIFICATION = MB_REGULAR_IDENTIFICATION + ERR_VALUES_START,
 | 
				
			||||||
 | 
					}MB_ConformityTypeDef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @brief Structure for decive identification message type */
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						MB_MEITypeDef 		        MEI_Type;			  ///< MEI Type assigned number for Device Identification Interface
 | 
				
			||||||
 | 
					  MB_ConformityTypeDef      ReadDevId;
 | 
				
			||||||
 | 
					  MB_ConformityTypeDef      Conformity;
 | 
				
			||||||
 | 
					  uint8_t                   MoreFollows;    ///< in this library always a zero
 | 
				
			||||||
 | 
					  uint8_t                   NextObjId;
 | 
				
			||||||
 | 
					  uint8_t                   NumbOfObj;  
 | 
				
			||||||
 | 
					}MB_DevIdMsgTypeDef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @brief Structure for modbus messsage */
 | 
				
			||||||
 | 
					typedef struct 	// RS_MsgTypeDef
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t 							MbAddr;							///< Modbus Slave Address
 | 
				
			||||||
 | 
						MB_FunctonTypeDef 		Func_Code;					///< Modbus Function Code
 | 
				
			||||||
 | 
					  MB_DevIdMsgTypeDef    DevId;              ///< Read Device Identification Header struct
 | 
				
			||||||
 | 
						uint16_t 							Addr;								///< Modbus Address of data
 | 
				
			||||||
 | 
						uint16_t 							Qnt;								///< Quantity of modbus data
 | 
				
			||||||
 | 
						uint8_t 							ByteCnt;						///< Quantity of bytes of data in message to transmit/receive
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						uint16_t 							DATA[DATA_SIZE];		///< Modbus Data
 | 
				
			||||||
 | 
						MB_ExceptionTypeDef		Except_Code;				///< Exception Code for the command
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						uint16_t 							MB_CRC;							///< Modbus CRC
 | 
				
			||||||
 | 
					}RS_MsgTypeDef;
 | 
				
			||||||
 | 
					//--------------------------------------------------
 | 
				
			||||||
 | 
					extern RS_MsgTypeDef MODBUS_MSG;
 | 
				
			||||||
 | 
					/////////////////////---MODBUS USER SETTINGS---//////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** MODBUS_SETTINGS
 | 
				
			||||||
 | 
					  * @} 
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @addtogroup MODBUS_MESSAGE_DEFINES
 | 
				
			||||||
 | 
						* @ingroup 		MODBUS
 | 
				
			||||||
 | 
						* @brief 			Some defines for modbus
 | 
				
			||||||
 | 
						@{
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					/** @brief Structure for coils operation */
 | 
				
			||||||
 | 
					typedef enum
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						SET_COIL,
 | 
				
			||||||
 | 
						RESET_COIL,
 | 
				
			||||||
 | 
						TOOGLE_COIL,
 | 
				
			||||||
 | 
					}MB_CoilsOpTypeDef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//--------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 	Macros to set pointer to 16-bit array
 | 
				
			||||||
 | 
						* @param 	_arr_ 				- массив регистров (16-бит).
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					#define MB_Set_Arr16_Ptr(_arr_)												((uint16_t*)(&(_arr_)))
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 	Macros to set pointer to register
 | 
				
			||||||
 | 
						* @param 	_parr_ 				- массив регистров.
 | 
				
			||||||
 | 
						* @param 	_addr_ 				- Номер регистра (его индекс) от начала массива _arr_.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					#define MB_Set_Register_Ptr(_parr_, _addr_)						((uint16_t *)(_parr_)+(_addr_))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 	Macros to set pointer to a certain register that contains certain coil
 | 
				
			||||||
 | 
						* @param 	_parr_ 				- массив коилов.
 | 
				
			||||||
 | 
						* @param 	_coil_ 				- Номер коила от начала массива _arr_.
 | 
				
			||||||
 | 
						*	@note		Используется вместе с @ref MB_Set_Coil_Mask
 | 
				
			||||||
 | 
						@verbatim	Пояснение выражений
 | 
				
			||||||
 | 
											(_coil_/16) - get index (address shift) of register that contain certain coil
 | 
				
			||||||
 | 
						Visual explanation: 30th coil in coils registers array
 | 
				
			||||||
 | 
						xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
 | 
				
			||||||
 | 
						|register[0]----|	|register[1]----|
 | 
				
			||||||
 | 
						|skip this------|	|get this-------|
 | 
				
			||||||
 | 
															|shift to 14 bit|
 | 
				
			||||||
 | 
						@endverbatim
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					#define MB_Set_Coil_Reg_Ptr(_parr_, _coil_)						((uint16_t *)(_parr_)+((_coil_)/16))
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 	Macros to set mask to a certain bit in coils register
 | 
				
			||||||
 | 
						* @param 	_coil_ 				- Номер коила от начала массива _arr_.
 | 
				
			||||||
 | 
						*	@note		Используется вместе с @ref MB_Set_Coil_Reg_Ptr
 | 
				
			||||||
 | 
						@verbatim	Пояснение выражений
 | 
				
			||||||
 | 
											(16*(_coil_/16) - how many coils we need to skip. e.g. (16*30/16) - skip 16 coils from first register
 | 
				
			||||||
 | 
											_coil_-(16*(_coil_/16)) - shift to certain coil in certain register
 | 
				
			||||||
 | 
										e.g. Coil(30) gets in register[1] (30/16 = 1) coil №14 (30 - (16*30/16) = 30 - 16 = 14)
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						Visual explanation: 30th coil in coils registers array
 | 
				
			||||||
 | 
						xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
 | 
				
			||||||
 | 
						|register[0]----|	|register[1]----|
 | 
				
			||||||
 | 
						|skip this------|	|get this-------|
 | 
				
			||||||
 | 
															|shift to 14 bit|
 | 
				
			||||||
 | 
						@endverbatim
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					#define MB_Set_Coil_Mask(_coil_)											(1 << ( _coil_ - (16*((_coil_)/16)) ))
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 	Read Coil at its local address.
 | 
				
			||||||
 | 
						* @param 	_parr_ 				- массив коилов.
 | 
				
			||||||
 | 
						* @param 	_coil_ 				- Номер коила от начала массива _arr_.
 | 
				
			||||||
 | 
						* @return uint16_t			- Возвращает запрошенный коил на 0м бите.
 | 
				
			||||||
 | 
						*
 | 
				
			||||||
 | 
					  * @details 	Позволяет обратиться к коилу по адресу относительно _arr_.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					#define MB_Read_Coil_Local(_parr_, _coil_)					((	*MB_Set_Coil_Reg_Ptr(_parr_, _coil_)	&		MB_Set_Coil_Mask(_coil_) ) >> (_coil_))
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 	Set Coil at its local address.
 | 
				
			||||||
 | 
						* @param 	_parr_ 				- указатель на массив коилов.
 | 
				
			||||||
 | 
						* @param 	_coil_ 				- Номер коила от начала массива _arr_.
 | 
				
			||||||
 | 
						*	
 | 
				
			||||||
 | 
					  * @details 	Позволяет обратиться к коилу по адресу относительно _arr_.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					#define	MB_Set_Coil_Local(_parr_, _coil_)							*MB_Set_Coil_Reg_Ptr(_parr_, _coil_) 	|= 	MB_Set_Coil_Mask(_coil_)
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 	Reset Coil at its local address.
 | 
				
			||||||
 | 
						* @param 	_parr_ 				- указатель на массив коилов.
 | 
				
			||||||
 | 
						* @param 	_coil_ 				- Номер коила от начала массива _arr_.
 | 
				
			||||||
 | 
						*
 | 
				
			||||||
 | 
					  * @details 	Позволяет обратиться к коилу по адресу относительно _arr_.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					#define MB_Reset_Coil_Local(_parr_, _coil_)						*MB_Set_Coil_Reg_Ptr(_parr_, _coil_) 	&= ~(MB_Set_Coil_Mask(_coil_))
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 	Set Coil at its local address.
 | 
				
			||||||
 | 
						* @param 	_parr_ 				- указатель на массив коилов.
 | 
				
			||||||
 | 
						* @param 	_coil_ 				- Номер коила от начала массива _arr_.
 | 
				
			||||||
 | 
						*	
 | 
				
			||||||
 | 
					  * @details 	Позволяет обратиться к коилу по адресу относительно _arr_.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					#define	MB_Toogle_Coil_Local(_parr_, _coil_)					*MB_Set_Coil_Reg_Ptr(_parr_, _coil_) 	^= 	MB_Set_Coil_Mask(_coil_)
 | 
				
			||||||
 | 
					//--------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//------------------OTHER DEFINES-------------------
 | 
				
			||||||
 | 
					#define RegisterType_Holding				0
 | 
				
			||||||
 | 
					#define RegisterType_Input					1
 | 
				
			||||||
 | 
					#define RegisterType_Discrete				2
 | 
				
			||||||
 | 
					// create hadnles and settings for uart, tim, rs with _modbus_ name
 | 
				
			||||||
 | 
					//--------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef Divide_Up
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
						* @brief	Calc dividing including remainder
 | 
				
			||||||
 | 
						*	@param 	_val_		- делимое.
 | 
				
			||||||
 | 
						*	@param 	_div_		- делитель.
 | 
				
			||||||
 | 
						*	@details 	Если результат деления без остатка: он возвращается как есть
 | 
				
			||||||
 | 
											Если с остатком - округляется вверх
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					//#define Divide_Up(_val_, _div_)												(((_val_)%(_div_))? (_val_)/(_div_)+1 : (_val_)/_div_)	/* через тернарный оператор */
 | 
				
			||||||
 | 
					#define Divide_Up(_val_, _div_)												((_val_ - 1) / _div_) + 1																	/* через мат выражение */	
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef ByteSwap16
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 	Swap between Little Endian and Big Endian
 | 
				
			||||||
 | 
						* @param 	v 			- Переменная для свапа.
 | 
				
			||||||
 | 
					  * @return v (new)	- Свапнутая переменная.
 | 
				
			||||||
 | 
					  * @details 	Переключения между двумя типами хранения слова: HI-LO байты и LO-HI байты.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					#define ByteSwap16(v)																	(((v&0xFF00) >> (8)) | ((v&0x00FF) << (8)))
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					/** GENERAL_MODBUS_STUFF
 | 
				
			||||||
 | 
					  * @} 
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					/////////////////////////---FUNCTIONS---/////////////////////////////
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @addtogroup MODBUS_FUNCTIONS
 | 
				
			||||||
 | 
						* @ingroup 		MODBUS
 | 
				
			||||||
 | 
						* @brief 			Function for controling modbus communication
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					//----------------FUNCTIONS FOR USER----------------
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS
 | 
				
			||||||
 | 
						* @ingroup 		MODBUS_FUNCTIONS
 | 
				
			||||||
 | 
						* @brief 			Function for user use
 | 
				
			||||||
 | 
						@{
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					/* First set up of MODBUS */
 | 
				
			||||||
 | 
					void MODBUS_FirstInit(void);
 | 
				
			||||||
 | 
					/* Set or Reset Coil at its global address */
 | 
				
			||||||
 | 
					MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal);
 | 
				
			||||||
 | 
					/* Read Coil at its global address */
 | 
				
			||||||
 | 
					uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** MODBUS_DATA_ACCESS_FUNCTIONS
 | 
				
			||||||
 | 
					  * @} 
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					//---------PROCESS MODBUS COMMAND FUNCTIONS---------
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
 | 
				
			||||||
 | 
						* @ingroup 		MODBUS_FUNCTIONS
 | 
				
			||||||
 | 
						* @brief 			Function process commands
 | 
				
			||||||
 | 
						@{
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					/* Check is address valid for certain array */
 | 
				
			||||||
 | 
					MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB);
 | 
				
			||||||
 | 
					/* Define Address Origin for Input/Holding Registers */
 | 
				
			||||||
 | 
					MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType);
 | 
				
			||||||
 | 
					/* Define Address Origin for coils */
 | 
				
			||||||
 | 
					MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag);
 | 
				
			||||||
 | 
					/* Proccess command Read Coils (01 - 0x01) */
 | 
				
			||||||
 | 
					uint8_t MB_Read_Coils(RS_MsgTypeDef *modbus_msg);
 | 
				
			||||||
 | 
					/* Proccess command Read Holding Registers (03 - 0x03) */
 | 
				
			||||||
 | 
					uint8_t MB_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg);
 | 
				
			||||||
 | 
					/* Proccess command Read Input Registers (04 - 0x04) */
 | 
				
			||||||
 | 
					uint8_t MB_Read_Input_Regs(RS_MsgTypeDef *modbus_msg);
 | 
				
			||||||
 | 
					/* 	Proccess command Write Single Coils (05 - 0x05) */
 | 
				
			||||||
 | 
					uint8_t MB_Write_Single_Coil(RS_MsgTypeDef *modbus_msg);
 | 
				
			||||||
 | 
					/* Proccess command Write Multiple Coils (15 - 0x0F) */
 | 
				
			||||||
 | 
					uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg);
 | 
				
			||||||
 | 
					/* Proccess command Write Multiple Register (16 - 0x10) */
 | 
				
			||||||
 | 
					uint8_t MB_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** MODBUS_DATA_ACCESS_FUNCTIONS
 | 
				
			||||||
 | 
					  * @} 
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					/////////////////////////---FUNCTIONS---/////////////////////////////
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					/////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					/////////////////////////---CALC DEFINES---//////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TRACES DEFINES
 | 
				
			||||||
 | 
					#ifndef Trace_MB_UART_Enter
 | 
				
			||||||
 | 
					#define Trace_MB_UART_Enter()
 | 
				
			||||||
 | 
					#endif //Trace_MB_UART_Enter
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					#ifndef Trace_MB_UART_Exit
 | 
				
			||||||
 | 
					#define Trace_MB_UART_Exit()
 | 
				
			||||||
 | 
					#endif //Trace_MB_UART_Exit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef Trace_MB_TIM_Enter
 | 
				
			||||||
 | 
					#define Trace_MB_TIM_Enter()
 | 
				
			||||||
 | 
					#endif //Trace_MB_TIM_Enter
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					#ifndef Trace_MB_TIM_Exit
 | 
				
			||||||
 | 
					#define Trace_MB_TIM_Exit()
 | 
				
			||||||
 | 
					#endif //Trace_MB_TIM_Exit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif //__MODBUS_H_
 | 
				
			||||||
							
								
								
									
										39
									
								
								modbus_config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								modbus_config.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					**************************************************************************
 | 
				
			||||||
 | 
					* @file interface_config.h
 | 
				
			||||||
 | 
					* @brief Конфигурация для модбаса
 | 
				
			||||||
 | 
					*************************************************************************/
 | 
				
			||||||
 | 
					#include <Arduino.h>
 | 
				
			||||||
 | 
					#ifndef _MODBUS_CONFIG_H_
 | 
				
			||||||
 | 
					#define _MODBUS_CONFIG_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MODBUS PARAMS
 | 
				
			||||||
 | 
					#define MODBUS_DEVICE_ID 							1			///< девайс текущего устройства
 | 
				
			||||||
 | 
					#define MODBUS_TIMEOUT 						    5000 	///< максимальнйы тайтаут MB в тиках таймера
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// STRING OBJECTS MODBUS
 | 
				
			||||||
 | 
					#define MODBUS_VENDOR_NAME            "NIO-12"
 | 
				
			||||||
 | 
					#define MODBUS_PRODUCT_CODE           ""
 | 
				
			||||||
 | 
					#define MODBUS_REVISION               "Ver. 1.0"
 | 
				
			||||||
 | 
					#define MODBUS_VENDOR_URL             ""
 | 
				
			||||||
 | 
					#define MODBUS_PRODUCT_NAME           ""
 | 
				
			||||||
 | 
					#define MODBUS_MODEL_NAME             "STM32F103"
 | 
				
			||||||
 | 
					#define MODBUS_USER_APPLICATION_NAME  ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PERIPH FUNCTIONS AND HANDLERS
 | 
				
			||||||
 | 
					#define rs_huart                      Serial1 				//используемый uart
 | 
				
			||||||
 | 
					#define HUART_TypeDef                 HardwareSerial
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * @brief    Поменять комманды 0x03 и 0x04 местами (для LabView терминалки от двигателей)
 | 
				
			||||||
 | 
					  * @details  Терминалка от двигателей использует для чтения регистров комманду R_HOLD_REGS вместо R_IN_REGS
 | 
				
			||||||
 | 
					  *           Поэтому чтобы считывать Input Regs - надо поменять их местами.
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					//#define MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					/////////////////////////---CALC DEFINES---//////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					#endif //_MODBUS_CONFIG_H_
 | 
				
			||||||
							
								
								
									
										160
									
								
								modbus_data.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								modbus_data.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,160 @@
 | 
				
			|||||||
 | 
					/** 
 | 
				
			||||||
 | 
					**************************************************************************
 | 
				
			||||||
 | 
					* @file   modbus_data.h
 | 
				
			||||||
 | 
					* @brief    Заголовочный файл с описанием даты MODBUS.
 | 
				
			||||||
 | 
					* @details  Данный файл необходимо подключается в rs_message.h. После rs_message.h 
 | 
				
			||||||
 | 
					* подключается к основному проекту.
 | 
				
			||||||
 | 
					* 
 | 
				
			||||||
 | 
					* @defgroup MODBUS_DATA
 | 
				
			||||||
 | 
					* @ingroup  MODBUS
 | 
				
			||||||
 | 
					* @brief    Modbus data description
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					*************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _MODBUS_DATA_H_
 | 
				
			||||||
 | 
					#define _MODBUS_DATA_H_
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					#include "stdint.h"
 | 
				
			||||||
 | 
					//--------------DEFINES FOR REGISTERS---------------
 | 
				
			||||||
 | 
					// DEFINES FOR ARRAYS
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
					  * @addtogroup MODBUS_DATA_RERISTERS_DEFINES
 | 
				
			||||||
 | 
					  * @ingroup    MODBUS_DATA
 | 
				
			||||||
 | 
					  * @brief      Defines for registers
 | 
				
			||||||
 | 
					  Структура дефайна адресов
 | 
				
			||||||
 | 
					  @verbatim    
 | 
				
			||||||
 | 
					  Для массивов регистров:
 | 
				
			||||||
 | 
					    R_<NAME_ARRAY>_ADDR   -  модбас адресс первого регистра в массиве
 | 
				
			||||||
 | 
					    R_<NAME_ARRAY>_QNT    -  количество регистров в массиве
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  При добавлении новых массивов регистров, необходимо их добавить в функцию MB_DefineRegistersAddress
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							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);	// начало регистров хранения/входных
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					  @endverbatim
 | 
				
			||||||
 | 
					  * @{
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
					  * @brief Регистры хранения
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					typedef struct //MB_DataInRegsTypeDef
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  uint16_t data[10];
 | 
				
			||||||
 | 
					}MB_DataInRegsTypeDef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
					  * @brief Входные регистры 
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					typedef struct //MB_DataInRegsTypeDef
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  uint16_t data[10];
 | 
				
			||||||
 | 
					}MB_DataHoldRegsTypeDef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DEFINES FOR INPUT REGISTERS ARRAYS
 | 
				
			||||||
 | 
					#define   R_INPUT_ADDR                 0
 | 
				
			||||||
 | 
					#define   R_INPUT_QNT                  10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DEFINES FOR HOLDING REGISTERS ARRAYS
 | 
				
			||||||
 | 
					#define   R_HOLDING_ADDR                   0
 | 
				
			||||||
 | 
					#define   R_HOLDING_QNT                    10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					/** MODBUS_DATA_RERISTERS_DEFINES
 | 
				
			||||||
 | 
					  * @} 
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//----------------DEFINES FOR COILS-----------------
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
					  * @addtogroup MODBUS_DATA_COILS_DEFINES
 | 
				
			||||||
 | 
					  * @ingroup    MODBUS_DATA
 | 
				
			||||||
 | 
					  * @brief      Defines for coils
 | 
				
			||||||
 | 
					  @verbatim    
 | 
				
			||||||
 | 
					  Структура дефайна
 | 
				
			||||||
 | 
					  Для массивов коилов:
 | 
				
			||||||
 | 
					    C_<NAME_ARRAY>_ADDR   - модбас адресс первого коила в массиве
 | 
				
			||||||
 | 
					    C_<NAME_ARRAY>_QNT    - количество коилов в массиве (минимум 16)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  При добавлении новых массивов коилов, необходимо их добавить в функцию MB_DefineCoilsAddress
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(MB_Check_Address_For_Arr(Addr, Qnt, C_<NEW_ARRAY>_ADDR, C_<NEW_ARRAY>_QNT) == NO_ERRORS)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      *pCoils = MB_Set_Coil_Reg_Ptr(&<NEW_ARRAY>, Addr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @endverbatim
 | 
				
			||||||
 | 
					  * @{
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
					  * @brief     Коилы
 | 
				
			||||||
 | 
					  * @details   Желательно с помощью reserved делать стркутуру кратной 16-битам
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					typedef struct //MB_DataCoilsTypeDef
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  unsigned reserved:16;
 | 
				
			||||||
 | 
					}MB_DataCoilsTypeDef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DEFINES FOR COIL ARRAYS
 | 
				
			||||||
 | 
					#define C_CONTROL_ADDR                0
 | 
				
			||||||
 | 
					#define C_CONTROL_QNT                 16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** MODBUS_DATA_COILS_DEFINES
 | 
				
			||||||
 | 
					  * @} 
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					//-----------MODBUS DEVICE DATA SETTING-------------
 | 
				
			||||||
 | 
					// MODBUS DATA STRUCTTURE
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
					  * @brief Структура со всеми регистрами и коилами модбас 
 | 
				
			||||||
 | 
					  * @ingroup  MODBUS_DATA
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					typedef struct // tester modbus data
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  MB_DataInRegsTypeDef      InRegs;     ///< Modbus input registers @ref MB_DataInRegsTypeDef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MB_DataCoilsTypeDef       Coils;      ///< Modbus coils @ref MB_DataCoilsTypeDef
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  MB_DataHoldRegsTypeDef    HoldRegs;   ///< Modbus holding registers @ref MB_DataHoldRegsTypeDef
 | 
				
			||||||
 | 
					}MB_DataStructureTypeDef;
 | 
				
			||||||
 | 
					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_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					///////////////////////TEMP/OUTDATE/OTHER////////////////////
 | 
				
			||||||
							
								
								
									
										339
									
								
								rs_message.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								rs_message.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,339 @@
 | 
				
			|||||||
 | 
					/** 
 | 
				
			||||||
 | 
					**************************************************************************
 | 
				
			||||||
 | 
					* @file rs_message.c
 | 
				
			||||||
 | 
					* @brief Модуль для реализации протоколов по RS/UART.
 | 
				
			||||||
 | 
					**************************************************************************\
 | 
				
			||||||
 | 
					* @details
 | 
				
			||||||
 | 
					* Данный модуль реализует основные функции для приема и передачи сообщений
 | 
				
			||||||
 | 
					* по протоколу RS через UART в режиме прерываний. Реализована обработка
 | 
				
			||||||
 | 
					* приема и передачи данных, управление состояниями RS, а также функции для
 | 
				
			||||||
 | 
					* инициализации и управления периферией.
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* Реализованы следующие функции:
 | 
				
			||||||
 | 
					* - RS_Receive_IT() — запуск приема данных в прерывании по UART.
 | 
				
			||||||
 | 
					* - RS_Transmit_IT() — запуск передачи данных в прерывании по UART.
 | 
				
			||||||
 | 
					* - RS_Init() — инициализация структуры RS и привязка периферии.
 | 
				
			||||||
 | 
					* - RS_ReInit_UART() — переинициализация UART и перезапуск приема данных.
 | 
				
			||||||
 | 
					* - RS_Abort() — остановка работы RS/UART с очисткой флагов и структур.
 | 
				
			||||||
 | 
					* - RS_Handle_Receive_Start() — обработка старта приема данных по RS.
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* В модуле также определен буфер RS_Buffer[] для хранения принимаемых/передаваемых данных.
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* @note
 | 
				
			||||||
 | 
					* Для корректной работы модуля предполагается использование соответствующих
 | 
				
			||||||
 | 
					* обработчиков прерываний UART и таймера (RS_UART_Handler(), RS_TIM_Handler()),
 | 
				
			||||||
 | 
					* которые надо вызывать с обработчиках используемой периферии
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@verbatim
 | 
				
			||||||
 | 
					//-------------------Функции-------------------//
 | 
				
			||||||
 | 
					Functions: users
 | 
				
			||||||
 | 
					  -	RS_Parse_Message/RS_Collect_Message	Заполнение структуры сообщения и буфера
 | 
				
			||||||
 | 
					  -	RS_Response  									Ответ на сообщение
 | 
				
			||||||
 | 
					  - RS_Define_Size_of_RX_Message	Определение размера принимаемых данных
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Functions: general
 | 
				
			||||||
 | 
					  -	RS_Receive_IT									Ожидание комманды и ответ на неё
 | 
				
			||||||
 | 
					  -	RS_Transmit_IT								Отправление комманды и ожидание ответа
 | 
				
			||||||
 | 
					  -	RS_Init												Инициализация переферии и структуры для RS
 | 
				
			||||||
 | 
					  -	RS_ReInit_UART								Реинициализация UART для RS
 | 
				
			||||||
 | 
					  -	RS_Abort											Отмена приема/передачи по ЮАРТ
 | 
				
			||||||
 | 
					  -	RS_Init												Инициализация периферии и modbus handler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Functions: callback/handler
 | 
				
			||||||
 | 
					  - RS_Handle_Receive_Start				Функция для запуска приема или остановки RS
 | 
				
			||||||
 | 
					  - RS_Handle_Transmit_Start			Функция для запуска передачи или остановки RS
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  -	RS_UART_RxCpltCallback				Коллбек при окончании приема или передачи
 | 
				
			||||||
 | 
					    RS_UART_TxCpltCallback		
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					  - RS_UART_Handler								Обработчик прерывания для UART
 | 
				
			||||||
 | 
					  - RS_TIM_Handler								Обработчик прерывания для TIM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@endverbatim
 | 
				
			||||||
 | 
					*************************************************************************/
 | 
				
			||||||
 | 
					#include "rs_message.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t RS_Buffer[MSG_SIZE_MAX]; // uart buffer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//-------------------------------------------------------------------
 | 
				
			||||||
 | 
					//-------------------------GENERAL FUNCTIONS-------------------------
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * @brief 	Start receive IT.
 | 
				
			||||||
 | 
					  * @param 	hRS 		- указатель на хендлер RS.
 | 
				
			||||||
 | 
					  * @param 	RS_msg 	- указатель на структуру сообщения.
 | 
				
			||||||
 | 
					  * @return RS_RES	- статус о состоянии RS после инициализации приема.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) {
 | 
				
			||||||
 | 
					  if (hRS->f.RS_Busy || hRS->f.RX_Busy) return RS_BUSY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  RS_EnableReceive();
 | 
				
			||||||
 | 
					  RS_Set_Busy(hRS);
 | 
				
			||||||
 | 
					  RS_Set_RX_Flags(hRS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  hRS->pMessagePtr = RS_msg;
 | 
				
			||||||
 | 
					  hRS->lastByteTime = millis();
 | 
				
			||||||
 | 
					  hRS->RS_STATUS = RS_OK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return RS_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * @brief 	Start transmit IT.
 | 
				
			||||||
 | 
					  * @param 	hRS 		- указатель на хендлер RS.
 | 
				
			||||||
 | 
					  * @param 	RS_msg 	- указатель на структуру сообщения.
 | 
				
			||||||
 | 
					  * @return RS_RES	- статус о состоянии RS после инициализации передачи.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) {
 | 
				
			||||||
 | 
					  if (hRS->f.RS_Busy || hRS->f.TX_Busy) return RS_BUSY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  RS_StatusTypeDef RS_RES = RS_Collect_Message(hRS, RS_msg, hRS->pBufferPtr);
 | 
				
			||||||
 | 
					  if (RS_RES != RS_OK) {
 | 
				
			||||||
 | 
					    RS_Abort(hRS, ABORT_RS);
 | 
				
			||||||
 | 
					    RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
 | 
				
			||||||
 | 
					    return RS_RES;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  RS_EnableTransmit();
 | 
				
			||||||
 | 
					  RS_Set_Busy(hRS);
 | 
				
			||||||
 | 
					  RS_Set_TX_Flags(hRS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  hRS->pMessagePtr = RS_msg;
 | 
				
			||||||
 | 
					  hRS->huart->write(hRS->pBufferPtr, hRS->RS_Message_Size);
 | 
				
			||||||
 | 
					  hRS->lastByteTime = millis();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return RS_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 	Initialize UART and handle RS stucture.
 | 
				
			||||||
 | 
						* @param 	hRS 					- указатель на хендлер RS.
 | 
				
			||||||
 | 
						* @param 	suart 				- указатель на структуру с настройками UART.
 | 
				
			||||||
 | 
						* @param 	stim 					- указатель на структуру с настройками таймера.
 | 
				
			||||||
 | 
						* @param 	pRS_BufferPtr - указатель на буффер для приема-передачи по UART. Если он NULL, то поставиться библиотечный буфер.
 | 
				
			||||||
 | 
						* @return RS_RES				- статус о состоянии RS после инициализации.
 | 
				
			||||||
 | 
						* @note		Инициализация перефирии и структуры для приема-передачи по RS.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, HUART_TypeDef *SerialPort, uint8_t *pRS_BufferPtr) {
 | 
				
			||||||
 | 
					  if (!hRS || !SerialPort) return RS_ERR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  hRS->huart = SerialPort;
 | 
				
			||||||
 | 
					  hRS->pBufferPtr = pRS_BufferPtr ? pRS_BufferPtr : RS_Buffer;
 | 
				
			||||||
 | 
					  hRS->RS_STATUS = RS_OK;
 | 
				
			||||||
 | 
					  RS_Set_Free(hRS);
 | 
				
			||||||
 | 
					  RS_Reset_RX_Flags(hRS);
 | 
				
			||||||
 | 
					  RS_Reset_TX_Flags(hRS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  hRS->f.RX_Half = 0;
 | 
				
			||||||
 | 
					  hRS->lastByteTime = millis();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return RS_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
						* @brief 	Abort RS/UART.
 | 
				
			||||||
 | 
						* @param 	hRS 				- указатель на хендлер RS.
 | 
				
			||||||
 | 
						* @param 	AbortMode 	- выбор, что надо отменить.
 | 
				
			||||||
 | 
												- ABORT_TX:		 Отмена передачи по ЮАРТ, с очищением флагов TX,
 | 
				
			||||||
 | 
												- ABORT_RX:		 Отмена приема по ЮАРТ, с очищением флагов RX,
 | 
				
			||||||
 | 
												- ABORT_RX_TX: Отмена приема и передачи по ЮАРТ,
 | 
				
			||||||
 | 
												- ABORT_RS: 	 Отмена приема-передачи RS, с очищением всей структуры.
 | 
				
			||||||
 | 
						* @return RS_RES			- статус о состоянии RS после аборта.
 | 
				
			||||||
 | 
						* @note		Отмена работы UART в целом или отмена приема/передачи RS. 
 | 
				
			||||||
 | 
											Также очищается хендл hRS.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode) {
 | 
				
			||||||
 | 
					  if ((AbortMode & ABORT_RS) == 0) {
 | 
				
			||||||
 | 
					    if ((AbortMode & ABORT_RX) == ABORT_RX) RS_Reset_RX_Flags(hRS);
 | 
				
			||||||
 | 
					    if ((AbortMode & ABORT_TX) == ABORT_TX) RS_Reset_TX_Flags(hRS);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    RS_Clear_All(hRS);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  RS_Set_Free(hRS);
 | 
				
			||||||
 | 
					  hRS->RS_STATUS = RS_ABORTED;
 | 
				
			||||||
 | 
					  return RS_ABORTED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//-------------------------GENERAL FUNCTIONS-------------------------
 | 
				
			||||||
 | 
					//-------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//-------------------------------------------------------------------
 | 
				
			||||||
 | 
					//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
						* @brief 	Handle for starting receive.
 | 
				
			||||||
 | 
						* @param 	hRS 		- указатель на хендлер RS.
 | 
				
			||||||
 | 
						* @param 	RS_msg 	- указатель на структуру сообщения.
 | 
				
			||||||
 | 
						* @return RS_RES	- статус о состоянии RS после инициализации приема или окончания общения.
 | 
				
			||||||
 | 
						* @note		Определяет начинать прием команды/ответа или нет.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
 | 
				
			||||||
 | 
					{	
 | 
				
			||||||
 | 
						RS_StatusTypeDef RS_RES = RS_OK;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						switch(hRS->sRS_Mode)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							case SLAVE_ALWAYS_WAIT: 											// in slave mode with permanent waiting
 | 
				
			||||||
 | 
								RS_RES = RS_Receive_IT(hRS, RS_msg); break; // start receiving again
 | 
				
			||||||
 | 
							case SLAVE_TIMEOUT_WAIT:											// in slave mode with timeout waiting (start receiving cmd by request)
 | 
				
			||||||
 | 
								RS_Set_Free(hRS);	 RS_RES = RS_OK; break;		// end RS communication (set RS unbusy)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  if(RS_RES != RS_OK)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						return RS_RES;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/**  
 | 
				
			||||||
 | 
						* @brief 	Handle for starting transmit.
 | 
				
			||||||
 | 
						* @param 	hRS 		- указатель на хендлер RS.
 | 
				
			||||||
 | 
						* @param 	RS_msg 	- указатель на структуру сообщения.
 | 
				
			||||||
 | 
						* @return RS_RES	- статус о состоянии RS после инициализации передачи.
 | 
				
			||||||
 | 
						* @note		Определяет отвечать ли на команду или нет.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
 | 
				
			||||||
 | 
					{	
 | 
				
			||||||
 | 
						RS_StatusTypeDef RS_RES = RS_OK;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						switch(hRS->sRS_Mode)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							case SLAVE_ALWAYS_WAIT: 	// in slave mode always response
 | 
				
			||||||
 | 
							case SLAVE_TIMEOUT_WAIT:	// transmit response
 | 
				
			||||||
 | 
								RS_RES = RS_Transmit_IT(hRS, RS_msg); break; 
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					  if(RS_RES != RS_OK)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
						return RS_RES;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/**  
 | 
				
			||||||
 | 
						* @brief 	UART RX Callback: define behaviour after receiving parts of message.
 | 
				
			||||||
 | 
						* @param 	hRS 		- указатель на хендлер RS.
 | 
				
			||||||
 | 
						* @return RS_RES	- статус о состоянии RS после обработки приема.
 | 
				
			||||||
 | 
						* @note		Контролирует прием сообщения: определяет размер принимаемой посылки и обрабатывает его.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_UART_RxCpltCallback(RS_HandleTypeDef *hRS) {
 | 
				
			||||||
 | 
					  if (!hRS->f.RX_Half && hRS->sRS_RX_Size_Mode == RS_RX_Size_NotConst) {
 | 
				
			||||||
 | 
					    hRS->f.RX_Half = 1;
 | 
				
			||||||
 | 
					    uint32_t restSize = 0xFFFF;
 | 
				
			||||||
 | 
					    RS_StatusTypeDef res = RS_Define_Size_of_RX_Message(hRS, &restSize);
 | 
				
			||||||
 | 
					    if (res == RS_SKIP || restSize == 0xFFFF) {
 | 
				
			||||||
 | 
					      RS_Abort(hRS, ABORT_RX);
 | 
				
			||||||
 | 
					      return RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // parse received data
 | 
				
			||||||
 | 
					      RS_RES = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr); // parse message
 | 
				
			||||||
 | 
					      hRS->RS_Message_Size = NuRS_of_Rest_Bytes;
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // RESPONSE
 | 
				
			||||||
 | 
					      RS_RES = RS_Response(hRS, hRS->pMessagePtr);	
 | 
				
			||||||
 | 
					      return RS_RES;
 | 
				
			||||||
 | 
					    } 
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
						else // if we had received whole message
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							hRS->f.RX_Half = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//---------PROCESS DATA & ENDING RECEIVING--------
 | 
				
			||||||
 | 
							RS_Set_RX_End(hRS);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							// 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;	
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**  
 | 
				
			||||||
 | 
						* @brief 	UART TX Callback: define behaviour after transmiting message.
 | 
				
			||||||
 | 
						* @param 	hRS 		- указатель на хендлер RS.
 | 
				
			||||||
 | 
						* @return RS_RES	- статус о состоянии RS после обработки приема.
 | 
				
			||||||
 | 
						* @note		Определяет поведение RS после передачи сообщения.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						RS_StatusTypeDef RS_RES = RS_OK;
 | 
				
			||||||
 | 
						HAL_StatusTypeDef uart_res = 0;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//--------------ENDING TRANSMITTING-------------
 | 
				
			||||||
 | 
						RS_Set_TX_End(hRS);
 | 
				
			||||||
 | 
						RS_EnableReceive();
 | 
				
			||||||
 | 
					//  for(int i = 0; i < hRS->sRS_Timeout; i++);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//-----------START RECEIVING or END RS----------
 | 
				
			||||||
 | 
						RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						return RS_RES;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**  
 | 
				
			||||||
 | 
						* @brief 	Handler for UART.
 | 
				
			||||||
 | 
						* @param 	hRS 		- указатель на хендлер RS.
 | 
				
			||||||
 | 
						* @note		Обрабатывает ошибки если есть и вызывает RS Коллбеки.
 | 
				
			||||||
 | 
						*					Добавить вызов этой функции в UARTx_IRQHandler() после HAL_UART_IRQHandler().
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					void RS_UART_Handler(RS_HandleTypeDef *hRS) {
 | 
				
			||||||
 | 
					  while (hRS->huart->available()) {
 | 
				
			||||||
 | 
					    uint8_t b = hRS->huart->read();
 | 
				
			||||||
 | 
					    hRS->pBufferPtr[hRS->RS_Message_Size++] = b;
 | 
				
			||||||
 | 
					    hRS->lastByteTime = millis();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (hRS->f.RX_Busy && (hRS->RS_Message_Size >= RX_FIRST_PART_SIZE) && !hRS->f.RX_Half)
 | 
				
			||||||
 | 
					      RS_UART_RxCpltCallback(hRS);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * @brief  Handler for TIM (timeout check).
 | 
				
			||||||
 | 
					  * @param  hRS - указатель на хендлер RS.
 | 
				
			||||||
 | 
					  * @note   Проверяет таймаут между байтами. Если превышен, сбрасывает RX и перезапускает прием.
 | 
				
			||||||
 | 
					  *         Вызывать в TIMx_IRQHandler() после HAL_TIM_IRQHandler().
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					void RS_TIM_Handler(RS_HandleTypeDef *hRS) {
 | 
				
			||||||
 | 
					    if (!hRS) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsigned long now = millis();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Если идет прием данных и есть таймаут
 | 
				
			||||||
 | 
					    if (hRS->f.RX_Busy && hRS->sRS_Timeout > 0) {
 | 
				
			||||||
 | 
					        if ((now - hRS->lastByteTime) >= hRS->sRS_Timeout) {
 | 
				
			||||||
 | 
					            // таймаут истек → abort RX и restart
 | 
				
			||||||
 | 
					            RS_Abort(hRS, ABORT_RX);
 | 
				
			||||||
 | 
					            RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Можно также проверять TX, если нужна логика таймаута передачи
 | 
				
			||||||
 | 
					    if (hRS->f.TX_Busy && hRS->sRS_Timeout > 0) {
 | 
				
			||||||
 | 
					        if ((now - hRS->lastByteTime) >= hRS->sRS_Timeout) {
 | 
				
			||||||
 | 
					            RS_Abort(hRS, ABORT_TX);
 | 
				
			||||||
 | 
					            // TX не рестартим автоматически
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// weak functions
 | 
				
			||||||
 | 
					__attribute__((weak)) RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { return RS_ERR; }
 | 
				
			||||||
 | 
					__attribute__((weak)) RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff) { return RS_ERR; }
 | 
				
			||||||
 | 
					__attribute__((weak)) RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff) { return RS_ERR; }
 | 
				
			||||||
 | 
					__attribute__((weak)) RS_StatusTypeDef RS_Define_Size_of_RX_Message(RS_HandleTypeDef *hRS, uint32_t *rx_data_size) { return RS_ERR; }
 | 
				
			||||||
							
								
								
									
										256
									
								
								rs_message.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								rs_message.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,256 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					**************************************************************************
 | 
				
			||||||
 | 
					* @file rs_message.h
 | 
				
			||||||
 | 
					* @brief Заголовочный файл для модуля реализации протоколов по RS/UART.
 | 
				
			||||||
 | 
					**************************************************************************
 | 
				
			||||||
 | 
					* @defgroup RS_TOOLS
 | 
				
			||||||
 | 
					* @brief 		Всякое для работы по UART/RS
 | 
				
			||||||
 | 
					**************************************************************************
 | 
				
			||||||
 | 
					@details
 | 
				
			||||||
 | 
					**************************************************************************
 | 
				
			||||||
 | 
					Для настройки RS/UART под нужный протокол, необходимо:
 | 
				
			||||||
 | 
					  - Определить структуру сообщения RS_MsgTypeDef и 
 | 
				
			||||||
 | 
					  дефайны RX_FIRST_PART_SIZE и MSG_SIZE_MAX.
 | 
				
			||||||
 | 
					  - Подключить этот файл в раздел rs_message.h.
 | 
				
			||||||
 | 
						- Определить функции для обработки сообщения: RS_Parse_Message(), 
 | 
				
			||||||
 | 
					  RS_Collect_Message(), RS_Response(), RS_Define_Size_of_RX_Message()
 | 
				
			||||||
 | 
						- Добавить UART/TIM Handler в Хендлер используемых UART/TIM.
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					Так же данный модуль использует счетчики 
 | 
				
			||||||
 | 
					**************************************************************************
 | 
				
			||||||
 | 
					@verbatim
 | 
				
			||||||
 | 
					Визуальное описание. Форматирование сохраняется как в коде.
 | 
				
			||||||
 | 
					@endverbatim
 | 
				
			||||||
 | 
					*************************************************************************/
 | 
				
			||||||
 | 
					#ifndef __RS_LIB_H_
 | 
				
			||||||
 | 
					#define __RS_LIB_H_
 | 
				
			||||||
 | 
					#include "modbus.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					////////////////////////////---DEFINES---////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Check that all defines required by RS are defined */
 | 
				
			||||||
 | 
					#ifndef MSG_SIZE_MAX
 | 
				
			||||||
 | 
					#error Define MSG_SIZE_MAX (Maximum size of message). This is necessary to create buffer for UART.
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef RX_FIRST_PART_SIZE
 | 
				
			||||||
 | 
					#error Define RX_FIRST_PART_SIZE (Size of first part of message). This is necessary to receive the first part of the message, from which determine the size of the remaining part of the message.
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Clear message-uart buffer */
 | 
				
			||||||
 | 
					#define RS_Clear_Buff(_buff_)              for(int i=0; i<MSG_SIZE_MAX;i++) _buff_[i] = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Set/Reset flags */
 | 
				
			||||||
 | 
					#define RS_Set_Free(_hRS_)                 (_hRS_->f.RS_Busy = 0)
 | 
				
			||||||
 | 
					#define RS_Set_Busy(_hRS_)                 (_hRS_->f.RS_Busy = 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RS_Set_RX_Flags(_hRS_)             do { \
 | 
				
			||||||
 | 
					                                              _hRS_->f.RX_Busy = 1;  \
 | 
				
			||||||
 | 
					                                              _hRS_->f.RX_Done = 0;  \
 | 
				
			||||||
 | 
					                                              _hRS_->f.RX_Half = 0;  \
 | 
				
			||||||
 | 
					                                          } while(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RS_Set_RX_Active_Flags(_hRS_)      (_hRS_->f.RX_Ongoing = 1)
 | 
				
			||||||
 | 
					#define RS_Set_TX_Flags(_hRS_)             do { \
 | 
				
			||||||
 | 
					                                              _hRS_->f.TX_Busy = 1;  \
 | 
				
			||||||
 | 
					                                              _hRS_->f.TX_Done = 0;  \
 | 
				
			||||||
 | 
					                                          } while(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RS_Reset_RX_Active_Flags(_hRS_)    (_hRS_->f.RX_Ongoing = 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RS_Reset_RX_Flags(_hRS_)           do { \
 | 
				
			||||||
 | 
					                                              RS_Reset_RX_Active_Flags(_hRS_); \
 | 
				
			||||||
 | 
					                                              _hRS_->f.RX_Busy = 0;            \
 | 
				
			||||||
 | 
					                                              _hRS_->f.RX_Done = 0;            \
 | 
				
			||||||
 | 
					                                              _hRS_->f.RX_Half = 0;            \
 | 
				
			||||||
 | 
					                                          } while(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RS_Reset_TX_Flags(_hRS_)           do { \
 | 
				
			||||||
 | 
					                                              _hRS_->f.TX_Busy = 0;            \
 | 
				
			||||||
 | 
					                                              _hRS_->f.TX_Done = 0;            \
 | 
				
			||||||
 | 
					                                          } while(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RS_Set_RX_End_Flag(_hRS_)          (_hRS_->f.RX_Done = 1)
 | 
				
			||||||
 | 
					#define RS_Set_TX_End_Flag(_hRS_)          (_hRS_->f.TX_Done = 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RS_Set_RX_End(_hRS_)               do { RS_Reset_RX_Flags(_hRS_); RS_Set_RX_End_Flag(_hRS_); } while(0)
 | 
				
			||||||
 | 
					#define RS_Set_TX_End(_hRS_)               do { RS_Reset_TX_Flags(_hRS_); RS_Set_TX_End_Flag(_hRS_); } while(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Clear all RS stuff */
 | 
				
			||||||
 | 
					#define RS_Clear_All(_hRS_)                do { \
 | 
				
			||||||
 | 
					                                              RS_Clear_Buff(_hRS_->pBufferPtr); \
 | 
				
			||||||
 | 
					                                              RS_Reset_RX_Flags(_hRS_);         \
 | 
				
			||||||
 | 
					                                              RS_Reset_TX_Flags(_hRS_);         \
 | 
				
			||||||
 | 
					                                          } while(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RS_Is_RX_Busy(_hRS_)               (_hRS_->f.RX_Busy == 1)
 | 
				
			||||||
 | 
					#define RS_Is_TX_Busy(_hRS_)               (_hRS_->f.TX_Busy == 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* For Arduino we can redefine later if needed */
 | 
				
			||||||
 | 
					#ifndef RS_EnableReceive
 | 
				
			||||||
 | 
					#define RS_EnableReceive()
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef RS_EnableTransmit
 | 
				
			||||||
 | 
					#define RS_EnableTransmit()
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					////////////////////////////---DEFINES---////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					///////////////////////---STRUCTURES & ENUMS---//////////////////////
 | 
				
			||||||
 | 
					//------------------ENUMERATIONS--------------------
 | 
				
			||||||
 | 
					/** @brief Enums for respond CMD about RS status */
 | 
				
			||||||
 | 
					typedef enum		// RS_StatusTypeDef
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* IN-CODE STATUS (start from 0x01, and goes up)*/
 | 
				
			||||||
 | 
						/*0x01*/	RS_OK = 0x01,
 | 
				
			||||||
 | 
						/*0x02*/	RS_ERR,	
 | 
				
			||||||
 | 
						/*0x03*/	RS_ABORTED,	
 | 
				
			||||||
 | 
						/*0x04*/	RS_BUSY,		
 | 
				
			||||||
 | 
						/*0x05*/	RS_SKIP,	
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/*0x06*/	RS_COLLECT_MSG_ERR,
 | 
				
			||||||
 | 
						/*0x07*/	RS_PARSE_MSG_ERR,
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// reserved values
 | 
				
			||||||
 | 
					//	/*0x00*/ 	RS_UNKNOWN_ERR = 				0x00, ///< reserved for case, if no one error founded (nothing changed response from zero)
 | 
				
			||||||
 | 
					}RS_StatusTypeDef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @brief Enums for RS Modes */
 | 
				
			||||||
 | 
					typedef enum	// RS_ModeTypeDef
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						SLAVE_ALWAYS_WAIT =				0x01,		///< Slave mode with infinity waiting
 | 
				
			||||||
 | 
						SLAVE_TIMEOUT_WAIT = 			0x02,		///< Slave mode with waiting with timeout
 | 
				
			||||||
 | 
					//	MASTER = 									0x03,		///< Master mode
 | 
				
			||||||
 | 
					}RS_ModeTypeDef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @brief Enums for Abort modes */
 | 
				
			||||||
 | 
					typedef enum	// RS_AbortTypeDef
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ABORT_TX = 			0x01,		///< Abort transmit
 | 
				
			||||||
 | 
						ABORT_RX = 			0x02,		///< Abort receive
 | 
				
			||||||
 | 
						ABORT_RX_TX =		0x03,		///< Abort receive and transmit
 | 
				
			||||||
 | 
						ABORT_RS = 			0x04,		///< Abort uart and reset RS structure
 | 
				
			||||||
 | 
					}RS_AbortTypeDef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @brief Enums for RX Size modes */
 | 
				
			||||||
 | 
					typedef enum	// RS_RXSizeTypeDef
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						RS_RX_Size_Const = 			0x01,		///< size of receiving message is constant
 | 
				
			||||||
 | 
						RS_RX_Size_NotConst = 	0x02,		///< size of receiving message isnt constant
 | 
				
			||||||
 | 
					} RS_RX_SizeTypeDef;
 | 
				
			||||||
 | 
					//-----------STRUCTURE FOR HANDLE RS------------
 | 
				
			||||||
 | 
					/** @brief Struct for flags RS */
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned 									RX_Half:1;						///< flag: 0 - receiving msg before ByteCnt, 	0 - receiving msg after ByteCnt
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						unsigned 									RS_Busy:1;						///< flag: 1 - RS is busy, 0 - RS isnt busy		
 | 
				
			||||||
 | 
						unsigned 									RX_Ongoing:1;				  ///< flag: 1 - receiving data right now, 	0 - waiting for receiving data
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
						unsigned 									RX_Busy:1;						///< flag: 1 - receiving is active, 	0 - receiving isnt active
 | 
				
			||||||
 | 
						unsigned 									TX_Busy:1;						///< flag: 1 - transmiting is active, 0 - transmiting isnt active				
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						unsigned 									RX_Done:1;						///< flag: 1 - receiving is done, 	0 - receiving isnt done	
 | 
				
			||||||
 | 
						unsigned 									TX_Done:1;						///< flag: 1 - transmiting is done, 0 - transmiting isnt done	
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						// setted by user
 | 
				
			||||||
 | 
						unsigned 									MessageHandled:1;		  ///< flag: 1 - RS command is handled, 				0 - RS command isnt handled yet
 | 
				
			||||||
 | 
						unsigned 									EchoResponse:1;			  ///< flag: 1 - response with received msg,		0 - response with own msg
 | 
				
			||||||
 | 
						unsigned 									DeferredResponse:1;	  ///< flag: 1 - response not in interrupt, 		0 - response in interrupt
 | 
				
			||||||
 | 
						unsigned 									ReInit_UART:1;				///< flag: 1 - need to reinitialize uart, 		0 - nothing	
 | 
				
			||||||
 | 
					}RS_FlagsTypeDef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
						* @brief 	Handle for RS communication.
 | 
				
			||||||
 | 
						* @note 	Prefixes: h - handle, s - settings, f - flag
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					typedef struct	// RS_HandleTypeDef
 | 
				
			||||||
 | 
					{		
 | 
				
			||||||
 | 
						/* MESSAGE */
 | 
				
			||||||
 | 
						uint8_t								    ID;								    ///< ID of RS "channel"
 | 
				
			||||||
 | 
						RS_MsgTypeDef 						*pMessagePtr;					///< pointer to message struct
 | 
				
			||||||
 | 
						uint8_t 							    *pBufferPtr;					///< pointer to message buffer
 | 
				
			||||||
 | 
						uint32_t							    RS_Message_Size;			///< size of whole message, not only data
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/* HANDLERS and SETTINGS */
 | 
				
			||||||
 | 
						HUART_TypeDef							*huart;							  ///< handler for used uart
 | 
				
			||||||
 | 
						void 								      *htim;							  ///< handler for used tim
 | 
				
			||||||
 | 
						RS_ModeTypeDef						sRS_Mode;						  ///< setting: slave or master @ref RS_ModeTypeDef
 | 
				
			||||||
 | 
						uint16_t 							    sRS_Timeout;					///< setting: timeout in ms
 | 
				
			||||||
 | 
						RS_RX_SizeTypeDef					sRS_RX_Size_Mode;			///< setting: 1 - not const, 0 - const 
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/* FLAGS */		
 | 
				
			||||||
 | 
						RS_FlagsTypeDef						f;								    ///< These flags for controling receive/transmit
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
						/* RS STATUS */
 | 
				
			||||||
 | 
					  unsigned long             lastByteTime;
 | 
				
			||||||
 | 
						RS_StatusTypeDef 					RS_STATUS;						///< RS status
 | 
				
			||||||
 | 
					}RS_HandleTypeDef;
 | 
				
			||||||
 | 
					extern RS_HandleTypeDef hmodbus1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///////////////////////---STRUCTURES & ENUMS---//////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					///////////////////////////---FUNCTIONS---///////////////////////////
 | 
				
			||||||
 | 
					//----------------FUNCTIONS FOR PROCESSING MESSAGE-------------------
 | 
				
			||||||
 | 
					/*--------------------Defined by users purposes--------------------*/
 | 
				
			||||||
 | 
					/* Respond accord to received message */
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Collect message in buffer to transmit it */
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Parse message from buffer to process it */
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define size of RX Message that need to be received */
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Define_Size_of_RX_Message(RS_HandleTypeDef *hRS, uint32_t *rx_data_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//-------------------------GENERAL FUNCTIONS-------------------------
 | 
				
			||||||
 | 
					/*-----------------Should be called from main code-----------------*/
 | 
				
			||||||
 | 
					/* Initialize UART and handle RS stucture */
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, HUART_TypeDef *huart, uint8_t *pRS_BufferPtr);
 | 
				
			||||||
 | 
					/* Start receive IT */
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
 | 
				
			||||||
 | 
					/* Start transmit IT */
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
 | 
				
			||||||
 | 
					/* Abort RS/UART */
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode);
 | 
				
			||||||
 | 
					//-------------------------GENERAL FUNCTIONS-------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//-------------------------------------------------------------------
 | 
				
			||||||
 | 
					//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
 | 
				
			||||||
 | 
					/* Handle for starting receive */
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
 | 
				
			||||||
 | 
					/* Handle for starting transmit */
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
 | 
				
			||||||
 | 
					/* UART RX Callback: define behaviour after receiving parts of message */
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_UART_RxCpltCallback(RS_HandleTypeDef *hRS);
 | 
				
			||||||
 | 
					/* UART TX Callback: define behaviour after transmiting message */
 | 
				
			||||||
 | 
					RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS);
 | 
				
			||||||
 | 
					/* Handler for UART */
 | 
				
			||||||
 | 
					void RS_UART_Handler(RS_HandleTypeDef *hRS);
 | 
				
			||||||
 | 
					/* Handler for TIM */
 | 
				
			||||||
 | 
					void RS_TIM_Handler(RS_HandleTypeDef *hRS);
 | 
				
			||||||
 | 
					//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
 | 
				
			||||||
 | 
					///////////////////////////---FUNCTIONS---///////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef printf_rs_err
 | 
				
			||||||
 | 
					#define printf_rs_err(...)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef printf_rs
 | 
				
			||||||
 | 
					#define printf_rs(...)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif // __RS_LIB_H_
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user