I have two programs that talk with serial rs232
1. written in c# with the use pf SerialPort class
2. written in java with the use of librxtx - SerialPort class
both: BaudRate - 9600, Parity-None, StopBits - 1, DataBits - 8
they communicate with the same the device that send the same data all the time
in c# i get the following 6 bytes: 255,98,144,19,1,0
in java i get the following 6 bytes: -1,98,-112,19,1,0
the c# code is the right one.
here are the code for c#:
m_serialPort = new SerialPort("COM15", 9600, Parity.None, 8, StopBits.One);
m_serialPort.DataReceived += SPDataRecieved;
m_serialPort.Open();
public override void SPDataRecieved(object sender, SerialDataReceivedEventArgs e)
{
try
{
Thread.Sleep(80);
byte[] toBytes = new byte[6];
m_serialPort.Read(toBytes, 0, 6);
}
catch (Exception ex)
{
}
}
}
here are the code for java:
m_SerialPort = (SerialPort) commPort;
m_SerialPort.setSerialPortParams
(9600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);
InputStream in = m_SerialPort.getInputStream();
byte[] buffer = new byte[6];
int len = -1;
Thread.sleep(80);
len = in.read(buffer,0,6);
what i need to add to the java code that the result will be the same?
Note that byte[] in Java and C# differ for 2 main reasons:
Java byte type is signed, while the C# byte type is unsigned (if you need signed use sbyte type)
Java stores byte as Big Endian, while C# uses Little Endian by default
Since java doesn't include unsigned byte in the language, you can print a conversion to int in the following way:
byte b = 0x3a; // random value
return b & 0xFF;
The java bytes are signed, while the C# bytes are not.
Convert each java value with the following:
newValue = (value + 256) % 256
// (-1 + 256) % 256 = 255
// (98 + 256) % 256 = 98 etc
Related
I have been working on a networking project recently to revive a dead mmo game for personal learning, I have a python implementation which works to decode the game data using blowfish(pypi / pycryptodome) and would like to transfer this 'server' into a java project.
Initially using blowfish decryption in java (BouncyCastle and Cipher -- default) I was getting entirely different results between java and python. Through some research I found that java (along with most things) actually use blowfish-compat big endian.
This one python library seems to be the only one which correctly decodes the data. Next I decided to use a python asyncio server as a middle relay simply for encryption and decryption. The network flow now looks like this:
GameClient -> Java SocketServer -> Python server (decryption) -> Java SocketServer.
The original Python implementation results in these bytes in hex format:
32004a815f49367cc3691be26d7b668132506dc972d5a6bbad38299640c6e222c6e55096f50ff33711250675431633ca9ede
The Java implementation produces these results in hex format(using apache commons Hex.encodeHexString())
32004a815f49367cc3691be26d7b668132506dc972d5a6bbad38299640c6e222c6e5c65830d65f9b4d60eb26730685f486d7
Both of these hex representations are pre-blowfish decryption in Python they are just the raw bytes being sent from the game client.
My question is why do these bytes start off the same and then it seems java trails off? The python results are the correct results they are tested and work. I have tried wrapping the bytes in java in a buffer and then calling flip() however this did not produce the correct results either. Using another stackoverflow post (I do not have link I am sorry) I tried casting this byte[] into a BigInteger and that also did not produce the correct results.
Any help is greatly appreciated.
Python Implementation
#!/usr/bin/env python3
import asyncio
import binascii
import blowfish
import ipaddress
import os
import struct
import sys
AUTH_BLOWFISHKEY = b"[;'.]94-31==-%&#!^+]\000"
bf = blowfish.Cipher(AUTH_BLOWFISHKEY, byte_order="little")
class EncryptionRelay(asyncio.Protocol):
def connection_made(self, transport):
self.transport = transport
self.client = (transport.get_extra_info('peername')[0] + ":" # IP
+ str(transport.get_extra_info('peername')[1])) # port
print("Connection from: " + self.client)
def connection_lost(self, exc):
print("Connection closed: " + self.client)
def data_received(self, data):
print(data.hex()) #python output above
pt = b''.join(bf.decrypt_ecb(data[2:]))
self.transport.write(pt)
def closeSocket(self, reason):
print(reason)
self.transport.close()
def main():
loop = asyncio.get_event_loop()
coroutine = loop.create_server(EncryptionRelay, host=None, port=54556)
server = loop.run_until_complete(coroutine)
for socket in server.sockets:
print("Listening on: " + socket.getsockname()[0] + ":" +
str(socket.getsockname()[1]))
try:
loop.run_forever()
except KeyboardInterrupt:
pass
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()
if __name__ == "__main__":
main()
Java Implementation
public AuthServer(int port) {
serverGUI = new AuthServerGUI(port);
try {
serverSocket = new ServerSocket(port);
relay = new PythonEncryptionRelay(this);
new Thread(relay).start();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
while(true) {
try {
Socket socket = serverSocket.accept();
onConnection(socket); //sends an init packet to client -- irrelevant to question
byte[] incomingData = new byte[0];
byte[] temp = new byte[1024];
int k = -1;
while((k = socket.getInputStream().read(temp, 0, temp.length)) > -1) {
byte[] tbuff = new byte[incomingData.length + k];
System.arraycopy(incomingData, 0, tbuff, 0, incomingData.length);
System.arraycopy(temp, 0, tbuff, incomingData.length, k);
incomingData = tbuff;
receiveData(socket, incomingData);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void receiveData(Socket socket, byte[] data) {
int lenLo = (int) (data[0]);
int lenHi = (int) (data[1]);
int length = lenHi * 256 + lenLo;
if(lenHi < 0) {
System.out.println("Invalid Packet Length");
}
if(data.length != length) {
System.out.println("Incomplete Packet Received");
}
serverGUI.serverDebug("DATA RECEIVED");
serverGUI.serverDebug(Hex.encodeHexString(data)); //this is the java ouput above serverGUI is simply a jframe i built no data manipulation
serverGUI.serverDebug("DATA_RECEIVED DONE");
this.relay.sendData(data); //this function sends the data from socket server to the python asyncio server
}
public void receiveDataFromPythonRelay(Socket socket, byte[] data) {
serverGUI.debugPythonRelay("DATA RECEIVED");
serverGUI.debugPythonRelay(Hex.encodeHexString(data)); //this will be the output from the python script aka data decrypted.
//The data byte[] is created in the exact same way the incomingData array is built in the AuthServer run function
serverGUI.debugPythonRelay("DATA_RECEIVED DONE");
}
Additionally the way I am importing the data byte[] from sockets is programmed as such because the client does not send endl therefore readLine will not work from the streams.
A byte has 8 bits which means you can have maximum 0xff as value.
But Java uses signed byte which means msb is reserved for signed bit. This leaves you with only 7 bits for your value, so you can have maximum as 0x7f stored in byte type of variable. Any number greater than 0x07f will result in overflow.
Try using an int array. As int uses 4 bytes (32 bits) hence there will always be space for 8 bits.
use byte[] to read from the stream and then copy the contents in int[] , Use int intArr[i] = byteArr[i] & 0xFF; for ith value from byte[] to avoid negative numbers due to byte overflow
I did test mix two PCM audio file.
but don't get true audio file.
I used this example
So, my code:
private void mixSound() throws IOException {
byte[] music1 = null;
music1 = new byte[in1.available()];
music1 = convertStreamToByteArray(in1);
in1.close();
byte[] music2 = null;
music2 = new byte[in2.available()];
music2 = convertStreamToByteArray(in2);
in2.close();
byte[] output = new byte[music1.length];
for (int i = 0; i < output.length; i++) {
samplef1 = music1[i] / 128.0f;
samplef2 = music2[i] / 128.0f;
float mixed = samplef1 + samplef2;
// reduce the volume a bit:
mixed *= 0.8;
// hard clipping
if (mixed > 1.0f) mixed = 1.0f;
if (mixed < -1.0f) mixed = -1.0f;
byte outputSample = (byte) (mixed * 128.0f);
output[i] = outputSample;
} //for loop
save = openFileOutput(filename, Context.MODE_PRIVATE);
save.write(output);
save.flush();
save.close();
}
public byte[] convertStreamToByteArray(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buff = new byte[8000];
int i;
while ((i = is.read(buff, 0, buff.length)) > 0) {
baos.write(buff, 0, i);
}
return baos.toByteArray(); // be sure to close InputStream in calling function
}
2 audio files with bit rate 64000 & sampling rate 16000 GH & sterio
in1 = getResources().openRawResource(R.raw.a_2);
in2 = getResources().openRawResource(R.raw.a_diz_2);
Also try to convert
bytes array to short array -> then calculate-> then convert short to byte using converts methods
like bytes2Shorts(byte[] buf) and shorts2Bytes(short[] s).
But steel have a fail result.
Someone can say me Where is my wrong?
There are a number of issues here and I'll try to address some of them
First, using byte[] suggests that your PCM wave data format is AudioFormat.ENCODING_PCM_8BIT (or it should be this format if it already isn't). This format uses 8-bit (1 byte) unsigned, which means that the sound
samples are stored in the [0, 255] range (not in the [-127, +128] or [-128,+127] range).
This means that the negative values are in the [0, 127] range and the positive samples are in the [128,255] range.
When mixing values, it's best to prevent clipping right from the start so I'd use
byte mixed = (music1[i] + music2[i])/2; //this ensures that mixed remains within the `correct range` for your PCM format
You can also divide your samples by 128 (if you want to convert them to floating point values)
float samplef1 = (((float)music1[i]-127)/128 ; //converting samples to [-1, +1] range -- -1 corresponds a sample value of 0 and +1 to 255
float samplef2 = (((float)music2[i]-127)/128;
float mixed = (samplef1+samplef2)/2;
Note that you now have 2 options to play data(samples) generated in this way. Either, convert floats back to bytes or use the AudioFormat.ENCODING_PCM_FLOAT format.
audio files with bit rate 64000 & sampling rate 16000 GH & sterio
This can't be correct. Typical sampling rates are 4000Hz, 8000Hz, 11000Hz, 16000Hz, 22050Hz or 44100Hz. For bit depths, audio usually uses 8 bits, 16 bits or 32 bits.
For instance, CD quality audio uses 44100Hz, 16bit, stereo format.
I tried to implement native messaging protocol in java but it didn't work.
I tried it following way.
private String readMessage() {
int length = getInt(getLength());
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
byte[] b = new byte[4];
try {
int total;
for(int totalRead = 0 ; totalRead < length ; totalRead = totalRead + 4){
System.in.read(b); // make sure
bOut.write(b);
}
} catch (IOException e) {
e.printStackTrace();
}
String bRes = null;
try {
bRes = new String(bOut.toByteArray(), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return bRes;
}
To read size i have used following methods:
This construct the int from first four bytes
private int getInt(byte[] bytes)
{
return (bytes[3] << 24) & 0xff000000 |
(bytes[2] << 16) & 0x00ff0000 |
(bytes[1] << 8) & 0x0000ff00 |
(bytes[0] << 0) & 0x000000ff;
}
This reads first four bytes and returns byte array
private byte[] getLength()
{
int length = 0 ;
byte[] bytes = new byte[4];
try
{
System.in.read(bytes);
} catch (IOException e)
{
e.printStackTrace();
}
return bytes;
}
This gives "Error when communicating with the native messaging host" error. How can i implement this protocol correctly in java.
Can someone provide simple working example for java
My approach below gives a Java implementation that receives a message from a Chrome App and sends a message back. On my little-endian machine it works.
I haven't properly studied your effort but hopefully this will help with your 'simple working example' request.
The main points:
Communication is with the standard stream. As you know, read in the first 4 bytes separately to learn the length (here, in to lengthByte):
byte[] lengthByte = new byte[4];
int bytesRead = System.in.read(lengthByte,0,4);
//Read the message into byte[] c:
byte[] c = new byte[text_length];
int lengthAppMessage = System.in.read(c,0,text_length);
When writing back to the app, we write the message length in the 1st 4 bytes. For the message {"m":"hi"}, which is the message I send below, the message length is 10. (For {"m":"hello"} it's 13, etc.)
int returnedMessageLength = 10;
System.out.write((byte) (returnedMessageLength));
System.out.write((byte)0);
System.out.write((byte)0);
System.out.write((byte)0);
Where the last three lines are padding to sum to 4 bytes. You may need to put these three lines in to the stream before the message length.
When appending the message, the {"...":"..."} format is needed. We can send the message through in sections e.g.
System.out.append('{');
System.out.append('"');
System.out.append('m');
System.out.append('"');
System.out.append(':');
System.out.append('"');
System.out.append('h');
System.out.append('i');
System.out.append('"');
System.out.append('}');
The point is that breaking the message in to sections and sending each section separately circumnavigates the Java formatting problem (caused by the single outer quotes.)
Put all of the above code inside a never-ending 'while' loop to avoid exiting too soon. (To see this code running, I integrated it with the example from Google's native messaging page.)
This is not good code that I've used, but either by accident or design, it worked this way for me.
The below codes works well on my side.
//Convert length from Bytes to int
public static int getInt(byte[] bytes) {
return (bytes[3] << 24) & 0xff000000|
(bytes[2] << 16)& 0x00ff0000|
(bytes[1] << 8) & 0x0000ff00|
(bytes[0] << 0) & 0x000000ff;
}
// Read an input from Chrome Extension
static public String receiveMessage(){
byte[] b = new byte[4];
try{
System.in.read(b);
int size = getInt(b);
byte[] msg = new byte[size];
System.in.read(msg);
// make sure to get message as UTF-8 format
String msgStr = new String(msg, "UTF-8");
return msgStr;
}catch (IOException e){
e.printStackTrace();
return null;
}
}
You could use https://github.com/Cosium/web-native-messaging-host .
It is a java library allowing to turn any JVM application into a Web Native Messaging Host .
I'm developing an app based on Samsung Chord SDK. I need to send the video's current position in the sendDataToAll(), which accepts data in byte[][]. My problem is that when I try to send the current position (which is an int) type-casted into byte, I'm getting negative value (in byte) as returned. And when I try to convert the negative value in to int in the OnDataRecived(), it's still the same negative value. How do I solve this issue?
Sending code:
//for sending the message
int currPos = mVideoView.getCurrentPosition();
logView.append("Duration sent= " + currPos);
//Integer resume = -3;
Byte msgByte = new Byte("-3");
byte [] [] pay = new byte [1] [2];
pay[0] [0] = msgByte;
Byte msgByte2 = new Byte((byte) currPos);
logView.append("Duration sent= " + msgByte2);
pay[0] [1] = msgByte2;
mChordchannel.sendDataToAll("Integer", pay);
// im sending -3 so that im checking that the user pressed the resume .
Receiving code:
//on receiving
else if(intRec == -3) {
Byte pos = rec[0] [1];
int posn;
posn = pos.intValue();
logView.append("Duration received= " + posn);
mVideoView.seekTo(posn);
mVideoView.start();
}
I don't know anything about the Samsung Chord SDK, but you can't fit (most) ints in a byte. An int is 4 bytes wide.
To create a payload compatible with your current code, that sends all 4 bytes:
byte[][] payload = { {
-3,
(byte)(currPos >> 24),
(byte)(currPos >> 16),
(byte)(currPos >> 8),
(byte)(currPos >> 0),
} };
mChordchannel.sendDataToAll("Integer", payload);
To receive:
int position = new java.math.BigInteger(
Arrays.copyOfRange(rec[0], 1, 5)).intValue();
P.S. This is not pretty code! It is tolerable for basic ints, but if you later find you need to transmit more complicated data structures you will need a better way. Some ideas, in increasing order of sophistication:
Use data streams (wrap a DataOutputStream around a ByteArrayOutputStream; write values; when done writing, close the DataOutputStream and call toByteArray() on the ByteArrayOutputStream to get the payload).
Use serialization (wrap an ObjectOutputStream around a ByteArrayOutputStream; write values and/or objects; finish as above).
Use a JSON-encoder or XML-encoder. (E.g., encode the data as a String, then call getBytes("UTF-8") on the String and send that.)
I'm receiving SMS from GSM modem in PDU format; the TP-User-Data is "C8329BFD06DDDF72363904"
and what I get is: "�2����r69", while the sent sms is "Hello World!".
Here is my java code:
private String fromPDUText(String PDUSMSText) {
String endoding = PDUSMSText.substring(0, 2);
PDUSMSText = PDUSMSText.substring(18);
byte bs[] = new byte[PDUSMSText.length() / 2];
for(int i = 0; i < PDUSMSText.length(); i += 2) {
bs[i / 2] = (byte) Integer.parseInt(PDUSMSText.substring(i, i + 2), 16);
}
try {
String out = new String(bs, "ASCII");
} catch(UnsupportedEncodingException e) {
e.printStackTrace();
return "";
} finally {
return out;
}
}
The input is packed in 7-bits per character, which means that every 8 bytes encode 9 characters. Constructing a parser for this format can be a fun exercise or a frustrating experience, depending on how you take it. You are probably better off using a library, and a quick Google search reveals several code examples.
This is how 7Bit characters are packed:
Encoding-Decoding-7-bit-User-Data-for-SMS-PDU-PDU
Personally I find it easiest to attack this kind of problem by viewing it as having a pipe where you feed 8 bits in one end and retrieve 7 bits in the other. As long as there is at least 7 bits in the pipe you read from it. When there are less than 7 bits you need to add some more so you write 8 new bits to it. So what you need is:
A pipe that can hold at least 14 bits (but why be cheap? Go with a 32-bit int!).
A counter keeping track of how many bits are in the pipe at any given moment.
The algorithm in pseudo code is as follows:
pipe = 0;
bitCount = 0;
while(hasMoreData())
{
pipe |= readByte() << bitCount;
bitCount += 8;
while(bitCount >= 7)
{
writeByte(pipe & 0x7F);
pipe >>= 7;
bitCount -= 7;
}
}