/*
* Copyright 2022 Pnoker All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
Part of Libnodave, a free communication libray for Siemens S7
(C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2005.
Libnodave is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Libnodave is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package io.github.pnoker.driver.api.impl.nodave;
import io.github.pnoker.driver.api.DaveArea;
/**
* @author Thomas Rudin
*/
public final class PDU {
/**
* known function codes
*/
public final static byte FUNC_READ = 4;
public final static byte FUNC_WRITE = 5;
public int data;
int dlen;
int error;
int header; // the position of the header;
int hlen;
byte[] mem;
public int param; // the position of the parameters;
public int plen;
public int udata;
public int udlen;
/**
* set up the PDU information
*/
public PDU(final byte[] mem, final int pos) {
this.mem = mem;
this.header = pos;
}
public int addBitVarToReadRequest(final int area, final int DBnum, final int start, final int len) {
final byte pa[] = {0x12, 0x0a, 0x10, 0x01, /* single bits */
0x00, 0x1A, /* insert length in bytes here */
0x00, 0x0B, /* insert DB number here */
(byte) 0x84, /* change this to real area code */
0x00, 0x00, (byte) 0xC0 /* insert start address in bits */
};
Nodave.setUSBEWord(pa, 4, len);
Nodave.setUSBEWord(pa, 6, DBnum);
Nodave.setUSBELong(pa, 8, start);
Nodave.setUSByte(pa, 8, area);
this.mem[this.param + 1]++;
System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
this.plen += pa.length;
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
return 0;
}
public void addBitVarToWriteRequest(final DaveArea area, final int DBnum, final int start, final int byteCount,
final byte[] buffer) {
final byte da[] = {0, 3, 0, 0,};
final byte pa[] = {0x12, 0x0a, 0x10, 0x01, /* single bit */
0, 0, /* insert length in bytes here */
0, 0, /* insert DB number here */
0, /* change this to real area code */
0, 0, 0 /* insert start address in bits */
};
if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
|| (area == DaveArea.COUNTER200)) {
pa[3] = (byte) area.getCode();
pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
} else if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
pa[3] = 4;
pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
} else {
pa[4] = (byte) (byteCount / 0x100);
pa[5] = (byte) (byteCount & 0xff);
}
pa[6] = (byte) (DBnum / 256);
pa[7] = (byte) (DBnum & 0xff);
pa[8] = (byte) area.getCode();
pa[11] = (byte) (start & 0xff);
pa[10] = (byte) ((start / 0x100) & 0xff);
pa[9] = (byte) (start / 0x10000);
if ((this.dlen % 2) != 0) {
this.addData(da, 1);
}
this.mem[this.param + 1]++;
if (this.dlen > 0) {
final byte[] saveData = new byte[this.dlen];
System.arraycopy(this.mem, this.data, saveData, 0, this.dlen);
System.arraycopy(saveData, 0, this.mem, this.data + pa.length, this.dlen);
}
System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
this.plen += pa.length;
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
this.data = this.param + this.plen;
this.addData(da);
this.addValue(buffer);
}
/**
* Add data after parameters, set dlen as needed. Needs valid header and
* parameters
*/
void addData(final byte[] newData) {
final int appPos = this.data + this.dlen; // append to this position
this.dlen += newData.length;
System.arraycopy(newData, 0, this.mem, appPos, newData.length);
Nodave.setUSBEWord(this.mem, this.header + 8, this.dlen);
}
/**
* Add len bytes of len after parameters from a maybe longer block of bytes.
* Set dlen as needed. Needs valid header and parameters
*/
public void addData(final byte[] newData, final int len) {
final int appPos = this.data + this.dlen; // append to this position
this.dlen += len;
System.arraycopy(newData, 0, this.mem, appPos, len);
Nodave.setUSBEWord(this.mem, this.header + 8, this.dlen);
}
public void addParam(final byte[] pa) {
this.plen = pa.length;
System.arraycopy(pa, 0, this.mem, this.param, this.plen);
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
// mem[header + 6] = (byte) (pa.length / 256);
// mem[header + 7] = (byte) (pa.length % 256);
this.data = this.param + this.plen;
this.dlen = 0;
}
/*
* add data in user data. Add a user data header, if not yet present.
*/
public void addUserData(final byte[] da) {
final byte udh[] = {(byte) 0xff, 9, 0, 0};
if (this.dlen == 0) {
this.addData(udh);
}
this.addValue(da);
}
/**
* Add values after value header in data, adjust dlen and data count. Needs
* valid header,parameters,data,dlen
*/
void addValue(final byte[] values) {
int valCount = (0x100 * this.mem[this.data + 2]) + this.mem[this.data + 3];
if (this.mem[this.data + 1] == 4) { // bit data, length is in bits
valCount += 8 * values.length;
} else if (this.mem[this.data + 1] == 9) { // byte data, length is in
// bytes
valCount += values.length;
} else {
// XXX
}
if (this.udata == 0) {
this.udata = this.data + 4;
}
this.udlen += values.length;
Nodave.setUSBEWord(this.mem, this.data + 2, valCount);
this.addData(values);
}
public int addVarToReadRequest(final DaveArea area, final int DBnum, int start, final int len) {
final byte[] pa = {0x12, 0x0a, 0x10,
0x02, /* 1=single bit, 2=byte, 4=word */
0x00, 0x1A, /* length in bytes */
0x00, 0x0B, /* DB number */
(byte) 0x84, // * area code */
0x00, 0x00, (byte) 0xC0 /* start address in bits */
};
if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
pa[3] = 4;
start *= 8; /* bits */
} else if ((area == DaveArea