Added a pixelflut
This commit is contained in:
parent
7f31d407d7
commit
e6bf90667d
@ -3,9 +3,16 @@ cmake_minimum_required(VERSION 2.8)
|
|||||||
SET(COMPILE_DEFINITIONS -Werror -Wall)
|
SET(COMPILE_DEFINITIONS -Werror -Wall)
|
||||||
|
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS "-O3")
|
set(CMAKE_C_FLAGS "-Os")
|
||||||
|
set(CMAKE_CXX_FLAGS "-Os")
|
||||||
|
#set(CMAKE_C_FLAGS "-g -ggdb")
|
||||||
|
#set(CMAKE_CXX_FLAGS "-g -ggdb")
|
||||||
|
|
||||||
add_executable(fbcp fbcp.c)
|
add_executable(fbcp fbcp.c)
|
||||||
target_link_libraries(fbcp m)
|
target_link_libraries(fbcp m)
|
||||||
|
|
||||||
add_executable(flicker flicker.c)
|
add_executable(flicker flicker.c)
|
||||||
|
|
||||||
|
add_executable(pixelflut pixelflut.cpp)
|
||||||
|
find_package (Threads)
|
||||||
|
target_link_libraries (pixelflut ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
243
apps/c-src/pixelflut.cpp
Normal file
243
apps/c-src/pixelflut.cpp
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
int Nx, Ny;
|
||||||
|
uint8_t *buf;
|
||||||
|
|
||||||
|
void SetPixel(int x, int y, uint8_t r, uint8_t g, uint8_t b){
|
||||||
|
if (x < 0 || x >= Nx || y < 0 || y >= Ny) return;
|
||||||
|
buf[3*(x+Nx*y)+0] = r;
|
||||||
|
buf[3*(x+Nx*y)+1] = g;
|
||||||
|
buf[3*(x+Nx*y)+2] = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPixel(int x, int y, uint32_t c){
|
||||||
|
SetPixel(x, y, (c >> 16)&0xff, (c >> 8)&0xff, c&0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetPixel(int x, int y){
|
||||||
|
if (x < 0 || x >= Nx || y < 0 || y >= Ny) return 0;
|
||||||
|
uint32_t r = buf[3*(x+Nx*y)+0];
|
||||||
|
uint32_t g = buf[3*(x+Nx*y)+1];
|
||||||
|
uint32_t b = buf[3*(x+Nx*y)+2];
|
||||||
|
return (r << 16) | (g << 8) | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const int PFT_CONNECTION_TIMEOUT = 1;
|
||||||
|
volatile int PFT_ClientThreadCount = 0;
|
||||||
|
|
||||||
|
bool PFT_ReadIdent(char** begin, char* end, char* out, int size){
|
||||||
|
int i = 0;
|
||||||
|
while (*begin != end && isalpha(**begin) && i < size-1){
|
||||||
|
out[i++] = **begin;
|
||||||
|
(*begin)++;
|
||||||
|
}
|
||||||
|
out[i] = '\0';
|
||||||
|
return i != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PRF_ReadInt(char** begin, char* end, int *out){
|
||||||
|
if (*begin == end || !isdigit(**begin))
|
||||||
|
return false;
|
||||||
|
*out = 0;
|
||||||
|
while(*begin != end && isdigit(**begin)){
|
||||||
|
*out = (*out)*10+(**begin-'0');
|
||||||
|
(*begin)++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PFT_IsHex(char c){
|
||||||
|
return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
|
||||||
|
}
|
||||||
|
|
||||||
|
int PFT_HexCharToInt(char c){
|
||||||
|
if (isdigit(c))
|
||||||
|
return c-'0';
|
||||||
|
if (c >= 'a' && c <= 'f')
|
||||||
|
return c-'a'+10;
|
||||||
|
if (c >= 'A' && c <= 'F')
|
||||||
|
return c-'A'+10;
|
||||||
|
assert(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PFT_ReadColorHex(char** begin, char* end, uint32_t *out){
|
||||||
|
char* oldbegin = *begin;
|
||||||
|
*out = 0;
|
||||||
|
if (end-*begin < 6)
|
||||||
|
return false;
|
||||||
|
for(int i = 0; i != 6; i++){
|
||||||
|
if (!PFT_IsHex(**begin)){
|
||||||
|
*begin = oldbegin;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*out = (*out)*16+PFT_HexCharToInt(**begin);
|
||||||
|
(*begin)++;
|
||||||
|
}
|
||||||
|
if (end-*begin >= 2 && PFT_IsHex(**begin) && PFT_IsHex(begin[0][1])){
|
||||||
|
*out = (*out)*16+PFT_HexCharToInt(**begin);
|
||||||
|
(*begin)++;
|
||||||
|
*out = (*out)*16+PFT_HexCharToInt(**begin);
|
||||||
|
(*begin)++;
|
||||||
|
}else{
|
||||||
|
*out *= 256;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PFT_SkipSpace(char **begin, char *end){
|
||||||
|
while(*begin != end && **begin == ' '){
|
||||||
|
(*begin)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PFT_SkipOverNextNewline(char **begin, char *end){
|
||||||
|
while(*begin != end && **begin != '\n'){
|
||||||
|
(*begin)++;
|
||||||
|
}
|
||||||
|
if (*begin != end)
|
||||||
|
(*begin)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PFT_HandlePixelflutMessage(uint8_t *buffer, int size, int sock){
|
||||||
|
char *begin = (char*)buffer;
|
||||||
|
char *end = begin + size;
|
||||||
|
char cmd_buffer[32];
|
||||||
|
char response_buffer[100];
|
||||||
|
int x, y;
|
||||||
|
uint32_t c;
|
||||||
|
//packet_size = MIN(offset + (pixellength * MAX_PIXELS), packet_size);
|
||||||
|
while ( begin != end ) {
|
||||||
|
if (!PFT_ReadIdent(&begin, end, cmd_buffer, 32)){
|
||||||
|
PFT_SkipOverNextNewline(&begin, end);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strcmp(cmd_buffer, "PX") == 0){
|
||||||
|
PFT_SkipSpace(&begin, end);
|
||||||
|
if (!PRF_ReadInt(&begin, end, &x)){
|
||||||
|
PFT_SkipOverNextNewline(&begin, end);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PFT_SkipSpace(&begin, end);
|
||||||
|
if (!PRF_ReadInt(&begin, end, &y)){
|
||||||
|
PFT_SkipOverNextNewline(&begin, end);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PFT_SkipSpace(&begin, end);
|
||||||
|
if (PFT_ReadColorHex(&begin, end, &c)){
|
||||||
|
SetPixel(x, y, c>>8);
|
||||||
|
}else{
|
||||||
|
c = GetPixel(x, y);
|
||||||
|
int len = sprintf(response_buffer, "PX %i %i %06x\n", x, y, c);
|
||||||
|
send(sock, response_buffer, len, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(cmd_buffer, "SIZE") == 0){
|
||||||
|
int len = sprintf(response_buffer, "SIZE %i %i", Nx, Ny);
|
||||||
|
send(sock, response_buffer, len, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (strcmp(cmd_buffer, "HELP") == 0){
|
||||||
|
int len = sprintf(response_buffer, "see https://github.com/defnull/pixelflut\n");
|
||||||
|
send(sock, response_buffer, len, 0);
|
||||||
|
}
|
||||||
|
PFT_SkipOverNextNewline(&begin, end);
|
||||||
|
}
|
||||||
|
return begin-(char*)buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void * PFT_HandleClient(int sock){
|
||||||
|
PFT_ClientThreadCount++;
|
||||||
|
uint8_t buf[1024];
|
||||||
|
uint8_t offset = 0;
|
||||||
|
int read_size = 0;
|
||||||
|
while( (read_size = recv(sock , buf + offset, sizeof(buf) - offset , 0)) > 0){
|
||||||
|
offset = PFT_HandlePixelflutMessage(buf, read_size, sock);
|
||||||
|
memcpy(buf, buf+read_size-offset, offset);
|
||||||
|
}
|
||||||
|
close(sock);
|
||||||
|
PFT_ClientThreadCount--;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void * PFT_RunServer(unsigned long port){
|
||||||
|
int client_sock;
|
||||||
|
socklen_t addr_len;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
addr_len = sizeof(addr);
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
fprintf(stderr, "PF: Starting Pixelflut Server...\n");
|
||||||
|
|
||||||
|
int server_sock = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
|
|
||||||
|
tv.tv_sec = PFT_CONNECTION_TIMEOUT;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
addr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
|
||||||
|
if (server_sock == -1){
|
||||||
|
fprintf(stderr, "PF: socket() failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int one = 1;
|
||||||
|
if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)) < 0)
|
||||||
|
fprintf(stderr, "PF: setsockopt(SO_REUSEADDR) failed\n");
|
||||||
|
if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(int)) < 0)
|
||||||
|
fprintf(stderr, "PF: setsockopt(SO_REUSEPORT) failed\n");
|
||||||
|
|
||||||
|
int retries;
|
||||||
|
for (retries = 0; bind(server_sock, (struct sockaddr*)&addr, sizeof(addr)) == -1 && retries < 10; retries++){
|
||||||
|
fprintf(stderr, "PF: bind() failed ...retry in 5s\n");
|
||||||
|
usleep(5000000);
|
||||||
|
}
|
||||||
|
if (retries == 10)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (listen(server_sock, 4) == -1){
|
||||||
|
fprintf(stderr, "PF: listen() failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "PF: Pixelflut Listening...\n");
|
||||||
|
|
||||||
|
setsockopt(server_sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv,sizeof(struct timeval));
|
||||||
|
setsockopt(server_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
|
||||||
|
|
||||||
|
while(true){
|
||||||
|
client_sock = accept(server_sock, (struct sockaddr*)&addr, &addr_len);
|
||||||
|
if(client_sock > 0){
|
||||||
|
std::thread client_thread(PFT_HandleClient, client_sock);
|
||||||
|
client_thread.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(server_sock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
Nx = atoi(argv[1]);
|
||||||
|
Ny = atoi(argv[2]);
|
||||||
|
buf = (uint8_t*)malloc(Nx*Ny*3);
|
||||||
|
int port = atoi(argv[3]);
|
||||||
|
if (port == 0) port = 4444;
|
||||||
|
|
||||||
|
std::thread pixelflut_tcp_thread(&PFT_RunServer,(unsigned long)port);
|
||||||
|
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
write(1, buf, Nx*Ny*3);
|
||||||
|
usleep(33*1000);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
BIN
apps/flicker
BIN
apps/flicker
Binary file not shown.
@ -22,6 +22,7 @@ WebPort = 8000
|
|||||||
Apps = [
|
Apps = [
|
||||||
{"guiname": "Structure formation", "name": "swifthohenberg", "cmd": "apps/swifthohenberg.py", "persistent": False},
|
{"guiname": "Structure formation", "name": "swifthohenberg", "cmd": "apps/swifthohenberg.py", "persistent": False},
|
||||||
{"guiname": "Flicker", "name": "flicker", "cmd": "apps/flicker"},
|
{"guiname": "Flicker", "name": "flicker", "cmd": "apps/flicker"},
|
||||||
|
{"guiname": "Pixelflut", "name": "pixelflut", "cmd": "apps/pixelflut", "persistent": True},
|
||||||
{"guiname": "Pong", "name": "pong", "cmd": "apps/pong.py"},
|
{"guiname": "Pong", "name": "pong", "cmd": "apps/pong.py"},
|
||||||
{"guiname": "YoutubeDL", "name": "youtubedl", "cmd": "apps/youtubedl.sh", "persistent": False},
|
{"guiname": "YoutubeDL", "name": "youtubedl", "cmd": "apps/youtubedl.sh", "persistent": False},
|
||||||
{"guiname": "Show Framebuffer", "name": "fbcp", "cmd": ["apps/fbcp", "/dev/fb0"]},
|
{"guiname": "Show Framebuffer", "name": "fbcp", "cmd": ["apps/fbcp", "/dev/fb0"]},
|
||||||
|
@ -16,4 +16,5 @@ cmake ../../apps/c-src
|
|||||||
make
|
make
|
||||||
popd
|
popd
|
||||||
mv build/c/fbcp apps/
|
mv build/c/fbcp apps/
|
||||||
mv build/c/flicker apps/
|
mv build/c/flicker apps/
|
||||||
|
mv build/c/pixelflut apps/
|
Loading…
Reference in New Issue
Block a user