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 "esp_err.h"
|
||||
#include "network.h"
|
||||
#include "soc/rtc.h"
|
||||
#include <esp_event.h>
|
||||
#include <esp_littlefs.h>
|
||||
#include <esp_log.h>
|
||||
|
|
|
|||
|
|
@ -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,7 +407,8 @@ 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,
|
||||
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++) {
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
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