Attachment 'MODBUS.v1.0.txt'

Download

   1 :Namespace MODBUS
   2 ⍝ Driver for serial Modbus communication in RTU Mode
   3 
   4 ⍝ The following command are supported
   5 ⍝ FORCE_COIL_ON    = Force ON a Single Coil
   6 ⍝ FORCE_COIL_OFF   = Force OFF a Single Coil
   7 ⍝ READ_REG_FLOAT   = Read One FLOAT Register
   8 ⍝ READ_BYTE        = Read Multiple Registers as Bytes
   9 ⍝ PRESET_REG_FLOAT = Write a Float Value to a Register
  10 ⍝ PRESET_REG_INT   = Write an Integer Value to a Register
  11 
  12 ⍝ See the comments of the individual methods for more information
  13 
  14 
  15     (⎕IO ⎕ML ⎕WX)←1 3 3   ⍝ System variables
  16 
  17     I2H2←{'0123456789ABCDEF'[⎕IO+16 16⊤⍵]}              ⍝ Convert one Integer (0-255) to 2 Bytes Hexadecimal
  18     I2H4←{,⍉'0123456789ABCDEF'[⎕IO+16 16⊤255 255⊤⍵]}    ⍝ Convert one Integer (0-65535) to 4 Bytes Hexadecimal
  19     H22B←{16⊥¨16|(-⎕IO)+(⊂'0123456789ABCDEF0123456789abcdef')⍳¨((⍴⍵)⍴2 1)⊂⍵}   ⍝ Convert a pair of HEX characters to Bytes (0-255)
  20 
  21 
  22     ∇ r←sendObj FORCE_COIL_ON(modbusAddr coilNumber)
  23       :Access Public
  24     ⍝ To Force ON a Single Coil
  25 
  26     ⍝ sendObj    = SerialPort or TCP object
  27     ⍝ modbusAddr = Address of MODBUS device
  28     ⍝ coilNumber = Coil Number
  29 
  30     ⍝ r[1] = 1 for Success, 0 for Failure
  31     ⍝ r[2] = Value if Success or Literal Error if failure
  32      
  33       r←I2H2 modbusAddr       ⍝ Address of MODBUS device
  34       r,←'05'                 ⍝ Force Single Coil Command (5 decimal)
  35       r,←I2H4 coilNumber-1    ⍝ Coil Number (coil #1 is 0 in the program)
  36       r,←'FF00'               ⍝ Coil ON hex command
  37       r,←CRC_H r              ⍝ Checksum Calculation
  38       r←H22B r                ⍝ To Bytes
  39       r←sendObj.SendReceive r ⍝ Communication
  40      
  41     ⍝ To Exit on Communication Error
  42       :If 0=1⊃r ⋄ r←0(2⊃r) ⋄ →0 ⋄ :Else ⋄ r←2⊃r ⋄ :End
  43      
  44     ⍝ To Check if Byte Count is Correct
  45       :If 7=⍴,r ⋄ r←0 'Byte Count Incorrect Error' ⋄ →0 ⋄ :End
  46      
  47     ⍝ To Check if the CRC of the Answer is Correct
  48       :If ~(CRC_D ¯2↓r)≡¯2↑r
  49           r←0 'CRC Error on Answer' ⋄ →0
  50       :End
  51      
  52     ⍝ To Check if the Meter Address is Present
  53       :If modbusAddr≠r[1] ⋄ r←0 'Modbus Address Not Present Error' ⋄ →0 ⋄ :End
  54      
  55     ⍝ To Check if Command Number is Present
  56       :If 131=r[2] ⋄ r←0 'Command Number Error' ⋄ →0 ⋄ :End
  57       :If 5≠r[2] ⋄ r←0 'Command Number Not Present' ⋄ →0 ⋄ :End
  58      
  59     ⍝ To Check if Coil ON is in the answer
  60       :If 255 0≢r[5 6] ⋄ r←0 'Error in answer' ⋄ →0 ⋄ :End
  61      
  62     ⍝ Success
  63       r←1
  64 
  65 
  66 
  67     ∇ r←sendObj FORCE_COIL_OFF(modbusAddr coilNumber)
  68       :Access Public
  69     ⍝ To Force OFF a Single Coil
  70 
  71     ⍝ sendObj    = SerialPort or TCP object
  72     ⍝ modbusAddr = Address of MODBUS device
  73     ⍝ coilNumber = Coil Number
  74 
  75     ⍝ r[1] = 1 for Success, 0 for Failure
  76     ⍝ r[2] = Value if Success or Literal Error if failure
  77      
  78       r←I2H2 modbusAddr       ⍝ Address of MODBUS device
  79       r,←'05'                 ⍝ Force Single Coil Command (5 decimal)
  80       r,←I2H4 coilNumber-1    ⍝ Coil Number (coil #1 is 0 in the program)
  81       r,←'0000'               ⍝ Coil OFF hex command
  82       r,←CRC_H r              ⍝ Checksum Calculation
  83       r←H22B r                ⍝ To Bytes
  84       r←sendObj.SendReceive r ⍝ Communication
  85      
  86     ⍝ To Exit on Communication Error
  87       :If 0=1⊃r ⋄ r←0(2⊃r) ⋄ →0 ⋄ :Else ⋄ r←2⊃r ⋄ :End
  88      
  89     ⍝ To Check if Byte Count is Correct
  90       :If 7=⍴,r ⋄ r←0 'Byte Count Incorrect Error' ⋄ →0 ⋄ :End
  91      
  92     ⍝ To Check if the CRC of the Answer is Correct
  93       :If ~(CRC_D ¯2↓r)≡¯2↑r
  94           r←0 'CRC Error on Answer' ⋄ →0
  95       :End
  96      
  97     ⍝ To Check if the Meter Address is Present
  98       :If modbusAddr≠r[1] ⋄ r←0 'Modbus Address Not Present Error' ⋄ →0 ⋄ :End
  99      
 100     ⍝ To Check if Command Number is Present
 101       :If 131=r[2] ⋄ r←0 'Command Number Error' ⋄ →0 ⋄ :End
 102       :If 5≠r[2] ⋄ r←0 'Command Number Not Present' ⋄ →0 ⋄ :End
 103      
 104     ⍝ To Check if Coil OFF is in the answer
 105       :If 0 0≢r[5 6] ⋄ r←0 'Error in answer' ⋄ →0 ⋄ :End
 106      
 107     ⍝ Success
 108       r←1
 109 
 110 
 111 
 112     ∇ r←sendObj READ_BYTE(modbusAddr regAddr regQty)
 113       :Access Public
 114     ⍝ Read Register(s) as Bytes
 115 
 116     ⍝ sendObj    = SerialPort or TCP object
 117     ⍝ modbusAddr = Address of MODBUS device
 118     ⍝ regAddr    = Starting register
 119     ⍝ regQty     = Number of registers to read (2 bytes per registers)
 120 
 121     ⍝ r[1] = 1 for Success, 0 for Failure
 122     ⍝ r[2] = Bytes in register(s) if Success or Literal Error if failure
 123      
 124       r←I2H2 modbusAddr       ⍝ Address of MODBUS device
 125       r,←'03'                 ⍝ Read Holding Register Command (3 decimal)
 126       r,←I2H4 regAddr-40001   ⍝ Starting Address (address 0 is 40001)
 127       r,←I2H4 regQty          ⍝ Number of Registers To Read
 128       r,←CRC_H r              ⍝ Checksum Calculation
 129       r←H22B r                ⍝ Hex To Bytes
 130       r←sendObj.SendReceive r ⍝ Communication
 131      
 132     ⍝ To Exit on Communication Error
 133       :If 0=1⊃r ⋄ r←0(2⊃r) ⋄ →0 ⋄ :Else ⋄ r←2⊃r ⋄ :End
 134      
 135      ⍝ To Check if Byte Count is Correct
 136       :If 3>⍴,r
 137       :OrIf r[3]≠¯5+⍴,r
 138           r←0 'Byte Count Incorrect Error' ⋄ →0
 139       :End
 140      
 141     ⍝ To Check if the CRC of the Answer is Correct
 142       :If ~(CRC_D ¯2↓r)≡¯2↑r
 143           r←0 'CRC Error on Answer' ⋄ →0
 144       :End
 145      
 146     ⍝ To Check if the Modbus Address is Present
 147       :If modbusAddr≠r[1] ⋄ r←0 'Modbus Address Not Present Error' ⋄ →0 ⋄ :End
 148      
 149     ⍝ To Check if Command Number is Present
 150       :If 131=r[2] ⋄ r←0 'Command Number Error' ⋄ →0 ⋄ :End
 151       :If 3≠r[2] ⋄ r←0 'Command Number Not Present' ⋄ →0 ⋄ :End
 152      
 153     ⍝ Success
 154       r←1(3↓¯2↓r)
 155 
 156 
 157 
 158     ∇ r←sendObj READ_REG_FLOAT(modbusAddr regAddr)
 159       :Access Public
 160     ⍝ Read One FLOAT Register of a MODBUS device
 161 
 162     ⍝ sendObj    = SerialPort or TCP object
 163     ⍝ modbusAddr = Address of MODBUS device
 164     ⍝ regAddr    = Address of Register
 165 
 166     ⍝ r[1] = 1 for Success, 0 for Failure
 167     ⍝ r[2] = Value if Success or Literal Error if failure
 168      
 169       r←I2H2 modbusAddr       ⍝ Address of MODBUS device
 170       r,←'03'                 ⍝ Read Holding Register Command (3 decimal)
 171       r,←I2H4 regAddr-40001   ⍝ Starting Address
 172       r,←'0002'               ⍝ 2 Registers To Read
 173       r,←CRC_H r              ⍝ Checksum Calculation
 174       r←H22B r                ⍝ To Bytes
 175       r←sendObj.SendReceive r ⍝ Communication
 176      
 177     ⍝ To Exit on Communication Error
 178       :If 0=1⊃r ⋄ →0 ⋄ :Else ⋄ r←2⊃r ⋄ :End
 179      
 180     ⍝ To Check if Byte Count is Correct
 181       :If 3>⍴,r
 182       :OrIf r[3]≠¯5+⍴,r
 183           r←0 'Byte Count Incorrect Error' ⋄ →0
 184       :End
 185      
 186     ⍝ To Check if the CRC of the Answer is Correct
 187       :If ~(CRC_D ¯2↓r)≡¯2↑r
 188           r←0 'CRC Error on Answer' ⋄ →0
 189       :End
 190      
 191     ⍝ To Check if the Address of MODBUS device is Present
 192       :If modbusAddr≠r[1] ⋄ r←0 'Serial Address of MODBUS device Not Present Error' ⋄ →0 ⋄ :End
 193      
 194     ⍝ To Check if Command Number is Present
 195       :If 131=r[2] ⋄ r←0 'Command Number Error' ⋄ →0 ⋄ :End
 196       :If 3≠r[2] ⋄ r←0 'Command Number Not Present' ⋄ →0 ⋄ :End
 197      
 198     ⍝ Success
 199       r←3↓¯2↓r
 200       r←1,(FLOAT_TO_DEC r[⍳4])
 201 
 202 
 203 
 204     ∇ r←sendObj PRESET_REG_FLOAT(modbusAddr regAddr value)
 205       :Access Public
 206     ⍝ Write a Float Value to a single Register
 207 
 208     ⍝ sendObj    = SerialPort or TCP object
 209     ⍝ modbusAddr = Address of MODBUS device
 210     ⍝ regAddr    = Address of Register
 211     ⍝ value      = Value
 212 
 213     ⍝ r[1] = 1 for Success, 0 for Failure
 214     ⍝ r[2] = Literal Error if Failure
 215      
 216       r←I2H2 modbusAddr       ⍝ Serial Address of MODBUS device
 217       r,←'10'                 ⍝ Preset Register Command (16 decimal)
 218       r,←I2H4 regAddr-40001   ⍝ Starting Address
 219       r,←'0002'               ⍝ 2 Registers To Write
 220       r,←'02'                 ⍝ Byte Count
 221       r,←DEC_TO_FLOAT value   ⍝ Decimal to Hex
 222       r,←CRC_H r              ⍝ Checksum Calculation
 223       r←H22B r                ⍝ Hex To Bytes
 224       r←sendObj.SendReceive r ⍝ Communication
 225      
 226     ⍝ To Exit on Communication Error
 227       :If 0=1⊃r ⋄ →0 ⋄ :Else ⋄ r←2⊃r ⋄ :End
 228      
 229     ⍝ To Check if the CRC of the Answer is Correct
 230       :If ~(CRC_D ¯2↓r)≡¯2↑r
 231           r←0 'CRC Error on Answer' ⋄ →0
 232       :End
 233      
 234     ⍝ To Check if the Address of MODBUS device is Present
 235       :If modbusAddr≠r[1] ⋄ r←0 'Serial Address of MODBUS device Not Present Error' ⋄ →0 ⋄ :End
 236      
 237     ⍝ To Check if Command Number is Present
 238       :If 131=r[2] ⋄ r←0 'Command Number Error' ⋄ →0 ⋄ :End
 239       :If 16≠r[2] ⋄ r←0 'Command Number Not Present' ⋄ →0 ⋄ :End
 240      
 241     ⍝ Success
 242       r←1
 243 
 244 
 245 
 246     ∇ r←sendObj PRESET_REG_INT(modbusAddr regAddr value)
 247       :Access Public
 248     ⍝ Write an Integer Value to a single Register
 249 
 250     ⍝ sendObj    = SerialPort or TCP object
 251     ⍝ modbusAddr = Address of MODBUS device
 252     ⍝ regAddr    = Address of Register
 253     ⍝ value      = Value (0 - 65535)
 254 
 255     ⍝ r[1] = 1 for Success, 0 for Failure
 256     ⍝ r[2] = Literal Error if Failure
 257      
 258       r←I2H2 modbusAddr       ⍝ Serial Address of MODBUS device
 259       r,←'10'                 ⍝ Preset Register Command
 260       r,←I2H4 regAddr-40001   ⍝ Starting Address
 261       r,←'0001'               ⍝ 1 Registers To Write
 262       r,←'02'                 ⍝ Byte Count
 263       r,←I2H4 value           ⍝ Integer to Hex
 264       r,←CRC_H r              ⍝ Checksum Calculation
 265       r←H22B r                ⍝ Hex To Bytes
 266       r←sendObj.SendReceive r ⍝ Communication
 267      
 268     ⍝ To Exit on Communication Error
 269       :If 0=1⊃r ⋄ →0 ⋄ :Else ⋄ r←2⊃r ⋄ :End
 270      
 271     ⍝ To Check if the CRC of the Answer is Correct
 272       :If ~(CRC_D ¯2↓r)≡¯2↑r
 273           r←0 'CRC Error on Answer' ⋄ →0
 274       :End
 275      
 276     ⍝ To Check if the Address of MODBUS device is Present
 277       :If modbusAddr≠r[1] ⋄ r←0 'Address of MODBUS device Not Present Error' ⋄ →0 ⋄ :End
 278      
 279     ⍝ To Check if Command Number is Present
 280       :If 131=r[2] ⋄ r←0 'Command Number Error' ⋄ →0 ⋄ :End
 281       :If 16≠r[2] ⋄ r←0 'Command Number Not Present' ⋄ →0 ⋄ :End
 282      
 283     ⍝ No error
 284       r←1
 285 
 286 
 287 
 288     ∇ r←CRC_D v;i;ii;lsb
 289     ⍝ Calculate the CRC of a Decimal String
 290       r←16⍴1
 291       :For i :In ⍳⍴v
 292           r[⎕IO+7+⍳8]←(¯8↑r)≠,⍉(8⍴2)⊤v[i] ⍝ XOR est ≠
 293      
 294           :For ii :In ⍳8
 295               lsb←¯1↑r ⋄ r←0,15↑r
 296               :If 1=lsb
 297                   r←r≠1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1
 298               :End
 299           :End
 300       :End
 301       r←⌽2⊥⍉2 8⍴r
 302 
 303 
 304 
 305     ∇ r←CRC_H v;hex;i;ii;lsb
 306     ⍝ Calculate the CRC of a Hexadecimal String
 307       hex←'0123456789ABCDEF' ⋄ v←(-⎕IO)+hex⍳,v~' ' ⋄ r←16⍴1
 308       :For i :In ¯1+2×⍳0.5×⍴v
 309           r[⎕IO+7+⍳8]←(¯8↑r)≠,⍉2 2 2 2⊤v[i,i+1] ⍝ XOR est ≠
 310      
 311           :For ii :In ⍳8
 312               lsb←¯1↑r ⋄ r←0,15↑r
 313               :If 1=lsb
 314                   r←r≠1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1
 315               :End
 316           :End
 317       :End
 318       r←2⌽hex[⎕IO+2⊥⍉4 4⍴r]
 319 
 320 
 321 
 322     ∇ r←FLOAT_TO_DEC v;exponent;sign;significand
 323     ⍝ Convert a Float Quadlet (32 bits) to Decimal Number
 324       v←,(⍉(8⍴2)⊤v)[3 4 1 2;]
 325       sign←,1↑[1]⍉v
 326       exponent←2⊥8↑[1]1↓[1]⍉v
 327       significand←2⊥¯23↑[1]⍉v
 328       r←(¯1*sign)×(1+significand÷2*23)×2*(exponent-127)
 329       r←(0≠+/[1]⍉v)×r
 330 
 331 
 332 
 333     ∇ r←DEC_TO_FLOAT v;exponent;sign;significand
 334     ⍝ Convert a Decimal Number to a Float Quadlet
 335     ⍝ THE 2*¯127 IS TO TAKE CARE OF ZERO (ERROR IF ⍟0)
 336       sign←¯1=×v
 337       exponent←⍉(8⍴2)⊤127+⌊2⍟|v⍝+2*¯127
 338       significand←⍉(23⍴2)⊤⌊(2*23)ׯ1+2*1|2⍟|v⍝+2*¯127
 339       r←sign,exponent,significand
 340       r←4⌽'0123456789ABCDEF'[⎕IO+2⊥⍉8 4⍴r]
 341 
 342 
 343 :EndNamespace

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2016-01-11 00:39:59, 12.7 KB) [[attachment:MODBUS.v1.0.txt]]
 All files | Selected Files: delete move to page

You are not allowed to attach a file to this page.