Существует IoT-устройство, которое отправляет несколько байтов по MQTT / TCP, и я слушаю / подписан на тему под названием StartSession, Master_Topic и т. Д. *
Вот некоторые фактические данные ДО отправки через MQTT:
StartSession | B8-27-EB-42-2C-8B | 1521761472.417744 | 130.20.213.246 | версия 1
Master_Topic | B8-27-EB-42-2C-8B | +1521761474,2269528 | 0,0 | 0,0 | 0,0 | 0,0 | 0,0 | 27,8 | 27,7 | 0,0
Ниже приведен скрипт Python MQTT Paho. Python вызывает функции formatOutputMsg_SIGNAL_A () , formatOutputMsg_Array () и formatOutputMsg () для форматирования данных перед публикацией через MQTT, см. Соответствующий фрагмент (я не могу дать все сценарий, потому что это не мое, а остальное не имеет значения):
Это просто справочная информация, я не могу изменить реализацию Python, это не мой код и не в моем контроле.
Данные StartSession передаются в виде простого текста formatOutputMsg () .
Master_Topic преобразуется в байты перед отправкой с использованием formatOutputMsg_Array () .
Python на IoT:
//relevant section that formats data before publishing over MQTT
# logging.debug("publishing %s %s %s %s", topic, mac, ftime, value)
if drop == False:
if topic == topics.Master_SIGNAL.name:
# convert string array to float array
arr = np.array(list(map(float, value)))
client.publish(topics.Master_Topic.name, self.formatOutputMsg_Array(mac, arr))
elif topic == topics.Raw_SIGNAL.name:
ecgTime = float(value[0])
ecg = np.array(list(map(float, value[1:])))
client.publish(topics.Raw_SIGNAL.name, self.formatOutputMsg_SIGNAL_A(mac, [1, ecg]))
else:
client.publish(topic, self.formatOutputMsg(mac, value))
//formatting functions used by Master_SIGNAL
# for the master topic output
def formatOutputMsg_Array(self, mac, arr):
mac_bin = mac.encode("ascii");
mac_len = len(mac_bin);
arr_bin = array.array('d', arr).tobytes();
arr_len = len(arr_bin);
m = struct.pack('qqd%ss%ss' % (mac_len, arr_len), mac_len, arr_len, time.time(), mac_bin, arr_bin);
return m
# build output message for SIGNAL_A output.
def formatOutputMsg_SIGNAL_A(self, mac, arr):
mac_bin = mac.encode("ascii");
mac_len = len(mac_bin);
ecg_time = arr[0];
ecg_bin = array.array('d', arr[1]).tobytes();
ecg_len = len(ecg_bin);
m = struct.pack('qqdd%ss%ss' % (mac_len, ecg_len), mac_len, ecg_len, time.time(), ecg_time, mac_bin, ecg_bin);
return m
# build output message. Formatted like: "deviceid time value"
# example: 18:66:DA:43:87:4C,1507228882.122167,98.81615394017435
def formatOutputMsg(self, mac, value):
msg = mac + "|" + str(time.time()) + "|" + "|".join(value)
return msg
Проблема заключается в том, что байты идут в обратном порядке, когда я получаю их на клиенте Android, я не знаю, меняет ли его порядок Python, порядок MSB и LSB, или что-то еще ... в любом случае я написал подпрограмму в своем Android / Java-клиент для переворачивания большинства данных в правильном порядке, , однако я не могу правильно перевернуть / отформатировать поле MAC-АДРЕС.
Соответствующий код Java / Android на стороне клиента:
//vital tag related topics topic.contains("StartSession") || topic.contains("StopSession") || topic.contains("Alarm") || topic.contains("Raw_ECG")
else if (topic.contains("Master_Topic") || topic.equalsIgnoreCase("Master_Topic")) {
Log.i(TAG, "Master_Topic");
/*Master_Topic entire byte position:mac_len={0->8},arr_len={8->16),time={16->24},mac_bin={24->(24+mac_bin_len)},arr_bin={(24->(24+mac_bin_len)->(24->(24+mac_bin_len)+arr_len_value)}
* It seems the bytes are coming in reversed order. There we will use reverse() to reverse bytes. */
//First, 0->8,length=8,type=long,label=mac_len
byte[] payload = message.getPayload();
byte[] mac_len = new byte[8];
System.arraycopy(payload, 0, mac_len, 0, mac_len.length);
long mac_len_value = 0;
//reverse the byte order
reverse(mac_len);
//get the mac_len value
mac_len_value = ByteBuffer.wrap(mac_len).getLong();
//Second,8->16,length=8,type=long,label=arr_len
byte[] arr_len = new byte[8];
System.arraycopy(payload, 8, arr_len, 0, arr_len.length);
//reverse in place
reverse(arr_len);
long arr_len_value = 0;
arr_len_value = ByteBuffer.wrap(arr_len).getLong();
//Third,16-24,length=8,type=double,label=time
byte[] timeBytes = new byte[8];
System.arraycopy(payload, 16, timeBytes, 0, timeBytes.length);
reverse(timeBytes);
double time = ByteBuffer.wrap(timeBytes).getDouble();
/*Fourth,24->(24+mac_bin.length),type=char,label=mac_bin.
* The mac_len_value is of type long, we cannot initialize an array on long length in Java, therefore lets create a List*/
List < Byte > mac_bin_list = new ArrayList < Byte > ();
int i = 0;
while (i < mac_len_value) {
mac_bin_list.add((byte) 0);
i++;
}
//List to array
Byte[] Mac_Bin = mac_bin_list.toArray(new Byte[mac_bin_list.size()]);
byte[] mac_bin = Util.toPrimitives(Mac_Bin);
System.arraycopy(payload, 24, mac_bin, 0, mac_bin.length);
//ATTENTION - MAC ADDRESS CANNOT BE REVERSED CORRECTLY
reverse(mac_bin);
String mac_address = new String(mac_bin, "US-ASCII");
//mac_address = Arrays.toString(octets);
/*Five,(24+mac_bin.length)->(24+mac_bin.length)+(arr_bin.length),type=char,label=arr_bin.
* The arr_len_value is of type long, we cannot initialize an array on long length in Java, therefore lets create a List*/
List < Byte > arr_bin_list = new ArrayList < Byte > ();
int c = 0;
while (c < arr_len_value) {
arr_bin_list.add((byte) 0);
c++;
}
Byte[] Arr_Bin = arr_bin_list.toArray(new Byte[arr_bin_list.size()]);
byte[] arr_bin = Util.toPrimitives(Arr_Bin);
//Five,24+(mac_bin.length)+(arr_bin.length)->,type=char,label=mac_bin
System.arraycopy(payload, 24 + (mac_bin.length), arr_bin, 0, arr_bin.length);
reverse(arr_bin);
double[] values = toDoubleA(arr_bin);
/*The bytes section was reversed to give the right order of arrival, but this caused the actual decimal places to be reversed.
Therefore instead of 2.72 we see 27.2, therefore if the values is not 0.0 then reverse left & right side of decimal.*/
// reverse left & right side of decimal
int d = 0;
String valueOfData = null;
for (double data: values) {
//if the data is not 0, then we need to reverse the order to get the right value
if (data != 0.0) {
valueOfData = String.valueOf(data);
StringBuilder sb = new StringBuilder(valueOfData);
valueOfData = sb.reverse().toString();
values[d] = Double.valueOf(valueOfData).doubleValue();
}
d++;
}
StringBuilder datas = new StringBuilder();
for (double data: values) {
datas.append(data + "|");
}
datas = datas.reverse();
Log.i(TAG, "*Master_Topic,mac_len_value=" + mac_len_value + ",arr_len_value=" + arr_len_value + ",time=" + time + ",mac_address=" + mac_address + ",datas=" + datas);
}
else
{
String msg = new String(message.getPayload(),StandardCharsets.UTF_8);
Log.e(TAG, "Error topic: " +topic+",not supported!");
}
}
public byte[] toByteArray(int value) {
return new byte[] {
(byte)(value >> 24),
(byte)(value >> 16),
(byte)(value >> 8),
(byte)value};
}
int reverseBits(int n)
{
int rev = 0;
// traversing bits of 'n'
// from the right
while (n > 0)
{
// bitwise left shift
// 'rev' by 1
rev <<= 1;
// if current bit is '1'
if ((int)(n & 1) == 1)
rev ^= 1;
// bitwise right shift
//'n' by 1
n >>= 1;
}
// required number
return rev;
}
//from https://www.daniweb.com/programming/software-development/code/216874/primitive-types-as-byte-arrays
public long toLong(byte[] data) {
if (data == null || data.length != 8) return 0x0;
// ----------
return (long)(
// (Below) convert to longs before shift because digits
// are lost with ints beyond the 32-bit limit
(long)(0xff & data[0]) << 56 |
(long)(0xff & data[1]) << 48 |
(long)(0xff & data[2]) << 40 |
(long)(0xff & data[3]) << 32 |
(long)(0xff & data[4]) << 24 |
(long)(0xff & data[5]) << 16 |
(long)(0xff & data[6]) << 8 |
(long)(0xff & data[7]) << 0
);
}
//from https://www.daniweb.com/programming/software-development/code/216874/primitive-types-as-byte-arrays
public double toDouble(byte[] data) {
if (data == null || data.length != 8) return 0x0;
// ---------- simple:
return Double.longBitsToDouble(toLong(data));
}
//from https://www.daniweb.com/programming/software-development/code/216874/primitive-types-as-byte-arrays
public double[] toDoubleA(byte[] data) {
if (data == null) return null;
// ----------
if (data.length % 8 != 0) return null;
double[] dbls = new double[data.length / 8];
for (int i = 0; i < dbls.length; i++) {
dbls[i] = toDouble( new byte[] {
data[(i*8)],
data[(i*8)+1],
data[(i*8)+2],
data[(i*8)+3],
data[(i*8)+4],
data[(i*8)+5],
data[(i*8)+6],
data[(i*8)+7],
} );
}
return dbls;
}
//reverse the byte array
public void reverse(byte[] array) {
if (array == null) {
return;
}
int i = 0;
int j = array.length - 1;
byte tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
}
Вот мои журналы Android, когда поступают данные MQTT:
тема: StartSession, полезная нагрузка: 30: 9C: 23: 0F: 55: 34 | 1536460344.7305844 | 130.20.213.246 | версия 1
Master_Topic
* Master_Topic, mac_len_value = 17, arr_len_value = 64, время = 1.536460346541999E9, mac_address = * 1 055 * 43: 55: F0: 32: С9: 03 , = Данные | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 27.8 | 27,7 | 0,0
Кажется, что даже в StartSession, когда отправляется простой текст, MAC-АДРЕС изменяется с (правильный) B8-27-EB-42-2C-8B на (неправильный) 30 : 9C: 23: 0F: 55: 34
.
Для MasterTopic я пытался изменить порядок следования байтов, потому что изменение байтов помогло в восстановлении других полей, см. Мой reverse () в коде Java. Однако, я получил (неверный) 43: 55: F0: 32 : C9: 03 вместо правильного (правильного) B8-27-EB-42-2C-8B
Актуальный вопрос) Что происходит с данными MAC-АДРЕСА И как я могу правильно их восстановить ???
Спасибо
Миллион !!!