Added a pixelflut
This commit is contained in:
		| @@ -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/ | ||||||
		Reference in New Issue
	
	Block a user
	 Andreas Völker
					Andreas Völker