i am new to java serial port programming,
I have trying to read data from the modbus slave device through modbus RTU over serial port from my java application.
I am using the Jamod java library to read modbus protocal.
In my case my application failed to receive entire modbus response from the device. please find my java coding and error log for your reference.
Any one can suggest me what may be the reason for the error.
<br/>
**ERROR**<br/>
Clear input: 02 c2 c1<br/>
Sent: 01 04 03 e8 00 05 b0 79 <br/>
Last request: 01 04 03 e8 00 05 b0 79<br/>
CRC Error in received frame: 0 bytes: <br/>
Response: 01 84 <br/>
net.wimpi.modbus.ModbusIOException: I/O exception - failed to read<br/>
at net.wimpi.modbus.io.ModbusRTUTransport.readResponse(ModbusRTUTransport.java:163)<br/>
at net.wimpi.modbus.io.ModbusSerialTransaction.execute(ModbusSerialTransaction.java:187)<br/>
at modbusnewapplication.ModbusConnection.main(ModbusConnection.java:8<br/>
Modbus Program <br/>
---------------<br/>
package modbusnewapplication;<br/>
import java.io.;<br/>
import javax.comm.;<br/>
import net.wimpi.modbus.ModbusCoupler;<br/>
import net.wimpi.modbus.io.ModbusSerialTransaction;<br/>
import net.wimpi.modbus.msg.ReadInputRegistersRequest;<br/>
import net.wimpi.modbus.msg.ReadInputRegistersResponse;<br/>
import net.wimpi.modbus.net.SerialConnection;<br/>
import net.wimpi.modbus.util.SerialParameters;<br/>
public class ModbusConnection {<br/>
public static void main(String[] args) {<br/>
// if (args.length < 4) {<br/>
// System.out.println("not enough args");<br/>
// System.exit(1);<br/>
// }else{<br/>
try {<br/>
System.out.println("Serial Port Connection");<br/><br/>
/* The important instances of the classes mentioned before */<br/>
SerialConnection con = null; //the connection<br/>
ModbusSerialTransaction trans = null; //the transaction<br/>
ReadInputRegistersRequest req = null; //the request<br/>
ReadInputRegistersResponse res = null; //the response<br/>
// **1 Variables for storing the parameters** <br/>
String portname= "COM1"; //the name of the serial port to be used<br/>
int unitid = 1; //the unit identifier we will be talking to<br/>
int ref = 1000; //the reference, where to start reading from<br/>
int count = 5; //the count of IR's to read<br/>
int repeat = 1; //a loop for repeating the transaction <br/>
boolean isopen = false;<br/><br/>
**// 2. Set master identifier**
// ModbusCoupler.createModbusCoupler(null);
// ModbusCoupler.getReference().setMaster(master); I added this in
// ModbusCoupler.getReference().setMaster(true);
// ModbusCoupler.getReference().setUnitID(1);
**// 3. Setup serial parameters**<br/>
SerialParameters params = new SerialParameters();<br/>
params.setPortName("COM1");<br/>
params.setBaudRate(9600);<br/>
params.setDatabits(8);<br/>
params.setParity("None");<br/>
params.setStopbits(1);<br/>
params.setEncoding("RTU");<br/>
params.setEcho(false);<br/>
System.setProperty("net.wimpi.modbus.debug", "true");<br/>
**// 4. Open the connection**<br/>
con = new SerialConnection(params);
System.out.println("Connection..." + con.toString());
con.open();
isopen = con.isOpen();<br/>
System.out.println("Serial port status..." + isopen);<br/>
**// 5. Prepare a request<br/>**
req = new ReadInputRegistersRequest(ref, count);<br/>
req.setUnitID(unitid);<br/>
req.setHeadless();<br/>
**// 6. Prepare a transaction<br/>**
trans = new ModbusSerialTransaction(con);<br/>
trans.setRequest(req);<br/>
**// 7. Execute the transaction repeat times<br/>**
int k = 0;<br/>
do { <br/>
trans.execute();<br/>
res = (ReadInputRegistersResponse) trans.getResponse();<br/>
for (int n = 0; n < res.getWordCount(); n++) {<br/>
System.out.println("Word " + n + "=" + res.getRegisterValue(n));<br/>
}<br/>
k++;<br/>
} while (k < repeat);<br/>
**// 8. Close the connection**<br/>
con.close();<br/>
} catch (Exception ex) {<br/>
ex.printStackTrace();<br/>
}<br/>
//}//else<br/>
}//main
}
You should add a method like Thread.sleep(500) between request and response method in jamod library. Maybe this kind of error is usually caused by the length of response data.
jamod library didn't consider the long size of response data. So, we need to request and wait until all data is received from the serial interface. Ff not, because all data is not received, CRC check will fail and cause an error.
Related
I have a csv file containing 24231 rows. I would like to apply LOOCV based on the project name instead of the observations of the whole dataset.
So if my dataset contains information for 15 projects, I would like to have the training set based on 14 projects and the test set based on the other project.
I was relying on weka's API, is there anything that automates this process?
For non-numeric attributes, Weka allows you to retrieve the unique values via Attribute.numValues() (how many are there) and Attribute.value(int) (the -th value).
package weka;
import weka.core.Attribute;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.converters.ConverterUtils;
public class LOOByValue {
/**
* 1st arg: ARFF file to load
* 2nd arg: 0-based index in ARFF to use for class
* 3rd arg: 0-based index in ARFF to use for LOO
*
* #param args the command-line arguments
* #throws Exception if loading/processing of data fails
*/
public static void main(String[] args) throws Exception {
// load data
Instances full = ConverterUtils.DataSource.read(args[0]);
full.setClassIndex(Integer.parseInt(args[1]));
int looCol = Integer.parseInt(args[2]);
Attribute looAtt = full.attribute(looCol);
if (looAtt.isNumeric())
throw new IllegalStateException("Attribute cannot be numeric!");
// iterate unique values to create train/test splits
for (int i = 0; i < looAtt.numValues(); i++) {
String value = looAtt.value(i);
System.out.println("\n" + (i+1) + "/" + full.attribute(looCol).numValues() + ": " + value);
Instances train = new Instances(full, full.numInstances());
Instances test = new Instances(full, full.numInstances());
for (int n = 0; n < full.numInstances(); n++) {
Instance inst = full.instance(n);
if (inst.stringValue(looCol).equals(value))
test.add((Instance) inst.copy());
else
train.add((Instance) inst.copy());
}
train.compactify();
test.compactify();
// TODO do something with the data
System.out.println("train size: " + train.numInstances());
System.out.println("test size: " + test.numInstances());
}
}
}
With Weka's anneal UCI dataset and the surface-quality for leave-one-out, you can generate something like this:
1/5: ?
train size: 654
test size: 244
2/5: D
train size: 843
test size: 55
3/5: E
train size: 588
test size: 310
4/5: F
train size: 838
test size: 60
5/5: G
train size: 669
test size: 229
I am trying to get MAC address of the device in a local network by using its IP address. To implement this in java I found a library name Pcap4j. I am using its class SendArpRequest to generate ARP request and receive a reply, but it always says "IP-Address was resolved to null".
Here is the java code:
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.pcap4j.core.BpfProgram.BpfCompileMode;
import org.pcap4j.core.NotOpenException;
import org.pcap4j.core.PacketListener;
import org.pcap4j.core.PcapHandle;
import org.pcap4j.core.PcapNativeException;
import org.pcap4j.core.PcapNetworkInterface;
import org.pcap4j.core.PcapNetworkInterface.PromiscuousMode;
import org.pcap4j.core.Pcaps;
import org.pcap4j.packet.ArpPacket;
import org.pcap4j.packet.EthernetPacket;
import org.pcap4j.packet.Packet;
import org.pcap4j.packet.namednumber.ArpHardwareType;
import org.pcap4j.packet.namednumber.ArpOperation;
import org.pcap4j.packet.namednumber.EtherType;
import org.pcap4j.util.ByteArrays;
import org.pcap4j.util.MacAddress;
import org.pcap4j.util.NifSelector;
#SuppressWarnings("javadoc")
public class SendArpRequest {
private static final String COUNT_KEY = SendArpRequest.class.getName() + ".count";
private static final int COUNT = Integer.getInteger(COUNT_KEY, 1);
private static final String READ_TIMEOUT_KEY = SendArpRequest.class.getName() + ".readTimeout";
private static final int READ_TIMEOUT = Integer.getInteger(READ_TIMEOUT_KEY, 10); // [ms]
private static final String SNAPLEN_KEY = SendArpRequest.class.getName() + ".snaplen";
private static final int SNAPLEN =Integer.getInteger(SNAPLEN_KEY, 65536); // [bytes]
private static final MacAddress SRC_MAC_ADDR =MacAddress.getByName("00:db:df:8b:b1:a9");
private static MacAddress resolvedAddr;
private SendArpRequest() {}
public static void main(String[] args) throws PcapNativeException, NotOpenException {
String strSrcIpAddress = "192.168.0.11"; // for InetAddress.getByName()
//String strDstIpAddress = args[0]; // for InetAddress.getByName()
String strDstIpAddress = "192.168.0.3"; // for InetAddress.getByName()
System.out.println(COUNT_KEY + ": " + COUNT);
System.out.println(READ_TIMEOUT_KEY + ": " + READ_TIMEOUT);
System.out.println(SNAPLEN_KEY + ": " + SNAPLEN);
System.out.println("\n");
PcapNetworkInterface nif;
try {
nif = new NifSelector().selectNetworkInterface();
} catch (IOException e){
e.printStackTrace();
return;
}
if (nif == null) {
return;
}
System.out.println(nif.getName() + "(" + nif.getDescription() + ")");
PcapHandle handle = nif.openLive(SNAPLEN, PromiscuousMode.PROMISCUOUS, READ_TIMEOUT);
PcapHandle sendHandle = nif.openLive(SNAPLEN, PromiscuousMode.PROMISCUOUS, READ_TIMEOUT);
ExecutorService pool = Executors.newSingleThreadExecutor();
try {
handle.setFilter(
"arp and src host "
+ strDstIpAddress
+ " and dst host "
+ strSrcIpAddress
+ " and ether dst "
+ Pcaps.toBpfString(SRC_MAC_ADDR),
BpfCompileMode.OPTIMIZE);
PacketListener listener =
new PacketListener() {
public void gotPacket(Packet packet) {
if (packet.contains(ArpPacket.class)) {
ArpPacket arp = packet.get(ArpPacket.class);
if (arp.getHeader().getOperation().equals(ArpOperation.REPLY)) {
SendArpRequest.resolvedAddr = arp.getHeader().getSrcHardwareAddr();
}
}
System.out.println(packet);
}
};
Task t = new Task(handle, listener);
pool.execute(t);
ArpPacket.Builder arpBuilder = new ArpPacket.Builder();
try {
arpBuilder
.hardwareType(ArpHardwareType.ETHERNET)
.protocolType(EtherType.IPV4)
.hardwareAddrLength((byte) MacAddress.SIZE_IN_BYTES)
.protocolAddrLength((byte) ByteArrays.INET4_ADDRESS_SIZE_IN_BYTES)
.operation(ArpOperation.REQUEST)
.srcHardwareAddr(SRC_MAC_ADDR)
.srcProtocolAddr(InetAddress.getByName(strSrcIpAddress))
.dstHardwareAddr(MacAddress.ETHER_BROADCAST_ADDRESS)
.dstProtocolAddr(InetAddress.getByName(strDstIpAddress));
} catch (UnknownHostException e) {
throw new IllegalArgumentException(e);
}
EthernetPacket.Builder etherBuilder = new EthernetPacket.Builder();
etherBuilder
.dstAddr(MacAddress.ETHER_BROADCAST_ADDRESS)
.srcAddr(SRC_MAC_ADDR)
.type(EtherType.ARP)
.payloadBuilder(arpBuilder)
.paddingAtBuild(true);
for (int i = 0; i < COUNT; i++) {
Packet p = etherBuilder.build();
System.out.println(p);
sendHandle.sendPacket(p);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
} finally {
if (handle != null && handle.isOpen()) {
handle.close();
}
if (sendHandle != null && sendHandle.isOpen()) {
sendHandle.close();
}
if (pool != null && !pool.isShutdown()) {
pool.shutdown();
}
System.out.println(strDstIpAddress + " was resolved to " + resolvedAddr);
}
}
private static class Task implements Runnable {
private PcapHandle handle;
private PacketListener listener;
public Task(PcapHandle handle, PacketListener listener) {
this.handle = handle;
this.listener = listener;
}
public void run() {
try {
handle.loop(COUNT, listener);
} catch (PcapNativeException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (NotOpenException e) {
e.printStackTrace();
}
}
}
}
And I got this output by using sourceIP = "192.168.0.11", sourceMAC = "00:db:df:8b:b1:a9" and destinationIP = "192.168.0.3".
com.arpscan.SendArpRequest.count: 1
com.arpscan.SendArpRequest.readTimeout: 10
com.arpscan.SendArpRequest.snaplen: 65536
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
6
6
7
2
2
0
0
0
0
0
NIF[0]: wlp1s0
: link layer address: 00:db:df:8b:b1:a9
: address: /192.168.0.11
: address: /fe80:0:0:0:c090:df9:7448:e0be
NIF[1]: any
: description: Pseudo-device that captures on all interfaces
NIF[2]: lo
: link layer address: 00:00:00:00:00:00
: address: /127.0.0.1
: address: /0:0:0:0:0:0:0:1
NIF[3]: virbr0
: link layer address: 52:54:00:72:e9:70
: address: /192.168.122.1
NIF[4]: enp0s31f6
: link layer address: 50:7b:9d:cc:71:d2
NIF[5]: bluetooth0
: description: Bluetooth adapter number 0
NIF[6]: nflog
: description: Linux netfilter log (NFLOG) interface
NIF[7]: nfqueue
: description: Linux netfilter queue (NFQUEUE) interface
NIF[8]: usbmon1
: description: USB bus number 1
NIF[9]: usbmon2
: description: USB bus number 2
Select a device number to capture packets, or enter 'q' to quit > 0
wlp1s0(null)
[Ethernet Header (14 bytes)]
Destination address: ff:ff:ff:ff:ff:ff
Source address: 00:db:df:8b:b1:a9
Type: 0x0806 (ARP)
[ARP Header (28 bytes)]
Hardware type: 1 (Ethernet (10Mb))
Protocol type: 0x0800 (IPv4)
Hardware address length: 6 [bytes]
Protocol address length: 4 [bytes]
Operation: 1 (REQUEST)
Source hardware address: 00:db:df:8b:b1:a9
Source protocol address: /192.168.0.11
Destination hardware address: ff:ff:ff:ff:ff:ff
Destination protocol address: /192.168.0.3
[Ethernet Pad (18 bytes)]
Hex stream: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[data (42 bytes)]
Hex stream: 00 db df 8b b1 a9 d0 04 01 62 61 38 08 06 00 01 08 00 06 04 00 02 d0 04 01 62 61 38 c0 a8 00 03 00 db df 8b b1 a9 c0 a8 00 0b
192.168.0.3 was resolved to null
Here I got null for destination MAC Address as you can see.
But when I run arp-scan command I got correct MAC address for the given IP Address. Here is screenshot of arp-scan result.
Please suggest me how I can implement it properly.
You need to add a packet factory moudle (e.g. pcap4j-packetfactory-static.jar) to your class path so that Pcap4J can dessect the ARP response.
And, probably you'd better add volatile to private static MacAddress resolvedAddr;.
Following the google ble app, I created two joysticks on the android app. Then, I am sending the joystick values from android phone to an arduino over ble using 1 write characteristics, the packets size is 4 bytes.
when I lift up my finger from the phone screen. The last packet will contain a stop signal, but on my arduino side, I can not receive the last packet 100% of the time.
I came across this post and found this source to build a queue to ensure data gets through.
After implementing the queue, I am able to use logcat to see that the queue is being used. However, I still couldn't receive the stop signal 100% of the time after implementing the queue.
I think it's because by the time calling on the writeCustomCharacteristic(packets, writecharacteristic_uuid) on the last packet, the write operation is still busy writing, therefore, it doesn't event send my last packet out.
following is my code:
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.d("onCharacteristicWrite", "reach onCharacteristicWrite +++++++++++++");
isWriting = false;
}
.
.
.
public void writeCustomCharacteristic(int value, String uuid_char) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
/*check if the service is available on the device*/
BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT));
if (mCustomService == null) {
Log.w(TAG, "Custom BLE Service not found");
return;
}
writeValue(value, uuid_char, mCustomService);
/*get the read characteristic from the service*/
// BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(UUID.fromString(uuid_char));
// mWriteCharacteristic.setValue(value, android.bluetooth.BluetoothGattCharacteristic.FORMAT_UINT16, 0);
// Log.d("CONNECT", "reached writeCustomCharacteristic");
// if (mBluetoothGatt.writeCharacteristic(mWriteCharacteristic) == false) {
// Log.w(TAG, "Failed to write characteristic");
// }
}
public void writeValue(int dataInt, String uuid_char, BluetoothGattService mCustomService) {
writeQueue.addFirst(dataInt);
//Log.d("WriteQueue", "--------------write queue size: " + Integer.toHexString(writeQueue.peekFirst()));
writeNextValueFromQueue(mCustomService, uuid_char);
}
public void writeNextValueFromQueue(BluetoothGattService mCustomService,String uuid_char) {
if(isWriting) {
// if( (writeQueue.peekFirst() & LEFT_MOTOR_STOP_BIT_MASK ) != (1 << JoyStickActivity.LEFT_MOTOR_STOP_SIGNAL_MASK)) {
// return;
// }
Log.d("isWritingFromQueue", "reach is writing equal to ture -----------> " + Integer.toHexString(writeQueue.peekFirst()));
for(int s : writeQueue) {
System.out.println(Integer.toHexString(s));
Log.d("isWritingFromQueue", Integer.toHexString(s));
}
return;
}
if(writeQueue.size() == 0) {
Log.d("writeNextValueFromQueue", "reach queue size is zero --------------------");
return;
}
isWriting = true;
value = writeQueue.pollFirst();
Log.d("writeNextValueFromQueue", "++++++++++++++++value: " + Integer.toHexString(value));
/*get the read characteristic from the service*/
BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(UUID.fromString(uuid_char));
mWriteCharacteristic.setValue(value,android.bluetooth.BluetoothGattCharacteristic.FORMAT_UINT32,0);
Log.d("CONNECT", "reached writeCustomCharacteristic");
if(mBluetoothGatt.writeCharacteristic(mWriteCharacteristic) == false){
Log.w(TAG, "Failed to write characteristic");
}
}
}
Update:
I added a while statement in my writeNextValueFromQueue() function, now it catches that when I receives the packet with the stop signal, I use the while loop to wait until the onCharacteristicWrite() is done, then send my last packet. This way I ensured that I send the last packet every time, however, it delays the time when the motor stops by a few hundred milliseconds.
Is there any way, where I can drop whatever packets that I am sending when I received my stop signal instead of waiting for the packets to be finished sending, then send the packet that includes my stop signal?
public void writeNextValueFromQueue(BluetoothGattService mCustomService,String uuid_char) {
if(isWriting) {
if( (writeQueue.peekFirst() & LEFT_MOTOR_STOP_BIT_MASK ) != (1 << JoyStickActivity.LEFT_MOTOR_STOP_SIGNAL_MASK)) {
return;
}
while(isWriting) {
}
Log.d("isWritingFromQueue", "reach is writing equal to ture -----------> " + Integer.toHexString(writeQueue.peekFirst()));
for(int s : writeQueue) {
System.out.println(Integer.toHexString(s));
Log.d("isWritingFromQueue", Integer.toHexString(s));
}
// return;
}
if(writeQueue.size() == 0) {
Log.d("writeNextValueFromQueue", "reach queue size is zero --------------------");
return;
}
isWriting = true;
value = writeQueue.pollFirst();
Log.d("writeNextValueFromQueue", "++++++++++++++++value: " + Integer.toHexString(value));
/*get the read characteristic from the service*/
BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(UUID.fromString(uuid_char));
mWriteCharacteristic.setValue(value,android.bluetooth.BluetoothGattCharacteristic.FORMAT_UINT32,0);
Log.d("CONNECT", "reached writeCustomCharacteristic");
if(mBluetoothGatt.writeCharacteristic(mWriteCharacteristic) == false){
Log.w(TAG, "Failed to write characteristic");
}
}
More Update:
Since adding the while statement cause a lag in my app, I am trying to figure out a different solution. Following Emil's suggestion and I started to print out stuff in onCharacteristicWrite() callback. show in the code below:
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
final StringBuilder stringBuilder;
// Log.d("onCharacteristicWrite", "reach onCharacteristicWrite +++++++++++++");
if(status == BluetoothGatt.GATT_SUCCESS){
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
stringBuilder = new StringBuilder(data.length);
for (byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
Log.d("onCharacteristicSuccess", "Value is " +stringBuilder.toString() );
}
}
isWriting = false;
}
Following is the log cat that successful sends the stop signal:
04-22 21:21:36.242 11242-11255/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:36.392 11242-11254/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:36.544 11242-11254/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:36.694 11242-11255/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:36.843 11242-11254/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:36.993 11242-11254/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:37.143 11242-11284/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:37.292 11242-11255/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:37.442 11242-11284/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:38.947 11242-11284/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 C0 00
As you can see, the very last packet contain C0, which is a stop signal. However, this signal does not get received most of the time.
I am trying to read mainframe file but all are working other than comp 3 file.Below program is giving strange values.It is not able to read the salary value which is double also it is giving 2020202020.20 values. I don't know what am missing.Please help me to find it.
Program:
public final class Readcopybook {
private String dataFile = "EMPFILE.txt";
private String copybookName = "EMPCOPYBOOK.txt";
public Readcopybook() {
super();
AbstractLine line;
try {
ICobolIOBuilder iob = JRecordInterface1.COBOL.newIOBuilder(copybookName)
.setFileOrganization(Constants.IO_BINARY_IBM_4680).setSplitCopybook(CopybookLoader.SPLIT_NONE);
AbstractLineReader reader = iob.newReader(dataFile);
while ((line = reader.read()) != null) {
System.out.println(line.getFieldValue("EMP-NO").asString() + " "
+ line.getFieldValue("EMP-NAME").asString() + " "
+ line.getFieldValue("EMP-ADDRESS").asString() + " "
+ line.getFieldValue("EMP-SALARY").asString() + " "
+ line.getFieldValue("EMP-ZIPCODE").asString());
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Readcopybook();
}
}
EMPCOPYBOOK:
001700 01 EMP-RECORD.
001900 10 EMP-NO PIC 9(10).
002000 10 EMP-NAME PIC X(30).
002100 10 EMP-ADDRESS PIC X(30).
002200 10 EMP-SALARY PIC S9(8)V9(2) COMP-3.
002200 10 EMP-ZIPCODE PIC 9(4).
EMPFILE:
0000001001suneel kumar r bangalore e¡5671
0000001002JOSEPH WHITE FIELD rrn4500
Output:
1001 suneel kumar r bangalore 20200165a10 5671
2020202020.20
2020202020.20
2020202020.20
2020202020.20
2020202020.20
2020202020.20
2020202020.20
2020202020.20
0.00
1002 JOSEPH WHITE FIELD 202072726e0 4500
One problem is you have done a Ebcdic to Ascii conversion on the file.
The 2020... is a dead give away x'20' is the ascii space character.
This Answer deals with problems with doing an Ebcdic to ascii conversion.
You need to do a Binary transfer from the Mainframe and read the file using Ebcdic. You will need to check the RECFM on the Mainframe. If the RECFM is
FB - problems just transfer
VB - either convert to FB on the mainframe of include the RDW (Record Descriptor Word) option in the transfer.
Other - Convert to FB/VB on the mainframe
Updated java Code
int fileOrg = Constants.IO_FIXED_LENGTH_RECORDS; // or Constants.IO_VB
ICobolIOBuilder iob = JRecordInterface1.COBOL
.newIOBuilder(copybookName)
.setFileOrganization(fileOrg)
.setFont("Cp037")
.setSplitCopybook(CopybookLoader.SPLIT_NONE);
Note: IO_BINARY_IBM_4680 is for IBM 4690 Registers
There is a wiki entry here
or this Question
How do you generate java~jrecord code fror a Cobol copybook
We have a number of Lanier MFPs that use the scan-to-folder option to allow people to get their documents, and we are starting to implement more security measures on the AD passwords they use by forcing a password reset.
Unfortunately, the Laniers use a proprietary encryption for the passwords. I've managed to get a functional Java command that will encrypt passwords into this format. The problem I've been encountering is that I then have to get this encoded password into PowerShell to pass it to the scanner.
I can run the Java command through a command line, but can't pass the encrypted password back into PowerShell as a string that the printer will accept (it needs to be in Base64). If I do pass the encoded password back into PowerShell, then run it through PowerShell's Base64 creation process, it is, obviously, changed too much for the scanner to use it.
What I need to determine is whether there's a way for me to take the following command line command, and get it to run in PowerShell, then provide me its output so I can pass this to the printer.
java -cp ./commons-codec-1.10.jar;. cdm.GwpwesCharacterEncoding %pass% "gwpwes002"
The Java command outputs a Base64 string based on the following line:
return new String(Base64.encodeBase64((byte[])encrypt));
As an example, if I pass the text 'Test' into that, I get the string "HVhcmtla25meHVncHQ=="
This is useless to me, though, as I can't then get this back into PowerShell to pass through to the printer, and if I encode it as Base64 with PowerShell, it comes out as "MgBoAHMAWgBtADkAegBjADIAQgBxAGUAMABKAHgAWgBYAGgAbgBiAG0AMAB3AD0A".
Can anyone help?
Revised code after some assistance:
$pass1 = "test"
$path = "c:\Test\printercreds"
$encode = "gwpwes002"
cd $path
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pInfo.FileName = 'java'
$pInfo.Arguments = "-jar .\commons-codec-1.10.jar cdm.GwpwesCharacterEncoding $pass1 $encode"
$pInfo.UseShellExecute = $false
$pInfo.RedirectStandardOutput = $true
$pInfo.RedirectStandardError = $true
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $pInfo
[void]$process.Start()
$passsec = $process.StandardOutput.ReadtoEnd()
$process.WaitforExit()
write-host $passsec
Please try this. Its the encoding for GWPWES002. I found a old java version here.
https://www.dropbox.com/s/3324g84x0l4bnon/GwpwesCharacterEncoding.java?dl=0
There is a weakness in this "encoding". The front part of the encoding is just random padding. the pack part is where the actual string is stored. Running the script on the same string just a few times points out this error.
encodeGwpwes002 -code "a"
generated this hashes
np6eWFieWJ6eWA==
np6eWJ5YWFieWA==
WFienlhYnlieWA==
nlhYnp5Ynp6eWA==
nlieWFieWJ6eWA==
everything up until eWA== is just random padding mean "eWA==" == "a"
same for "aaaaaaaa"
np5YWJ5YnlieWFhYWFhYWFg=
np5Ynp6eWJ6eWFhYWFhYWFg=
nlienp6eWJ6eWFhYWFhYWFg=
WJ5YWJ6enlieWFhYWFhYWFg=
Meaning that
"eWFhYWFhYWFg=" Is "aaaaaaaa".
the password you provided as "test", A example of manipulation would be :
HVhcmtla25meHVncHQ== IS "test" :: 29 88 92 154 217 90 219 153 158 29 89 220 29
HVhcmtla25meFVncHQ== IS "Test" :: 29 88 92 154 217 90 219 153 158 21 89 220 29
Here is the powershell I have translated below
#private static String encodeGwpwes002(String code, int codeSize) {
function encodeGwpwes002([string]$code, [int]$codeSize = 0){
#byte[] protectCode;
[byte]$protectCode | Out-Null
#try {
try{
#protectCode = code.getBytes("UTF-8");
$protectCode = [System.Text.Encoding]::UTF8.GetBytes($code)
#}catch (Throwable e) {
}catch{
#return null;
return $null
#}
}
#int encodeSize = codeSize;
[int]$encodeSize = $codeSize
#if (protectCode.length >= codeSize) {
if(($protectCode.length) -ge $codeSize){
#encodeSize = protectCode.length + 9;
$encodeSize = ($protectCode.length) + 9
#}
}
#byte[] simple = new byte[encodeSize];
[byte[]]$simple = New-Object byte[] $encodeSize
#int diffuseCnt = 0;
[int]$diffuseCnt = 0
#int simpleCnt = 0;
[int]$simpleCnt = 0
#if (protectCode.length < encodeSize - 1) {
if(($protectCode.length) -lt ($encodeSize - 1)){
#for (diffuseCnt = 0; diffuseCnt < encodeSize - 1 - protectCode.length; ++diffuseCnt) {
for($diffuseCnt = 0; $diffuseCnt -lt ($encodeSize - 1 - ($protectCode.length)); $diffuseCnt++){
#simple[diffuseCnt] = (byte)(Math.random() * 25.0 + 97.0);
$simple[$diffuseCnt] = [byte] (Get-Random -Maximum 0.9 -Minimum 0.1) * 25.0 + 97.0
#}
}
#}
}
#simple[diffuseCnt++] = 122;
$simple[$diffuseCnt++] = 122
#for (simpleCnt = diffuseCnt; simpleCnt < protectCode.length + diffuseCnt; ++simpleCnt) {
for($simpleCnt = $diffuseCnt; $simpleCnt -lt ($protectCode.length) + $diffuseCnt; $simpleCnt++){
#simple[simpleCnt] = protectCode[simpleCnt - diffuseCnt];
$simple[$simpleCnt] = $protectCode[$simpleCnt - $diffuseCnt];
#}
}
#byte[] encrypt = new byte[simpleCnt];
[byte[]] $encrypt = New-Object byte[] $simpleCnt
#for (int i = 0; i < simpleCnt; ++i) {
for([int]$i=0; $i -lt $simpleCnt; $i++) {
#byte work = 0;
[byte]$work = 0
#work = (byte)((simple[i] & 192) >>> 6 | (simple[i] & 63) << 2);
$work = [byte](($simple[$i] -band 192) -shr 6 -bor ($simple[$i] -band 63) -shl 2)
#encrypt[i] = (byte)((work & 240) >>> 4 | (work & 15) << 4);
$encrypt[$i] = [byte](($work -band 240) -shr 4 -bor ($work -band 15) -shl 4)
#}
}
#return new String(Base64.encodeBase64((byte[])encrypt));
return [string]([System.Convert]::ToBase64String([byte[]]$encrypt))
#}
}
encodeGwpwes002TEST -code "Test"