finally a working version, nigga
This commit is contained in:
parent
4a0d3af4c1
commit
93a3bb5e1a
5 changed files with 64 additions and 61 deletions
5
doc.md
Normal file
5
doc.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Build TCP Server
|
||||||
|
我們使用posix socket制作主要的HTTP伺服器,
|
||||||
|
我們在bind的socket使用O_NONBLOCK,在一個poll裏使用迴圈檢查是否有需要accept的request,
|
||||||
|
我們對客戶端的socket(accepted)使用blocking io與select處理鏈接。
|
||||||
|
我們的伺服器只有單一線程,以避免相關的同步問題且避免因爲受限的環境且容易處理底下的tag syncing 問題
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "./lib/meshtalos.h"
|
#include "./lib/meshtalos.h"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
#include "soc/rtc.h"
|
||||||
#include <esp_event.h>
|
#include <esp_event.h>
|
||||||
#include <esp_littlefs.h>
|
#include <esp_littlefs.h>
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "meshtalos.h"
|
#include "meshtalos.h"
|
||||||
#include "./mpack.h"
|
#include "./mpack.h"
|
||||||
#include "./picohttpparser.h"
|
#include "./picohttpparser.h"
|
||||||
|
#include "lwip/inet.h"
|
||||||
#include "lwip/sockets.h"
|
#include "lwip/sockets.h"
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
@ -22,8 +23,8 @@
|
||||||
#define HTTPVER "HTTP/1.1"
|
#define HTTPVER "HTTP/1.1"
|
||||||
#define IMG_W_SIZE 152
|
#define IMG_W_SIZE 152
|
||||||
#define IMG_H_SIZE 296
|
#define IMG_H_SIZE 296
|
||||||
#define DISPLAY_SIZE IMG_W_SIZE *IMG_H_SIZE
|
#define DISPLAY_SIZE (IMG_W_SIZE * IMG_H_SIZE / 8)
|
||||||
#define IMG_HEADER_SIZE 15
|
#define IMG_HEADER_SIZE 11
|
||||||
#define IMG_SIZE IMG_HEADER_SIZE + DISPLAY_SIZE
|
#define IMG_SIZE IMG_HEADER_SIZE + DISPLAY_SIZE
|
||||||
|
|
||||||
struct client {
|
struct client {
|
||||||
|
|
@ -72,6 +73,7 @@ ssize_t client_send(struct client *cli, const char *buf, size_t len) {
|
||||||
if (cli->invalid) {
|
if (cli->invalid) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
printf("client written: %d\n", len);
|
||||||
int ret = send(cli->fd, buf, len, MSG_NOSIGNAL);
|
int ret = send(cli->fd, buf, len, MSG_NOSIGNAL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
cli->invalid = true;
|
cli->invalid = true;
|
||||||
|
|
@ -174,12 +176,10 @@ int fbadreq(struct client *c, const char *s, ...) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int api_tag_upload(struct client *c, struct http_param *p) {
|
int api_tag_upload(struct client *c, struct http_param *p) {
|
||||||
|
|
||||||
printf("INTO TAG RECV\n");
|
|
||||||
int acc = 0;
|
int acc = 0;
|
||||||
for (int i = 0; i < p->headers_len; i++) {
|
for (int i = 0; i < p->headers_len; i++) {
|
||||||
if (HEAD_MATCH("Content-Type", p->headers[i]) &&
|
if (HEAD_MATCH("Content-Type", p->headers[i]) &&
|
||||||
HEAD_VAL_MATCH("image/x-portable-greymap", p->headers[i])) {
|
HEAD_VAL_MATCH("image/x-portable-bitmap", p->headers[i])) {
|
||||||
acc++;
|
acc++;
|
||||||
}
|
}
|
||||||
if (HEAD_MATCH("Content-Length", p->headers[i])) {
|
if (HEAD_MATCH("Content-Length", p->headers[i])) {
|
||||||
|
|
@ -192,18 +192,19 @@ int api_tag_upload(struct client *c, struct http_param *p) {
|
||||||
if (acc != 2) {
|
if (acc != 2) {
|
||||||
|
|
||||||
return fbadreq(c,
|
return fbadreq(c,
|
||||||
"Only accept request with PGM P5 format that height and "
|
"Only accept request with PGM P4 format that height and "
|
||||||
"width is either %03d,%03d",
|
"width is either %03d,%03d",
|
||||||
IMG_W_SIZE, IMG_H_SIZE);
|
IMG_W_SIZE, IMG_H_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t upload_size = p->body_len;
|
size_t upload_size = p->body_len;
|
||||||
memcpy(imgbuf, p->body_start, p->body_len);
|
memcpy(imgbuf, p->body_start, p->body_len);
|
||||||
|
printf("tag read %d\n", p->body_len);
|
||||||
|
|
||||||
while (upload_size < IMG_SIZE) {
|
while (upload_size < IMG_SIZE) {
|
||||||
// upload PGM sanitize
|
// upload PGM sanitize
|
||||||
if (upload_size > IMG_HEADER_SIZE) {
|
if (upload_size > IMG_HEADER_SIZE) {
|
||||||
if (strncmp(imgbuf, "P5", 2) != 0) {
|
if (strncmp(imgbuf, "P4", 2) != 0) {
|
||||||
return badreq(c);
|
return badreq(c);
|
||||||
}
|
}
|
||||||
int santinize_acc = 0;
|
int santinize_acc = 0;
|
||||||
|
|
@ -235,7 +236,11 @@ int api_tag_upload(struct client *c, struct http_param *p) {
|
||||||
? sizeof(httpbuf)
|
? sizeof(httpbuf)
|
||||||
: IMG_SIZE - upload_size;
|
: IMG_SIZE - upload_size;
|
||||||
ssize_t rcv_size = client_recv(c, httpbuf, next_size);
|
ssize_t rcv_size = client_recv(c, httpbuf, next_size);
|
||||||
|
if (rcv_size != next_size) {
|
||||||
|
return fbadreq(c, "size mistmatch");
|
||||||
|
}
|
||||||
memcpy(imgbuf + upload_size, httpbuf, rcv_size);
|
memcpy(imgbuf + upload_size, httpbuf, rcv_size);
|
||||||
|
printf("tag read %d\n", p->body_len);
|
||||||
upload_size += next_size;
|
upload_size += next_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -311,56 +316,44 @@ void http_client_handle(struct conn *c, struct client *client, int client_id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static inline int get_bit(const uint8_t *buf, int w, int x, int y) {
|
||||||
* @brief Rotates an 8-bit image 90 degrees clockwise IN-PLACE.
|
int i = y * w + x;
|
||||||
* @param data Pointer to the image buffer (1 byte per pixel)
|
return (buf[i >> 3] >> (7 - (i & 7))) & 1;
|
||||||
* @param W Original width (e.g., 296)
|
|
||||||
* @param H Original height (e.g., 152)
|
|
||||||
* * NOTE: After this function, the logical width is H and height is W.
|
|
||||||
* The buffer must be large enough to hold W*H bytes.
|
|
||||||
*/
|
|
||||||
void rotate90_clockwise_inplace(uint8_t *data, int W, int H) {
|
|
||||||
int total_pixels = W * H;
|
|
||||||
|
|
||||||
// We need 1 bit per pixel to track if we've moved it.
|
|
||||||
// For 296x152, this is 44,992 bits = 5,624 bytes.
|
|
||||||
uint8_t *visited = (uint8_t *)calloc((total_pixels + 7) / 8, 1);
|
|
||||||
if (!visited)
|
|
||||||
return; // Handle allocation failure (OOM)
|
|
||||||
|
|
||||||
for (int i = 0; i < total_pixels; i++) {
|
|
||||||
// Skip if this pixel was already moved as part of a previous cycle
|
|
||||||
if (visited[i >> 3] & (1 << (i & 7)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int curr_idx = i;
|
|
||||||
uint8_t val_to_move = data[i];
|
|
||||||
|
|
||||||
while (!(visited[curr_idx >> 3] & (1 << (curr_idx & 7)))) {
|
|
||||||
// Mark as visited
|
|
||||||
visited[curr_idx >> 3] |= (1 << (curr_idx & 7));
|
|
||||||
|
|
||||||
// Calculate new coordinates for 90-degree clockwise
|
|
||||||
// (x, y) -> (H - 1 - y, x)
|
|
||||||
int x = curr_idx % W;
|
|
||||||
int y = curr_idx / W;
|
|
||||||
|
|
||||||
// The NEW dimensions are Height H and Width W (swapped)
|
|
||||||
// New 1D Index = new_y * NEW_WIDTH + new_x
|
|
||||||
// For 90deg CW: new_x = H - 1 - y, new_y = x
|
|
||||||
int next_idx = x * H + (H - 1 - y);
|
|
||||||
|
|
||||||
// Swap values
|
|
||||||
uint8_t temp = data[next_idx];
|
|
||||||
data[next_idx] = val_to_move;
|
|
||||||
val_to_move = temp;
|
|
||||||
|
|
||||||
curr_idx = next_idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(visited);
|
|
||||||
}
|
}
|
||||||
#define IMG_BLK_SIZE 1024
|
|
||||||
|
static inline void set_bit(uint8_t *buf, int w, int x, int y, int v) {
|
||||||
|
int i = y * w + x;
|
||||||
|
uint8_t m = 1 << (7 - (i & 7));
|
||||||
|
if (v)
|
||||||
|
buf[i >> 3] |= m;
|
||||||
|
else
|
||||||
|
buf[i >> 3] &= ~m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief In-place 90-degree clockwise rotation for 1-bit-per-pixel images.
|
||||||
|
* @param data The image buffer
|
||||||
|
* @param W Original width
|
||||||
|
* @param H Original height
|
||||||
|
*/
|
||||||
|
void rotate90_inline(uint8_t *data, int W, int H) {
|
||||||
|
static uint8_t temp[(IMG_H_SIZE * IMG_W_SIZE + 7) / 8] = {0};
|
||||||
|
|
||||||
|
int new_w = H;
|
||||||
|
int new_h = W;
|
||||||
|
|
||||||
|
for (int y = 0; y < H; y++) {
|
||||||
|
for (int x = 0; x < W; x++) {
|
||||||
|
int v = get_bit(data, W, x, y);
|
||||||
|
|
||||||
|
// (x, y) → (h-1-y, x)
|
||||||
|
// set_bit(temp, new_w, H - 1 - y, x, v);
|
||||||
|
set_bit(temp, new_w, y, x, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memcpy(data, temp, DISPLAY_SIZE);
|
||||||
|
}
|
||||||
|
#define IMG_BLK_SIZE 300
|
||||||
|
|
||||||
void flush_mpack(mpack_writer_t *wr, const char *b, size_t len) {
|
void flush_mpack(mpack_writer_t *wr, const char *b, size_t len) {
|
||||||
struct client *c = mpack_writer_context(wr);
|
struct client *c = mpack_writer_context(wr);
|
||||||
|
|
@ -380,7 +373,7 @@ void send_image(struct client *c) {
|
||||||
mpack_write_cstr(&wr, "command");
|
mpack_write_cstr(&wr, "command");
|
||||||
mpack_write_cstr(&wr, "update_image");
|
mpack_write_cstr(&wr, "update_image");
|
||||||
mpack_write_cstr(&wr, "index");
|
mpack_write_cstr(&wr, "index");
|
||||||
mpack_write_u64(&wr, i);
|
mpack_write_u64(&wr, i - IMG_HEADER_SIZE);
|
||||||
mpack_write_cstr(&wr, "data");
|
mpack_write_cstr(&wr, "data");
|
||||||
mpack_write_bin(&wr, &imgbuf[i], MIN(IMG_BLK_SIZE, IMG_SIZE - i));
|
mpack_write_bin(&wr, &imgbuf[i], MIN(IMG_BLK_SIZE, IMG_SIZE - i));
|
||||||
mpack_finish_map(&wr);
|
mpack_finish_map(&wr);
|
||||||
|
|
@ -414,7 +407,8 @@ void tsend() {
|
||||||
}
|
}
|
||||||
printf("img_w: %d, img_h: %d\n", img_w, img_h);
|
printf("img_w: %d, img_h: %d\n", img_w, img_h);
|
||||||
if (img_w == IMG_H_SIZE) {
|
if (img_w == IMG_H_SIZE) {
|
||||||
rotate90_clockwise_inplace((uint8_t *)imgbuf + IMG_HEADER_SIZE, IMG_H_SIZE,
|
printf("rotate\n");
|
||||||
|
rotate90_inline((uint8_t *)imgbuf + IMG_HEADER_SIZE, IMG_H_SIZE,
|
||||||
IMG_W_SIZE);
|
IMG_W_SIZE);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < arrlen(workers.c); i++) {
|
for (int i = 0; i < arrlen(workers.c); i++) {
|
||||||
|
|
@ -424,12 +418,12 @@ void tsend() {
|
||||||
|
|
||||||
int main_listen(const int worker_port, int http_port) {
|
int main_listen(const int worker_port, int http_port) {
|
||||||
// workers
|
// workers
|
||||||
int sfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
int sfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
struct sockaddr_in b = {0};
|
struct sockaddr_in b = {0};
|
||||||
memset(&b, 0, sizeof(struct sockaddr_in));
|
memset(&b, 0, sizeof(struct sockaddr_in));
|
||||||
b.sin_port = htons(worker_port);
|
b.sin_port = htons(worker_port);
|
||||||
b.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
b.sin_family = AF_INET;
|
b.sin_family = AF_INET;
|
||||||
|
b.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
int val = 1;
|
int val = 1;
|
||||||
assert(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != -1);
|
assert(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != -1);
|
||||||
assert(bind(sfd, (struct sockaddr *)&b, sizeof(b)) != -1);
|
assert(bind(sfd, (struct sockaddr *)&b, sizeof(b)) != -1);
|
||||||
|
|
@ -443,8 +437,8 @@ int main_listen(const int worker_port, int http_port) {
|
||||||
int httpfd = socket(AF_INET, SOCK_STREAM, 0);
|
int httpfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
memset(&b, 0, sizeof(struct sockaddr_in));
|
memset(&b, 0, sizeof(struct sockaddr_in));
|
||||||
b.sin_port = htons(http_port);
|
b.sin_port = htons(http_port);
|
||||||
b.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
b.sin_family = AF_INET;
|
b.sin_family = AF_INET;
|
||||||
|
b.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
val = 1;
|
val = 1;
|
||||||
assert(setsockopt(httpfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != -1);
|
assert(setsockopt(httpfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != -1);
|
||||||
assert(bind(httpfd, (struct sockaddr *)&b, sizeof(b)) != -1);
|
assert(bind(httpfd, (struct sockaddr *)&b, sizeof(b)) != -1);
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,6 @@
|
||||||
#include "./storage.h"
|
#include "./storage.h"
|
||||||
|
|
||||||
#define TOPIC_LEN 20
|
#define TOPIC_LEN 20
|
||||||
#define IMG_W_SIZE 152
|
|
||||||
#define IMG_H_SIZE 296
|
|
||||||
#define DISPLAY_SIZE IMG_W_SIZE *IMG_H_SIZE
|
|
||||||
#define IMG_HEADER_SIZE 15
|
|
||||||
#define IMG_SIZE IMG_HEADER_SIZE + DISPLAY_SIZE
|
|
||||||
#define IMG_BLK_SIZE 300
|
|
||||||
|
|
||||||
struct Meshtalos {
|
struct Meshtalos {
|
||||||
struct Storage *storage;
|
struct Storage *storage;
|
||||||
|
|
|
||||||
9
tests/fill_random.py
Normal file
9
tests/fill_random.py
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
import requests as req
|
||||||
|
import random
|
||||||
|
|
||||||
|
blksize = 152 * 296
|
||||||
|
|
||||||
|
body = random.randbytes(blksize)
|
||||||
|
|
||||||
|
r = req.get("http://10.189.34.75/api/tag",data=body)
|
||||||
|
print(r.status_code)
|
||||||
Loading…
Add table
Reference in a new issue