← Back to dashboard

File view

LDN_MODBUS_MASTER.LIB

1
/*
2
***** Comm Port Pin Out *****
3
4
   SATA  			   DB-9
5
6
7	GND				9
7
6	RS485 A 		8	RS232 CTS
8
5	RS485 B 		7
9
4	RS232 CTS   	6	RS485 B
10
3	RS232 RX  		5	GND
11
2	RS232 TX 		4
12
1	GND          	3  RS232 TX
13
					2  RS232 RX
14
					1	RS485 A
15
*/
16
17
/*** BeginHeader
18
*/
19
#ifndef _LDN_MODBUS_MASTER_
20
#define _LDN_MODBUS_MASTER_
21
22
#define DINBUFSIZE			127
23
#define DOUTBUFSIZE			127
24
#define RS485_TX_ENABLE_BIT 2
25
#define MB_OFFSET				0
26
#define USE_MODBUS_CRC
27
28
// Comm time with a LDN takes 130 ms w/  DataReady writes
29
//								  and  70 ms w/0 writes
30
31
#ifdef MODBUS_S_ON
32
   #define PING_INTERVAL   500
33
#else
34
	#define PING_INTERVAL   250
35
#endif
36
37
38
#define  MODBUS_SERIAL_MASTER
39
40
// Modbus libraray diagnostics setting
41
#define MODBUS_DEBUG_PRINT 0x000	// set to 0 for no debug printout
42
												// 1 = DIO config
43
	                              	// 2 = DIO write
44
	                              	// 4 = HCO config
45
	                              	// 8 = HCO write
46
	                              	// 10 = DAC
47
	                              	// 20 = A/D
48
	                              	// 800 = MODBUS packet
49
50
#define MODBUS_DEBUG debug
51
52
/*** EndHeader */
53
/*** BeginHeader
54
55
GetLDNReg,
56
SetLDNReg,
57
MODBUS_Master_tick,
58
LDN_MASTER_Init,
59
MODBUS_Master_Serial_Init
60
61
*/
62
63
64
void MODBUS_Master_tick					(void);
65
void LDN_MASTER_Init					(void);
66
void SetLDNReg							(int chn, int idx, int val);
67
int  GetLDNReg			  				(int chn, int idx);
68
int  MODBUS_Master_Serial_Init 			(void);
69
70
// LDN Registry List
71
enum {
72
  RESET				= 0,
73
  AUTH_REQUEST		= 1,
74
  SET_PRES,
75
  RESIL,
76
  CURRENT_LIMIT,
77
  TIME_FACTOR,
78
  RESERVED_WRITE,
79
  SHUNT_PRES,
80
  MONITOR_PRES,
81
  WRITE_CONFIRM,
82
  MONITOR_COMPLETE,
83
  SHUNT_COMPLETE,
84
  PRESSURE,
85
  LDN_STATE,
86
  CURRENT_TEST,
87
  CURRENT_LR,
88
  LEAK_RATE,
89
  IS_MODULES_STATE,
90
  CV_TEMP,
91
  CV_STATE,
92
  RESERVED_READ,
93
  MODBUS_ADDRESS,
94
  CONTROLLER_SERIES,
95
  SOFTWARE_VERSION,
96
  HARDWARE_VERSION,
97
  NODE_REG_LEN
98
};
99
100
enum {
101
  LDN_STANDBY	= 0,
102
  LDN_SHUNT		= 1,
103
  LDN_MONITOR,
104
  LDN_AUTH,
105
  LDN_ALARM,
106
  LDN_SLEEP
107
};
108
109
int Serial_timeout;
110
111
/*** EndHeader */
112
113
int  MBM_Send_ADU 					(char * ADUaddress,  int ByteCount );
114
int  MODBUS_Serial_Tx 				(char * Packet, 		int ByteCount );
115
int  MODBUS_Serial_Rx 				(char * DataAddress, int ByteCount );
116
117
void ser485Tx() {BitWrPortI(PCDR, &PCDRShadow, 1, RS485_TX_ENABLE_BIT);}
118
void ser485Rx() {BitWrPortI(PCDR, &PCDRShadow, 0, RS485_TX_ENABLE_BIT);}
119
120
int RldnMbReg		[N_LDN][NODE_REG_LEN+1];
121
int WldnMbReg		[N_LDN][WRITE_CONFIRM];
122
123
Ms	  PingTimer;
124
int  PingLDN;
125
126
// Init ************************************************************************
127
void LDN_MASTER_Init(void) {
128
   uint8_t 	i;
129
   uint8_t 	j;
130
131
   PingTimer = MS_TIMER;
132
   PingLDN = 0;
133
134
   for (i = 0 ; i < N_LDN ; i++) {
135
   	for (j = 0 ; j < NODE_REG_LEN  ; j++)
136
			RldnMbReg[i][j] = 0;
137
		for (j = 0 ; j < WRITE_CONFIRM ; j++)
138
			WldnMbReg[i][j] = 0;
139
      	LDNS[i].RmbReg 		= RldnMbReg[i];
140
		LDNS[i].WmbReg 		= WldnMbReg[i];
141
		LDNS[i].Idx	   		= i;
142
		LDNS[i].MbAddr			= i + 1;
143
		LDNS[i].Active			= 0;
144
		LDNS[i].ErrorCnt		= 0;
145
   	LDNS[i].DataReady		= 0;
146
   	LDNS[i].Pressure		= 20.0;
147
148
   	LDNS[i].RmbReg[PRESSURE] = 2000;
149
   }
150
}
151
152
// Master Serial Init **********************************************************
153
int MODBUS_Master_Serial_Init ( void )
154
{	
155
	auto float timeout;
156
	char dummy;
157
   	unsigned long nowtime;
158
159
	printf("Init LDN Modbus ...\n");
160
	timeout = 5*11*1000.0/(float)BaudRate[MB_MASTER_BAUD_IDX];
161
   	Serial_timeout = (int)(timeout+.5);	
162
   	if ( Serial_timeout < 2 ) Serial_timeout = 2; 
163
164
   	BitWrPortI (PCFR, &PCFRShadow, 1, 0); 
165
166
   	WrPortI (SDCR, &SDCRShadow, 0x00); 
167
 
168
169
   	serDparity(PARAM_NOPARITY);
170
   	serDopen(BaudRate[MB_MASTER_BAUD_IDX]);
171
172
	ser485Rx();	
173
   	serDrdFlush();
174
   	while (serDrdUsed() > 0)
175
   	{
176
   		serDread(&dummy, 1, 100);
177
      	nowtime =MS_TIMER;
178
      	while (MS_TIMER - nowtime < 10) 
179
		  {
180
181
		  }
182
   }
183
	return MB_SUCCESS;
184
} // MODBUS_Serial_Init
185
186
// Modbus Serial Tick **********************************************************
187
void MODBUS_Master_tick(void)
188
{
189
   	int i;
190
   	int j;
191
   	int result;
192
	TimeStatStPtr MBStat;
193
	
194
	MBStat = &CycStat[1];
195
	result = 0;
196
197
   if (MS_TIMER - PingTimer > PING_INTERVAL) 
198
   {
199
   	MBStat->LastPass = MS_TIMER;
200
   	i = PingLDN;
201
      if (LDNS[i].Active) 
202
	  {
203
      	// Read Regs
204
         result = MBM_ReadRegs(LDNS[i].MbAddr, LDNS[i].RmbReg, MB_OFFSET, NODE_REG_LEN);
205
206
         // If Read Successful
207
         if (result != MB_SUCCESS) 
208
		 {
209
			LDNS[i].ErrorCnt++;
210
         	printf("LDN %d: MB Read Error \n", i);
211
         }
212
         else 
213
		 {
214
            LDNS[i].ErrorCnt = 0;
215
            LDNS[i].DataReady = 1;
216
217
				// Check for DataReady writes
218
				for (j = 0 ; j < WRITE_CONFIRM ; j++) 
219
				{
220
					if (LDNS[i].RmbReg[j] != LDNS[i].WmbReg[j])
221
						LDNS[i].DataReady = 0;
222
				}
223
224
				// if no writes Clear LDN DataReady Write Flag
225
				if (LDNS[i].DataReady && LDNS[i].RmbReg[WRITE_CONFIRM]) 
226
				{
227
					printf("LDN %d: MB Writes Sent\n", i);
228
					MsDelay(10);
229
					result += MBM_WriteReg(LDNS[i].MbAddr, WRITE_CONFIRM + MB_OFFSET, 0);
230
				}
231
	         else if (LDNS[i].DataReady == 0) 
232
			 {
233
	          	if (LDNS[i].RmbReg[WRITE_CONFIRM] == 0) 
234
				  {		
235
					// Write DataReady Flag
236
	          	   	printf("LDN %d: New MB Write group\n", i);
237
		         	MsDelay(10);
238
	         		result += MBM_WriteReg(LDNS[i].MbAddr, WRITE_CONFIRM + MB_OFFSET, 1);
239
	         	}
240
	         	// Write DataReady Values
241
	            for (j = 0 ; j < WRITE_CONFIRM ; j++) 
242
				{
243
	               if (LDNS[i].RmbReg[j] != LDNS[i].WmbReg[j]) 
244
				   {
245
	               		MsDelay(10);
246
	                  	result += MBM_WriteReg(LDNS[i].MbAddr, j + MB_OFFSET, LDNS[i].WmbReg[j]);
247
	               }
248
	            }
249
	         }
250
	         if (result != MB_SUCCESS)
251
			 {
252
	            LDNS[i].ErrorCnt++;
253
	            printf("LDN %d: Write Error\n", i);
254
	         }
255
	      }
256
	      if (MBStat->MaxMs < MS_TIMER - MBStat->LastPass)
257
		  {
258
	      	 MBStat->MaxMs = MS_TIMER - MBStat->LastPass;
259
		  }
260
	      if (MBStat->AvgMs == 0.0)
261
		  {
262
   		    MBStat->AvgMs = (float)(MS_TIMER - MBStat->LastPass);
263
		  }
264
   		else
265
		   {
266
     	   	 MBStat->AvgMs = (MBStat->AvgMs + (float)(MS_TIMER - MBStat->LastPass)) / 2.0;
267
		   }
268
	   }
269
270
      if (++PingLDN >= N_LDN)
271
	  {
272
      	PingLDN = 0;
273
	  }
274
      else if (LDNS[PingLDN].Active == 0)
275
	  {
276
    		PingLDN = 0;
277
	  }
278
279
      PingTimer = MS_TIMER; 
280
   }
281
}
282
283
/* START FUNCTION DESCRIPTION ********************************************
284
MODBUS_Serial_Tx		<Modbus_Slave_BL26xx.lib>
285
286
SYNTAX:			int MODBUS_Serial_Tx ( char *Packet, int ByteCount );
287
288
DESCRIPTION:	Transmit a Modbus packet to a "downstream" device.
289
					Calculate the CRC and append to the packet.
290
291
PARAMETER1:		address of packet - must have two byte pad at end for
292
					inclusion of CRC word
293
294
PARAMETER2:		number of bytes in the packet
295
296
RETURN VALUE:	MB_SUCCESS
297
298
END DESCRIPTION **********************************************************/
299
300
int MODBUS_Serial_Tx ( char *Packet, int ByteCount )
301
{	
302
	auto int CalcCRC,i;
303
	Ms txTimeout;
304
305
// insert CRC
306
#ifndef USE_MODBUS_CRC
307
	CalcCRC = getcrc ( Packet, ByteCount, 0xFFFF );
308
#else
309
	CalcCRC = MODBUS_CRC(Packet, ByteCount);
310
#endif
311
// Backwards for some reason...
312
313
	Packet[ByteCount+1] = CalcCRC;
314
   	Packet[ByteCount] = CalcCRC >> 8;
315
	ByteCount+=2;
316
317
#if MODBUS_DEBUG_PRINT & 0x800
318
	printf ( "Ser Tx:" );
319
	for ( i=0; i<ByteCount; i++ ) printf ( " %02X", Packet[i] );
320
	printf ( "\n\r" );
321
#endif
322
323
	ser485Tx();									// enable the RS485 transmitter
324
   	serDrdFlush();								// clear the read FIFO
325
   	serDwrite ( Packet, ByteCount );			// send the data
326
   	txTimeout = MS_TIMER;
327
 while ( serDrdUsed() != ByteCount && MS_TIMER < txTimeout + 500); 
328
 {
329
 	// wait for all bytes to be transmitted
330
	ser485Rx();									// disable the RS485 transmitter
331
   	serDrdFlush();								// clear the read FIFO
332
 }
333
	return MB_SUCCESS;						// show success
334
} // MODBUS_Serial_Tx
335
336
/* START FUNCTION DESCRIPTION *********************************************
337
MODBUS_Serial_Rx			<Modbus_Slave_BL26xx.lib>
338
339
DESCRIPTION:	Receive the response from the Modbus Slave
340
					Uses the global variable Serial_timeout
341
					It is the responsibility of the caller to handle
342
					a timeout if required.
343
344
PARAMETER1:		address to put the data
345
346
RETURN VALUE:	0 = no message
347
					+n = number of bytes with valid CRC
348
               MB_CRC_ERROR = invalid CRC
349
350
END DESCRIPTION **********************************************************/
351
352
int MODBUS_Serial_Rx ( char * DataAddress, int RegCount )
353
{	
354
	auto int RxCRC, CalcCRC;
355
	auto int ByteCount,i, reg, p1;
356
   	auto int backwards;
357
358
	ByteCount = serDread( DataAddress, RegCount*2+16, Serial_timeout );
359
360
   if ( ByteCount )
361
   {
362
	#if MODBUS_DEBUG_PRINT & 0x800
363
		printf ( "\n\rSer Rx:" );
364
		for ( i=0; i<ByteCount; i++ ) printf ( " %02X", DataAddress[i] );
365
	#endif
366
367
   	ByteCount -= 2;						// adjust for CRC
368
	#ifndef USE_MODBUS_CRC
369
		CalcCRC = getcrc ( DataAddress, ByteCount, 0xFFFF );
370
	#else
371
		CalcCRC = MODBUS_CRC(DataAddress, ByteCount);
372
	#endif
373
374
   #if MODBUS_DEBUG_PRINT & 0x400
375
   	reg = DataAddress[2];
376
      reg = (reg<<8) + (int)DataAddress[3];
377
		p1 = DataAddress[4];
378
      p1 = (p1<<8) + (int)DataAddress[5];
379
		printf ( "Ser Rx: Addr=%d Function=%2.2X Reg=%4d P1=%4d\n\r",
380
      	DataAddress[0], DataAddress[1], reg, p1 );
381
	#endif
382
383
		RxCRC = DataAddress[ByteCount+1] & 0x00FF; // LSByte
384
   	i = DataAddress[ByteCount]<<8;	// MSByte
385
   	RxCRC = RxCRC | ( i & 0xFF00 );	// MSbyte
386
387
	#if MODBUS_DEBUG_PRINT & 0x800
388
   	printf ( "  Calc CRC=%04X   Rcvd CRC=%04X\n\r", CalcCRC, RxCRC );
389
	#endif
390
391
	   if ( CalcCRC != RxCRC ) ByteCount = MB_CRC_ERROR;
392
   }
393
   return ByteCount;
394
} // MODBUS_Serial_Rx
395
396
// Modbus Send ADU *************************************************************
397
int MBM_Send_ADU ( char * ADUaddress, int ByteCount )
398
{
399
	auto unsigned CRCvalue;
400
   Ms start;
401
   int result;
402
   int i;
403
	   // Send the packet, wait for the response and remove "extra" stuff
404
	   result = MODBUS_Serial_Tx(ADUaddress, ByteCount);
405
	   if (result == MB_SUCCESS)
406
	   {
407
	      start = MS_TIMER;
408
	      while (MS_TIMER - start < 10);
409
	      result = MODBUS_Serial_Rx(ADUaddress, NODE_REG_LEN);
410
	      if (result == 0)
411
	         result = 1;
412
	      else if (result > 2 && result != MB_CRC_ERROR)
413
	         result = MB_SUCCESS;
414
	   }
415
	   return result;
416
} // MBM_Send_Packet
417
418
419
// Get Reg Value ***************************************************************
420
int GetLDNReg(int chn, int idx) 
421
{
422
	return Channel[chn].LDN->RmbReg[idx];
423
}
424
425
// Set Reg value ***************************************************************
426
void SetLDNReg(int chn, int idx, int val) 
427
{
428
   if (idx >= WRITE_CONFIRM)
429
   {
430
   	Channel[chn].LDN->RmbReg[idx] = val;
431
   }
432
   else 
433
   {
434
   	Channel[chn].LDN->WmbReg[idx] = val;
435
   	Channel[chn].LDN->DataReady 	= 0;
436
   }
437
438
   
439
}
440
441
/*** BeginHeader */
442
#endif
443
/*** EndHeader */