finally a working version, nigga

This commit is contained in:
jasinco 2026-01-02 15:27:55 +08:00
parent 4a0d3af4c1
commit 93a3bb5e1a
5 changed files with 64 additions and 61 deletions

5
doc.md Normal file
View 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 問題

View file

@ -1,6 +1,7 @@
#include "./lib/meshtalos.h"
#include "esp_err.h"
#include "network.h"
#include "soc/rtc.h"
#include <esp_event.h>
#include <esp_littlefs.h>
#include <esp_log.h>

View file

@ -1,6 +1,7 @@
#include "meshtalos.h"
#include "./mpack.h"
#include "./picohttpparser.h"
#include "lwip/inet.h"
#include "lwip/sockets.h"
#include <arpa/inet.h>
#include <assert.h>
@ -22,8 +23,8 @@
#define HTTPVER "HTTP/1.1"
#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 DISPLAY_SIZE (IMG_W_SIZE * IMG_H_SIZE / 8)
#define IMG_HEADER_SIZE 11
#define IMG_SIZE IMG_HEADER_SIZE + DISPLAY_SIZE
struct client {
@ -72,6 +73,7 @@ ssize_t client_send(struct client *cli, const char *buf, size_t len) {
if (cli->invalid) {
return -1;
}
printf("client written: %d\n", len);
int ret = send(cli->fd, buf, len, MSG_NOSIGNAL);
if (ret < 0) {
cli->invalid = true;
@ -174,12 +176,10 @@ int fbadreq(struct client *c, const char *s, ...) {
return -1;
}
int api_tag_upload(struct client *c, struct http_param *p) {
printf("INTO TAG RECV\n");
int acc = 0;
for (int i = 0; i < p->headers_len; 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++;
}
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) {
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",
IMG_W_SIZE, IMG_H_SIZE);
}
size_t upload_size = p->body_len;
memcpy(imgbuf, p->body_start, p->body_len);
printf("tag read %d\n", p->body_len);
while (upload_size < IMG_SIZE) {
// upload PGM sanitize
if (upload_size > IMG_HEADER_SIZE) {
if (strncmp(imgbuf, "P5", 2) != 0) {
if (strncmp(imgbuf, "P4", 2) != 0) {
return badreq(c);
}
int santinize_acc = 0;
@ -235,7 +236,11 @@ int api_tag_upload(struct client *c, struct http_param *p) {
? sizeof(httpbuf)
: IMG_SIZE - upload_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);
printf("tag read %d\n", p->body_len);
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) {
int i = y * w + x;
return (buf[i >> 3] >> (7 - (i & 7))) & 1;
}
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 Rotates an 8-bit image 90 degrees clockwise IN-PLACE.
* @param data Pointer to the image buffer (1 byte per pixel)
* @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.
* @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_clockwise_inplace(uint8_t *data, int W, int H) {
int total_pixels = W * H;
void rotate90_inline(uint8_t *data, int W, int H) {
static uint8_t temp[(IMG_H_SIZE * IMG_W_SIZE + 7) / 8] = {0};
// 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)
int new_w = H;
int new_h = W;
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;
for (int y = 0; y < H; y++) {
for (int x = 0; x < W; x++) {
int v = get_bit(data, W, x, y);
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;
// (x, y) → (h-1-y, x)
// set_bit(temp, new_w, H - 1 - y, x, v);
set_bit(temp, new_w, y, x, v);
}
}
free(visited);
memcpy(data, temp, DISPLAY_SIZE);
}
#define IMG_BLK_SIZE 1024
#define IMG_BLK_SIZE 300
void flush_mpack(mpack_writer_t *wr, const char *b, size_t len) {
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, "update_image");
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_bin(&wr, &imgbuf[i], MIN(IMG_BLK_SIZE, IMG_SIZE - i));
mpack_finish_map(&wr);
@ -414,8 +407,9 @@ void tsend() {
}
printf("img_w: %d, img_h: %d\n", img_w, img_h);
if (img_w == IMG_H_SIZE) {
rotate90_clockwise_inplace((uint8_t *)imgbuf + IMG_HEADER_SIZE, IMG_H_SIZE,
IMG_W_SIZE);
printf("rotate\n");
rotate90_inline((uint8_t *)imgbuf + IMG_HEADER_SIZE, IMG_H_SIZE,
IMG_W_SIZE);
}
for (int i = 0; i < arrlen(workers.c); i++) {
send_image(workers.c + i);
@ -424,12 +418,12 @@ void tsend() {
int main_listen(const int worker_port, int http_port) {
// workers
int sfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
int sfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in b = {0};
memset(&b, 0, sizeof(struct sockaddr_in));
b.sin_port = htons(worker_port);
b.sin_addr.s_addr = htonl(INADDR_ANY);
b.sin_family = AF_INET;
b.sin_addr.s_addr = htonl(INADDR_ANY);
int val = 1;
assert(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != -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);
memset(&b, 0, sizeof(struct sockaddr_in));
b.sin_port = htons(http_port);
b.sin_addr.s_addr = htonl(INADDR_ANY);
b.sin_family = AF_INET;
b.sin_addr.s_addr = htonl(INADDR_ANY);
val = 1;
assert(setsockopt(httpfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != -1);
assert(bind(httpfd, (struct sockaddr *)&b, sizeof(b)) != -1);

View file

@ -11,12 +11,6 @@
#include "./storage.h"
#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 Storage *storage;

9
tests/fill_random.py Normal file
View 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)