C语言 Arduino和LoRa,未接收到所有字节

bjg7j2ky  于 2022-12-03  发布在  其他
关注(0)|答案(1)|浏览(172)

我正在与Arduino和Lora合作。Arduino A有一个相机,收音机和SD卡。Arduino B有相同的设置,除了相机。
目标是从A向B发送一张图片。下面的代码应该从SD卡A读取32个字节(多亏了mmixLinus,它做得很好),并通过LoRa发送到Arduino B,后者将这32个字节保存到自己的SD卡中。文件将一次发送32个字节,直到所有的53 k到达。
经过一些故障排除,并认为我正在丢失数据包,我决定计数发送的数量与接收的数量。他们匹配。
我还把每个数据包的字节数发送到控制台。它们匹配。
但是,保存在接收SD卡中的结果文件比发送SD卡上的原始文件小。它无法使用。
我注意到,除了最后一个数据包可以更小之外,我希望每个数据包都是32字节。但是,即使发送和接收的字节匹配,我也不确定为什么我的代码在读取每个文件时不使用完整的32字节。
这些是我的主要问题。
1.你能帮我找出我做错了什么吗?
1.什么是一种 * 理想 * 的简单方法来实现错误检查,确保每个发送的数据包在接收时都经过检查和验证,并让发送方知道它可以发送下一个数据包?
这是发件人的代码。

oFile = SD.open("ring.jpg", FILE_READ); //open source file for read.
long cByteTotal = oFile.size(); //get total bytes
Serial.print("Original size: ");
Serial.println(cByteTotal);
while (cByteTotal > 0) {
  int length = cByteTotal < 32 ? cByteTotal : 32;
  if (length < 32) {
    Serial.println("Sending last packet."); //info
  }
  oFile.read(cArray, length); //read 32 bytes from file
  cArray[length] = '\0'; // terminate the char array
  sendMessage(String(cArray)); //send the file via Lora after casting to string
  delay(250); // just in case to give time to receiver to process
  cByteTotal -= length;
}
oFile.close();
Serial.println("Done Sending.");

void sendMessage(String cArray) {
  LoRa.beginPacket();
  LoRa.write(cArray.length());
  LoRa.write(cArray);
  LoRa.endPacket();
}

这是接收器的代码。

void loop() {
  onReceive(LoRa.parsePacket());
}

void onReceive(int packetSize) {
  if (packetSize == 0) {
    return;
  }
  packageTotal++;
  byte incomingLength = LoRa.read();
  String incoming = "";
  while (LoRa.available()) {
    incoming += (char)LoRa.read();
  }
  if (incomingLength != incoming.length()) {
    // check length for error
    Serial.println("LENGHT [ERROR]"); // this does not get triggered, which is good.
    return; // skip rest of function
  } else {
    cFile = SD.open("wimage.jpg", FILE_WRITE);
    cFile.print(incoming);
    cFile.close();
  }
}

我正在使用以下Lora library
谢谢你的帮助!

o2rvlv0m

o2rvlv0m1#

这里你犯的主要错误是你把文件内容当作一个字符串,这是绝对不应该的。一个二进制文件可以有0x00,字符串终止符,这肯定会毁了你的午餐。
首先,我们需要将32字节的块作为二进制blob来处理,并使用write(const uint8_t *buffer, size_t size);。另外,我们使用的是LoRa.write(cArray.length());,它没有做什么:它不会告诉LoRa库你发送了多少字节,接收方知道你收到了多少字节。你的函数应该是这样的:

void sendMessage(String cArray) {
  LoRa.beginPacket();
  LoRa.write(cArray, cArray.length());
  LoRa.endPacket();
}

接下来,传输本身。你正在while循环中传输,延迟非常小,太小了,至少有两个原因,,没有检查接收方是否确实收到了块#x,并且正确地接收了它。这将导致很多问题...
你已经有了一个循环,命名为loop(),所以你不需要另一个循环。相反,在loop中,从卡中读取32个字节,将它们发送到一个包中,包中包含块号、数据和基本CRC。例如,将包中的每个字节相加,并将其作为16位数使用。作为数据包的最后2个字节。您将拥有2 [计数器] +32 [数据] +2 [CRC]的结构。
然后切换到“等待确认”模式。直到你听到你的接收器返回,发送给你4个字节,2个为索引,2个为CRC,你什么也不做。如果发送回来的CRC是错误的,你不增加计数器。如果CRC是正确的,增加。然后你切换到发送模式。冲洗和重复。
在接收端,你处于待机模式。当你接收到一个数据包时,你计算CRC并比较--如果不正确,你把它发送回去,然后回到接收模式。如果正确,你把32个字节保存在缓冲区的正确位置。然后发送回索引+CRC。最后你保存。
哦,还有,是接收,不是接收...

相关问题