📦 Archived documentation: r1 (committed 2026-07-24) View current documentation →

EtherNet/IP Server (PLC Handler)

Answers EtherNet/IP requests from a PLC with eip.handle(): write requests unpack a status word into individual io flags using bit masks, and read requests build a binary reply with bin.alloc(), the "BIT" bit-packing format and "U16AB" registers.

eip.handle(function(req){ // handle incoming EtherNet/IP read and write requests

  if(req.data){ // Is this a write request with write data?

    print("EtherIP Write Request");
    print("EIP File", req.file);
    print("EIP Payload:", bin.toHex(req.data));

    req.data.seek(0);
    let status = req.data.read("U16AB");

    io.PALL = {
      _lu: now(),
      skidInletValveD: (status & (1<<11)) > 0,
      skidInletValveC: (status & (1<<10)) > 0,
      skidInletValveB: (status & (1<<9))  > 0,
      skidInletValveA: (status & (1<<8))  > 0,
      chnMasterAlarm:  (status & (1<<6))  > 0,
      masterAlarm:     (status & (1<<5))  > 0,
      skidDAlarm:      (status & (1<<4))  > 0,
      skidCAlarm:      (status & (1<<3))  > 0,
      skidBAlarm:      (status & (1<<2))  > 0,
      skidAAlarm:      (status & (1<<1))  > 0,
      feedEnable:       status & 1,

      flowAvailable: req.data.read("U16AB") / 0.2777778,
      skidAStatus:   req.data.read(), // read using the same previously defined structure
      skidBStatus:   req.data.read(),
      skidCStatus:   req.data.read(),
    };
    req.data.seek(100);
    io.PALL.inletTurbidity = req.data.read();

  } else {
    // Read request.

    print("EtherIP Read Request");
    print("EIP File", req.file);
    print("EIP Bytes:", req.bytes); // the byte length of the requested data

    let pallW = {
      highClearwellAlarm: alm.v("Clearwell") >= alm.warn,
      highPressAlarm: alm.fV("PALL Intake","Inlet Pressure High") > 0,
      filterOutputPermission: true,
      flowRequest: 151.1999 * pallProcess.pumpsRunningCount.limit(1,4) // m3/h
    };

    let buff = bin.alloc(100); // empty 100-byte buffer; the read/write cursor is positioned on it automatically
    buff.write("BIT", [0, io.p304.running, io.p303.running, io.p302.running, io.p301.running,
                       pallW.highClearwellAlarm, pallW.highPressAlarm, pallW.filterOutputPermission,
                       0,0,0,0,0,0,0,0]);            // write our statuses as bits
    buff.write("U16AB", [pallW.flowRequest * 0.2777778,
                         io.clearwellLevel701.inst * 10]); // flow request + clearwell level as U16s
    return buff; // return our binary data
  }
});