이전글을 아래 링크 참고
c++로 변환은 했는데 문제가 발생했다.
화질이 QVGA (320x240) 로 너무 구려서 VGA(640x480)로 업데이트 했는데 udp 패킷 순서가 3~4개일 때는 별로 안꼬여서 이전 글의 알고리즘이 잘 작동했는데 8~9개 정도로 늘어나니까 답도 없이 꼬여버렸다...
패킷을 수신하긴 하는데 합치다가 중간에 이가 빠져있으니 저장을 못하고 그냥 다음 이미지 조립으로 넘어가는 걸 반복했음.
일단 코드를 올리자면
아두이노 쪽 코드 수정은 이 부분만 수정하면 frame size가 결정됨.
sensor.h에 들어가보면 FRAMESIZE가 enum으로 정의되어 있고, 원하는 해상도를 선택해서 코드에 넣어주면 적용가능함.
그럼 이제 서버측 C++ 코드가 나와줘야겠죠?
#include <iostream>
#include <fstream>
#include <vector>
#include <cstdint>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib") // Link with ws2_32.lib
#define UDP_PORT 12345
#define MAX_PACKET_SIZE 1450
#define MAX_PACKETS 10
int main() {
// Initialize Winsock
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "Failed to initialize Winsock." << std::endl;
return -1;
}
// Create a UDP socket
SOCKET udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (udpSocket == INVALID_SOCKET) {
std::cerr << "Error creating UDP socket." << std::endl;
WSACleanup();
return -1;
}
// Bind the socket to the specified IP address and port
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(UDP_PORT);
if (bind(udpSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "Error binding UDP socket." << std::endl;
closesocket(udpSocket);
WSACleanup();
return -1;
}
// Initialize variables for receiving data
std::vector<std::vector<uint8_t>> tempData(MAX_PACKETS, std::vector<uint8_t>());
std::vector<uint8_t> combinedData;
combinedData.reserve(MAX_PACKET_SIZE * MAX_PACKETS);
while (true) {
// Receive data from the socket
uint8_t buffer[MAX_PACKET_SIZE];
sockaddr_in clientAddr;
int addrLen = sizeof(clientAddr);
ssize_t bytesReceived = recvfrom(udpSocket, reinterpret_cast<char*>(buffer), sizeof(buffer), 0, (struct sockaddr*)&clientAddr, &addrLen);
if (bytesReceived < 0) {
std::cerr << "Error receiving data." << std::endl;
break;
}
// Extract frame and packet information
uint8_t frameNo = buffer[0];
uint8_t packetNo = buffer[1];
uint8_t* imageData = buffer + 2;
size_t imageSize = bytesReceived - 2;
std::cout << "Received Frame: " << static_cast<int>(frameNo) << ", Packet: " << static_cast<int>(packetNo)
<< ", Image Size: " << imageSize << " bytes" << std::endl;
// Combine image data
tempData[packetNo].insert(tempData[packetNo].end(), imageData, imageData + imageSize);
// Check if all packets for the frame have been received
if (imageSize < MAX_PACKET_SIZE-2 && packetNo > 0) {
// Combine data from all packets
for (int index = 0; index <= packetNo; ++index) {
if (tempData[index].empty()) {
tempData = std::vector<std::vector<uint8_t>>(MAX_PACKETS, std::vector<uint8_t>());
combinedData.clear();
continue;
}
combinedData.insert(combinedData.end(), tempData[index].begin(), tempData[index].end());
}
// Save the image to a file (replace this with your own image saving logic)
std::string filename = "received_image_" + std::to_string(frameNo) + ".jpg";
std::ofstream outFile(filename, std::ios::binary);
outFile.write(reinterpret_cast<const char*>(combinedData.data()), combinedData.size());
outFile.close();
std::cout << "Image saved as " << filename << std::endl;
// Reset data for the next frame
tempData = std::vector<std::vector<uint8_t>>(MAX_PACKETS, std::vector<uint8_t>());
combinedData.clear();
}
}
// Close the UDP socket and cleanup Winsock
closesocket(udpSocket);
WSACleanup();
return 0;
}
vscode 환경이고 터미널에 gcc를 쳐서 컴파일을 해줬음.
PS C:\Users\wooch\vscode_source> gcc .\ESP32_CAM_SERVER_UDP.cpp -o udp_server -lws2_32 -lstdc++
PS C:\Users\wooch\vscode_source> .\udp_server.exe
근데 글 작성하면서 보니까 packet size는 11000~16000까지도 가는데 서버측 packet size를 10으로 줘서 문제가 생긴 것 같다는 느낌을 빡 받았음.
일단 20으로 바꿔본다.
엇?! 되네??
640 480으로 들어오고 3초 정도 했을 때30개 정도 들어왔다. 10fps 정도 잡히는 듯 했다.
요건 정상적으로 저장된 이미지고 초점이 안잡혀서 흐릿하긴 한데, 빵판이랑 버즈는 잘 보임.
다만 문제는 저장한 이미지 파일 중 0Byte인 파일이 가끔 있다는 점과 아래 사진처럼 짤려서 받는게 있다는 점이다.
근데 신기한 점은 중간까지 쓰여진 파일은 단 하나도 없다는 점이다. 모두 패킷 하나만 저장한 거 처럼 이 위치에서 짤려있음.
이 문제를 해결해서 다시 돌아오겠소..아디오스..
#include <iostream>
#include <fstream>
#include <vector>
#include <cstdint>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib") // Link with ws2_32.lib
#define UDP_PORT 12345
#define MAX_PACKET_SIZE 1450
#define MAX_PACKETS 20
int main() {
// Initialize Winsock
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "Failed to initialize Winsock." << std::endl;
return -1;
}
// Create a UDP socket
SOCKET udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (udpSocket == INVALID_SOCKET) {
std::cerr << "Error creating UDP socket." << std::endl;
WSACleanup();
return -1;
}
// Bind the socket to the specified IP address and port
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(UDP_PORT);
if (bind(udpSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "Error binding UDP socket." << std::endl;
closesocket(udpSocket);
WSACleanup();
return -1;
}
// Initialize variables for receiving data
std::vector<std::vector<uint8_t>> tempData(MAX_PACKETS, std::vector<uint8_t>());
std::vector<uint8_t> combinedData;
combinedData.reserve(MAX_PACKET_SIZE * MAX_PACKETS);
while (true) {
// Receive data from the socket
uint8_t buffer[MAX_PACKET_SIZE];
sockaddr_in clientAddr;
int addrLen = sizeof(clientAddr);
ssize_t bytesReceived = recvfrom(udpSocket, reinterpret_cast<char*>(buffer), sizeof(buffer), 0, (struct sockaddr*)&clientAddr, &addrLen);
if (bytesReceived < 0) {
std::cerr << "Error receiving data." << std::endl;
break;
}
// Extract frame and packet information
uint8_t frameNo = buffer[0];
uint8_t packetNo = buffer[1];
uint8_t* imageData = buffer + 2;
size_t imageSize = bytesReceived - 2;
std::cout << "Received Frame: " << static_cast<int>(frameNo) << ", Packet: " << static_cast<int>(packetNo)
<< ", Image Size: " << imageSize << " bytes" << std::endl;
// Combine image data
tempData[packetNo].insert(tempData[packetNo].end(), imageData, imageData + imageSize);
// Check if all packets for the frame have been received
if (imageSize < MAX_PACKET_SIZE-2 && packetNo > 0) {
// Combine data from all packets
for (int index = 0; index <= packetNo; ++index) {
if (tempData[index].empty()) {
tempData = std::vector<std::vector<uint8_t>>(MAX_PACKETS, std::vector<uint8_t>());
combinedData.clear();
continue;
}
combinedData.insert(combinedData.end(), tempData[index].begin(), tempData[index].end());
}
// Save the image to a file (replace this with your own image saving logic)
std::string filename = "received_image_" + std::to_string(frameNo) + ".jpg";
std::ofstream outFile(filename, std::ios::binary);
outFile.write(reinterpret_cast<const char*>(combinedData.data()), combinedData.size());
outFile.close();
}
// Close the UDP socket and cleanup Winsock
closesocket(udpSocket);
WSACleanup();
return 0;
}
해결 중 만난 끔찍한 혼종.. 계속 해결하겠슴다..
'Firmware Programming' 카테고리의 다른 글
[ARM] ARM 어셈블리어 분석 (0) | 2024.02.13 |
---|---|
[ARM] ARM 프로세서 기초 (0) | 2024.02.13 |
[Firmware Programming] ESP32-CAM 보드 UDP camera frame 패킷 순서 제어 및 실시간 전송 (1) | 2024.02.10 |
[Firmware Programming] ESP32-CAM 보드 usb로 upload 하기 (1) | 2024.02.08 |
[컴퓨터 구조] 컴퓨터 구조-CPU, ALU, Memory (0) | 2024.02.08 |