Disabled external gits

This commit is contained in:
2022-04-07 18:54:11 +02:00
parent 15e7120d6d
commit 0fb3e365d4
376 changed files with 50840 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
CC=g++
LDLIBS=`pkg-config --libs sfml-graphics sfml-window sfml-network`
all: main
main.o: main.cpp
main: main.o
run:
@./main
clean:
rm -f main.o main

View File

@@ -0,0 +1,120 @@
#include <SFML/Graphics.hpp>
#include <SFML/Network.hpp>
#include <iostream>
#include <type_traits>
using namespace std;
#define IMAGE_WIDTH 80
#define IMAGE_HEIGHT 60
#define SCALE_FACTOR 10
#define UPDATE_INTERVAL IMAGE_HEIGHT
#define SERVER_PORT 25700
#define BUFFER_SIZE (4 + IMAGE_WIDTH * 2)
#define HANDSHAKE_TIMEOUT 2000
void updateLine(uint8_t* buffer, uint32_t lineIndex, uint16_t* line);
void bernsteinRGB(uint8_t* rgba, double t);
void sendHandshake(sf::UdpSocket& socket, sf::IpAddress address, unsigned short port);
int main(int argc, char* argv[]) {
if (argc != 2) {
cout << "Invalid usage of client. You should pass the address of the server." << endl;
return -1;
}
// We create the window to which we render the image
sf::RenderWindow window(sf::VideoMode(IMAGE_WIDTH * SCALE_FACTOR, IMAGE_HEIGHT * SCALE_FACTOR), "Thermalizer", sf::Style::Close);
// The intermediate buffer in which the image is received before being sent to the GPU
uint8_t buffer[IMAGE_HEIGHT * IMAGE_WIDTH * 4]; // RGBA = 4 bytes per pixel
size_t lastRefresh = 0; // the number of lines since the last refresh
uint32_t lineIndex = 0; // the index of the last line that was received
// The texture to which the image will be drawn
sf::Texture texture;
texture.create(IMAGE_WIDTH, IMAGE_HEIGHT);
sf::Sprite sprite;
sprite.setTexture(texture);
sprite.setScale(SCALE_FACTOR, SCALE_FACTOR);
// The buffer in which the packet for the lines are received
char lineBuffer[BUFFER_SIZE];
size_t received;
sf::IpAddress serverAddress(argv[1]), senderAddress;
unsigned short serverPort = SERVER_PORT, senderPort;
// Create the UDP socket
cout << "Creating and binding a UDP socket..." << endl;
sf::UdpSocket socket;
sf::SocketSelector selector;
if (socket.bind(sf::UdpSocket::AnyPort) != sf::Socket::Done) {
cout << "Couldn't bind socket on port " << socket.getLocalPort() << endl;
return -1;
}
cout << "UDP Socket successfully bound." << endl;
sendHandshake(socket, serverAddress, serverPort);
selector.add(socket);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
// If the user requested the window to be closed
if (event.type == sf::Event::Closed ||
(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Q)) {
// Inform the server about the client stopping
socket.send(nullptr, 0, serverAddress, serverPort);
window.close();
}
}
if (selector.wait(sf::milliseconds(500))) {
// If a packet was received, we update the intermediate buffer
socket.receive(lineBuffer, BUFFER_SIZE, received, senderAddress, senderPort);
lineIndex = *((uint32_t*) lineBuffer);
updateLine(buffer, lineIndex, (uint16_t*) (lineBuffer + sizeof(uint32_t)));
lastRefresh++;
} else {
// If no packet was received in a while, we re-send a handshake to try to reconnect
sendHandshake(socket, serverAddress, serverPort);
}
// We refresh the image every once in a while, so that if there is packet loss on the last
// line the screen is still updated.
if (lastRefresh == UPDATE_INTERVAL || lineIndex == IMAGE_HEIGHT - 1) {
// If enough packets were received, we update the texture
lastRefresh = 0;
texture.update(buffer);
// And draw it to the screen
window.clear();
window.draw(sprite);
window.display();
}
}
}
// Updates the line of the buffer with the packet that arrived
void updateLine(uint8_t* buffer, uint32_t lineIndex, uint16_t* line) {
uint8_t* lineBuffer = buffer + lineIndex * IMAGE_WIDTH * 4;
for (size_t x = 0; x < IMAGE_WIDTH; x++)
bernsteinRGB(lineBuffer + x * 4, (double) line[x] / 0x3FFF);
}
// Performs the color interpolation using Bernstein polynomials
void bernsteinRGB(uint8_t* rgba, double t) {
rgba[0] = (9 * (1 - t) * t * t * t) * 255;
rgba[1] = (15 * (1 - t) * (1 - t) * t * t) * 255;
rgba[2] = (9 * (1 - t) * (1 - t) * (1 - t) * t) * 255;
rgba[3] = 255;
}
// Sends a handshake to the server
void sendHandshake(sf::UdpSocket& socket, sf::IpAddress address, unsigned short port) {
cout << "Sending a handshake to the server..." << endl;
socket.send(nullptr, 0, address, port);
}

View File

@@ -0,0 +1,5 @@
LDLIBS= -lcaca
CFLAGS= -Wall
main: main.o
main.o: main.c

View File

@@ -0,0 +1,216 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <caca.h>
#define ERR -1
#define NO_ERR 0
#define M_REQUIRE(cond_, mess_, ...) \
do{ \
if(!(cond_)){ \
fprintf(stderr, mess_, ##__VA_ARGS__); \
return ERR; \
} \
}while(0);
#define M_REQUIRE_NO_ERR(v, mess_, ...)\
M_REQUIRE(v==NO_ERR, mess_, ##__VA_ARGS__)
#define M_REQUIRE_NO_NULL(v, mess_, ...)\
M_REQUIRE(v!=NULL, mess_, ##__VA_ARGS__)
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
#define DEFAULT_PORT 25700
#define IM_WIDTH 80
#define IM_HEIGHT 60
#define IM_BPP 16
#define IM_TOTAL IM_WIDTH*IM_HEIGHT
#define PCKT_SIZE (IM_WIDTH*sizeof(pix_t)+sizeof(uint32_t))
#define PX_MAX_V 0x3FFF
#define IM_MR 0xFF00
#define IM_MG 0x0000
#define IM_MB 0x00FF
#define IM_MA 0x0000
#define IM_5B 0x1F
#define REF_DIV 1
typedef uint16_t pix_t;
typedef struct sockaddr_in saddr_t;
/*=================================================================================================*/
pix_t IMG_IN[IM_TOTAL] = {0};
caca_canvas_t* cv = NULL;
caca_display_t* dp = NULL;
caca_dither_t* dither;
int ww = 0, wh = 0;
uint64_t msg_cnt = 0;
uint8_t refresh = 0;
char event = 0;
/*=================================================================================================*/
int setup_caca(){
cv = caca_create_canvas(IM_WIDTH,IM_HEIGHT);
M_REQUIRE_NO_NULL(cv, "Error: Unable to create caca canvas\n");
dp = caca_create_display(cv);
M_REQUIRE_NO_NULL(dp, "Error: Unable to create caca canvas\n");
caca_set_display_title(dp,"CACA HEAT VIEWER");
ww = caca_get_canvas_width(cv);
wh = caca_get_canvas_height(cv);
#ifdef COLORING_RB
dither = caca_create_dither(IM_BPP,IM_WIDTH,IM_HEIGHT,IM_WIDTH*sizeof(pix_t),IM_MR,IM_MG,IM_MB,IM_MA);
#else
dither = caca_create_dither(IM_BPP,IM_WIDTH,IM_HEIGHT,IM_WIDTH*sizeof(pix_t),IM_5B<<10,IM_5B<<5,IM_5B,IM_MA);
#endif
caca_refresh_display(dp);
return NO_ERR;
}
int clear_caca(){
caca_free_display(dp);
caca_free_canvas(cv);
return NO_ERR;
}
int get_server_addr(const char* ip, const uint16_t port, struct sockaddr_in* const p_server_addr){
assert(p_server_addr != NULL);
struct sockaddr_in server_addr = {0};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
if(ip == NULL){
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
}else{
M_REQUIRE(inet_aton(ip, &server_addr.sin_addr)== 1, "Error: Unable to set server adress (IP)\n");
}
*p_server_addr = server_addr;
return NO_ERR;
}
int bind_server(const int socket, const uint16_t port){
struct sockaddr_in server_addr;
M_REQUIRE_NO_ERR(get_server_addr(NULL, port, &server_addr), "Error: Unable to get server adress\n");
M_REQUIRE_NO_ERR(bind(socket, (const struct sockaddr*) &server_addr, sizeof(server_addr)), " Error: Unable to bind socket\n");
return NO_ERR;
}
pix_t bernstein_rgb(float f){
uint8_t r = (9*(1-f) *f *f *f)*IM_5B;
uint8_t g = (15*(1-f) *(1-f) *f *f)*IM_5B;
uint8_t b = (9*(1-f) *(1-f) *(1-f) *f)*IM_5B;
return r<<10 | g<<5 | b;
}
pix_t custom_rb(float f){
uint8_t r = f*0xFF ;
uint8_t b = (1-f)*0xFF;
return r<<8 | b;
}
void adjust_row(uint32_t row){
for(size_t i = 0; i < IM_WIDTH; ++i){
#ifdef COLORING_RB
IMG_IN[row*IM_WIDTH+i] = custom_rb((float)IMG_IN[row*IM_WIDTH+i]/PX_MAX_V);
#else
IMG_IN[row*IM_WIDTH+i] = bernstein_rgb((float)IMG_IN[row*IM_WIDTH+i]/PX_MAX_V);
#endif
}
}
int handle_message(ssize_t in_msg_len, uint8_t* in_msg){
M_REQUIRE_NO_NULL(in_msg,"Error: input message is null\n");
M_REQUIRE(in_msg_len >=0, "Error: server message timeout\n");
M_REQUIRE(in_msg_len == PCKT_SIZE, "Error: message with wrong length (%zu)\n",in_msg_len);
uint32_t row = (uint32_t) in_msg[0];
if(row < IM_HEIGHT){
memcpy(IMG_IN + row*IM_WIDTH, in_msg + sizeof(uint32_t), IM_WIDTH*sizeof(pix_t));
adjust_row(row);
}
if(row == IM_HEIGHT-1){
refresh = 1;
}
return NO_ERR;
}
int main (int argc, char** argv){
M_REQUIRE(argc==2,"Invalid usage of client. You should pass the address of the server.\n");
fprintf(stderr, "Starting Caca\n");
M_REQUIRE_NO_ERR(setup_caca(),"Error: Creating Caca\n");
memset(IMG_IN,0,IM_TOTAL*sizeof(pix_t));
M_REQUIRE_NO_ERR(caca_dither_bitmap(cv,0,0,IM_WIDTH,IM_HEIGHT,dither,IMG_IN), "Error: Unable to draw\n");
caca_refresh_display(dp);
fprintf(stderr, "Started CACA HEAT VIEWER successfully\n");
fprintf(stderr, "Starting Network\n");
int32_t s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
M_REQUIRE(s > 0, "Error: Unable to open socket\n");
M_REQUIRE_NO_ERR(bind_server(s, 0), "Error: Unable to bind socket\n");
saddr_t srv_addr;
M_REQUIRE_NO_ERR(get_server_addr(argv[1], DEFAULT_PORT, &srv_addr), "Error: Unable to get server adress\n");
fprintf(stderr, "Started Network\n");
fprintf(stderr, "Sending poke to server...\n");
char e = 0;
M_REQUIRE(sendto(s,&e,0,0,(struct sockaddr *)&srv_addr,sizeof(srv_addr))==0, " Error: Unable to send message to server\n");
fprintf(stderr, "Sent poke successfully\n");
uint8_t quit = 0;
while(!feof(stdin) && !ferror(stdin) && !quit){
caca_event_t ev;
if(caca_get_event(dp, CACA_EVENT_RESIZE | CACA_EVENT_QUIT | CACA_EVENT_KEY_PRESS, &ev, 0)){
if(caca_get_event_type(&ev) == CACA_EVENT_RESIZE){
caca_set_canvas_size(cv,IM_WIDTH,IM_HEIGHT);
}else if(caca_get_event_type(&ev) & CACA_EVENT_QUIT){
quit = 1;
}else {
switch(caca_get_event_key_ch(&ev)){
case 'Q':
case 'q':
quit=1;
break;
default:
break;
}
}
}
uint8_t in_msg[PCKT_SIZE] = {0};
ssize_t in_msg_len = recv(s, in_msg, PCKT_SIZE, 0);
M_REQUIRE_NO_ERR(handle_message(in_msg_len, in_msg), "Error: Couldn't handle message\n");
++msg_cnt;
if (msg_cnt%(IM_HEIGHT/REF_DIV)==0 || refresh){
refresh = 0;
msg_cnt = 0;
M_REQUIRE_NO_ERR(caca_dither_bitmap(cv,0,0,IM_WIDTH,IM_HEIGHT,dither,IMG_IN), "Error: Unable to draw\n");
caca_refresh_display(dp);
}
}
M_REQUIRE(sendto(s,&e,0,0,(struct sockaddr *)&srv_addr,sizeof(srv_addr))==0, " Error: Unable to send message to server\n");
M_REQUIRE_NO_ERR(clear_caca(),"Error: Clearing Caca\n" );
close(s);
return NO_ERR;
}

View File

@@ -0,0 +1,67 @@
#ifndef _ALTERA_HPS_SOC_SYSTEM_H_
#define _ALTERA_HPS_SOC_SYSTEM_H_
/*
* This file was automatically generated by the swinfo2header utility.
*
* Created from SOPC Builder system 'soc_system' in
* file 'hw/quartus/soc_system.sopcinfo'.
*/
/*
* This file contains macros for module 'hps_0' and devices
* connected to the following master:
* h2f_lw_axi_master
*
* Do not include this header file and another header file created for a
* different module or master group at the same time.
* Doing so may result in duplicate macro names.
* Instead, use the system header file which has macros with unique names.
*/
/*
* Macros for device 'lepton_0', class 'lepton'
* The macros are prefixed with 'LEPTON_0_'.
* The prefix is the slave descriptor.
*/
#define LEPTON_0_COMPONENT_TYPE lepton
#define LEPTON_0_COMPONENT_NAME lepton_0
#define LEPTON_0_BASE 0x40000
#define LEPTON_0_SPAN 32768
#define LEPTON_0_END 0x47fff
/*
* Macros for device 'mcp3204_0', class 'mcp3204'
* The macros are prefixed with 'MCP3204_0_'.
* The prefix is the slave descriptor.
*/
#define MCP3204_0_COMPONENT_TYPE mcp3204
#define MCP3204_0_COMPONENT_NAME mcp3204_0
#define MCP3204_0_BASE 0x49000
#define MCP3204_0_SPAN 16
#define MCP3204_0_END 0x4900f
/*
* Macros for device 'pwm_1', class 'pwm'
* The macros are prefixed with 'PWM_1_'.
* The prefix is the slave descriptor.
*/
#define PWM_1_COMPONENT_TYPE pwm
#define PWM_1_COMPONENT_NAME pwm_1
#define PWM_1_BASE 0x49010
#define PWM_1_SPAN 16
#define PWM_1_END 0x4901f
/*
* Macros for device 'pwm_0', class 'pwm'
* The macros are prefixed with 'PWM_0_'.
* The prefix is the slave descriptor.
*/
#define PWM_0_COMPONENT_TYPE pwm
#define PWM_0_COMPONENT_NAME pwm_0
#define PWM_0_BASE 0x49020
#define PWM_0_SPAN 16
#define PWM_0_END 0x4902f
#endif /* _ALTERA_HPS_SOC_SYSTEM_H_ */

View File

@@ -0,0 +1,24 @@
#ifndef __IORW_H__
#define __IORW_H__
#if defined(__nios2_arch__) // For the soft-core Nios processor
#include <io.h>
#define io_write_8(base, ofst, data) (IOWR_8DIRECT((base), (ofst), (data)))
#define io_write_16(base, ofst, data) (IOWR_16DIRECT((base), (ofst), (data)))
#define io_write_32(base, ofst, data) (IOWR_32DIRECT((base), (ofst), (data)))
#define io_read_8(base, ofst) (IORD_8DIRECT((base), (ofst)))
#define io_read_16(base, ofst) (IORD_16DIRECT((base), (ofst)))
#define io_read_32(base, ofst) (IORD_32DIRECT((base), (ofst)))
#else // For the hard-core ARM Cortex A9 processor
#include <socal/socal.h>
#define io_write_8(base, ofst, data) (alt_write_byte((uintptr_t) (base) + (ofst), (data)))
#define io_write_16(base, ofst, data) (alt_write_hword((uintptr_t) (base) + (ofst), (data)))
#define io_write_32(base, ofst, data) (alt_write_word((uintptr_t) (base) + (ofst), (data)))
#define io_read_8(base, ofst) (alt_read_byte((uintptr_t) (base) + (ofst)))
#define io_read_16(base, ofst) (alt_read_hword((uintptr_t) (base) + (ofst)))
#define io_read_32(base, ofst) (alt_read_word((uintptr_t) (base) + (ofst)))
#endif
#endif

View File

@@ -0,0 +1,9 @@
all: app
clean:
rm -rf *.o
rm -f app
server.o: server.c server.h
app.o: app.c server.h
app: app.o server.o

View File

@@ -0,0 +1,125 @@
#include "hps_soc_system.h"
#include "lepton/lepton.h"
#include "server.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <socal/hps.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
/** The port on which the server is available */
#define SERVER_PORT 25700
int main(int argc, char* argv[]) {
// Copy the old terminal configuration to restore it later
struct termios orig_term_attr, new_term_attr;
tcgetattr(fileno(stdin), &orig_term_attr);
memcpy(&new_term_attr, &orig_term_attr, sizeof(struct termios));
// Set the input to non-canonical mode, so that the keypresses are instantaneously recorded
new_term_attr.c_lflag &= ~(ECHO | ICANON);
new_term_attr.c_cc[VTIME] = 0;
new_term_attr.c_cc[VMIN] = 0;
tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);
// Open the physical memory through the filesystem
int mem_fd = open("/dev/mem", O_SYNC | O_RDWR);
if(mem_fd == -1){
fprintf(stderr, "Failed to open /dev/mem. Exiting. Consider running this program with root privileges.\n");
tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr);
return -1;
}
// Map the physical memory into the virtual address space
size_t length = ALT_LWFPGASLVS_UB_ADDR - ALT_LWFPGASLVS_LB_ADDR + 1;
size_t offset = ALT_LWFPGASLVS_OFST;
void* mapped = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, offset);
if (mapped == MAP_FAILED){
fprintf(stderr, "Failed to map physical memory into virtual address space. Exiting.\n");
close(mem_fd);
tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr);
return -1;
}
// Initialize the lepton device with the mapped memory
lepton_dev lepton = lepton_inst(mapped + LEPTON_0_BASE);
lepton_init(&lepton);
// Create the socket
printf("Creating and binding a UDP socket on port %d...\n", SERVER_PORT);
int socket = create_upd_socket(SERVER_PORT);
if (socket == -1) {
fprintf(stderr, "Failed to create the UDP socket. Exiting.\n");
close(mem_fd);
munmap(mapped, length);
tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr);
return EXIT_FAILURE;
}
printf("Socket successfully bound.\n");
printf("Press 'q' to stop the server.\n");
while (1) {
// Wait for a client to connect
printf("Waiting for a new client to connect...\n");
struct sockaddr_in client_addr, sender_addr;
int event;
do {
// Wait for either a packet or the user quiting
event = wait_for_event(socket, &client_addr, -1);
} while (event == NO_EVENT);
if (event == QUIT_EVENT) {
printf("Stopping the server...\n");
munmap(mapped, length);
close(mem_fd);
close(socket);
tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr);
return EXIT_SUCCESS;
}
// Inform the user about the connection
char addr_string[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &client_addr.sin_addr, addr_string, INET_ADDRSTRLEN);
printf("Connected to client at address %s:%d.\n", addr_string, client_addr.sin_port);
// We continuously send the stream to the client until stopping is requested
do {
do {
lepton_start_capture(&lepton);
lepton_wait_until_eof(&lepton);
} while (lepton_error_check(&lepton));
uint16_t* image = lepton_get_image(&lepton, true);
send_image(socket, image, &client_addr);
event = wait_for_event(socket, &sender_addr, 0);
if (event == PACKET_EVENT &&
(sender_addr.sin_addr.s_addr != client_addr.sin_addr.s_addr
|| sender_addr.sin_port != client_addr.sin_port))
event = NO_EVENT;
} while (event == NO_EVENT);
// Stop the server if the user wants to
if (event == QUIT_EVENT) {
printf("Stopping the server...\n");
munmap(mapped, length);
close(mem_fd);
close(socket);
tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr);
return EXIT_SUCCESS;
}
printf("The client disconnected.\n");
}
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,79 @@
#include "joysticks.h"
#define JOYSTICK_RIGHT_VRY_MCP3204_CHANNEL (0)
#define JOYSTICK_RIGHT_VRX_MCP3204_CHANNEL (1)
#define JOYSTICK_LEFT_VRY_MCP3204_CHANNEL (2)
#define JOYSTICK_LEFT_VRX_MCP3204_CHANNEL (3)
/**
* joysticks_inst
*
* Instantiate a joysticks device structure.
*
* @param base Base address of the MCP3204 component connected to the joysticks.
*/
joysticks_dev joysticks_inst(void *mcp3204_base) {
joysticks_dev dev;
dev.mcp3204 = mcp3204_inst((void *) mcp3204_base);
return dev;
}
/**
* joysticks_init
*
* Initializes the joysticks device.
*
* @param dev joysticks device structure.
*/
void joysticks_init(joysticks_dev *dev) {
mcp3204_init(&(dev->mcp3204));
}
/**
* joysticks_read_left_vertical
*
* Returns the vertical position of the left joystick. Return value ranges
* between JOYSTICKS_MIN_VALUE and JOYSTICKS_MAX_VALUE.
*
* @param dev joysticks device structure.
*/
uint32_t joysticks_read_left_vertical(joysticks_dev *dev) {
return JOYSTICKS_MAX_VALUE - mcp3204_read(&dev->mcp3204, JOYSTICK_RIGHT_VRY_MCP3204_CHANNEL);
}
/**
* joysticks_read_left_horizontal
*
* Returns the horizontal position of the left joystick. Return value ranges
* between JOYSTICKS_MIN_VALUE and JOYSTICKS_MAX_VALUE.
*
* @param dev joysticks device structure.
*/
uint32_t joysticks_read_left_horizontal(joysticks_dev *dev) {
return mcp3204_read(&dev->mcp3204, JOYSTICK_LEFT_VRX_MCP3204_CHANNEL);
}
/**
* joysticks_read_right_vertical
*
* Returns the vertical position of the right joystick. Return value ranges
* between JOYSTICKS_MIN_VALUE and JOYSTICKS_MAX_VALUE.
*
* @param dev joysticks device structure.
*/
uint32_t joysticks_read_right_vertical(joysticks_dev *dev) {
return JOYSTICKS_MAX_VALUE - mcp3204_read(&dev->mcp3204, JOYSTICK_RIGHT_VRY_MCP3204_CHANNEL);
}
/**
* joysticks_read_right_horizontal
*
* Returns the horizontal position of the left joystick. Return value ranges
* between JOYSTICKS_MIN_VALUE and JOYSTICKS_MAX_VALUE.
*
* @param dev joysticks device structure.
*/
uint32_t joysticks_read_right_horizontal(joysticks_dev *dev) {
return mcp3204_read(&dev->mcp3204, JOYSTICK_RIGHT_VRX_MCP3204_CHANNEL);
}

View File

@@ -0,0 +1,27 @@
#ifndef __JOYSTICKS_H__
#define __JOYSTICKS_H__
#include "mcp3204/mcp3204.h"
/* joysticks device structure */
typedef struct joysticks_dev {
mcp3204_dev mcp3204; /* MCP3204 device handle */
} joysticks_dev;
/*******************************************************************************
* Public API
******************************************************************************/
#define JOYSTICKS_MIN_VALUE (MCP3204_MIN_VALUE)
#define JOYSTICKS_MAX_VALUE (MCP3204_MAX_VALUE)
joysticks_dev joysticks_inst(void *mcp3204_base);
void joysticks_init(joysticks_dev *dev);
uint32_t joysticks_read_left_vertical(joysticks_dev *dev);
uint32_t joysticks_read_left_horizontal(joysticks_dev *dev);
uint32_t joysticks_read_right_vertical(joysticks_dev *dev);
uint32_t joysticks_read_right_horizontal(joysticks_dev *dev);
#endif /* __JOYSTICKS_H__ */

View File

@@ -0,0 +1,44 @@
#include "mcp3204.h"
#include "iorw.h"
#define MCP3204_NUM_CHANNELS (4)
/**
* mcp3204_inst
*
* Instantiate a mcp3204 device structure.
*
* @param base Base address of the component.
*/
mcp3204_dev mcp3204_inst(void *base) {
mcp3204_dev dev;
dev.base = base;
return dev;
}
/**
* mcp3204_init
*
* Initializes the mcp3204 device.
*
* @param dev mcp3204 device structure.
*/
void mcp3204_init(mcp3204_dev *dev) {
return;
}
/**
* mcp3204_read
*
* Reads the register corresponding to the supplied channel parameter.
*
* @param dev mcp3204 device structure.
* @param channel channel to be read
*/
uint32_t mcp3204_read(mcp3204_dev *dev, uint32_t channel) {
if (channel >= 4)
return 0;
return io_read_32(dev->base, channel * 4);
}

View File

@@ -0,0 +1,23 @@
#ifndef __MCP3204_H__
#define __MCP3204_H__
#include <stdint.h>
/* mcp3204 device structure */
typedef struct mcp3204_dev {
void *base; /* Base address of component */
} mcp3204_dev;
/*******************************************************************************
* Public API
******************************************************************************/
#define MCP3204_MIN_VALUE (0)
#define MCP3204_MAX_VALUE (4095)
mcp3204_dev mcp3204_inst(void *base);
void mcp3204_init(mcp3204_dev *dev);
uint32_t mcp3204_read(mcp3204_dev *dev, uint32_t channel);
#endif /* __MCP3204_H__ */

View File

@@ -0,0 +1,9 @@
#ifndef __MCP3204_REGS_H__
#define __MCP3204_REGS_H__
#define MCP3204_CHANNEL_0_OFST (0 * 4) /* RO */
#define MCP3204_CHANNEL_1_OFST (1 * 4) /* RO */
#define MCP3204_CHANNEL_2_OFST (2 * 4) /* RO */
#define MCP3204_CHANNEL_3_OFST (3 * 4) /* RO */
#endif /* __MCP3204_REGS_H__ */

View File

@@ -0,0 +1,122 @@
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <unistd.h>
#include "lepton_regs.h"
#include "lepton.h"
#include "iorw.h"
/**
* lepton_inst
*
* Instantiate a lepton device structure.
*
* @param base Base address of the component.
*/
lepton_dev lepton_inst(void *base) {
lepton_dev dev;
dev.base = base;
return dev;
}
/**
* lepton_init
*
* Initializes the lepton device.
*
* @param dev lepton device structure.
*/
void lepton_init(lepton_dev *dev) {
return;
}
/**
* lepton_start_capture
*
* Instructs the device to start the frame capture process.
*
* @param dev lepton device structure.
*/
void lepton_start_capture(lepton_dev *dev) {
io_write_16(dev->base, LEPTON_REGS_COMMAND_OFST, 0x1);
}
/**
* lepton_error_check
*
* @abstract Check for errors at the device level.
* @param dev lepton device structure.
* @return true if there was an error, and false otherwise.
*/
bool lepton_error_check(lepton_dev *dev) {
return (io_read_16(dev->base, LEPTON_REGS_STATUS_OFST) & 0x2) != 0;
}
/**
* lepton_wait_until_eof
*
* Waits until the frame being captured has been fully received and saved in the
* internal memory.
*
* @param dev lepton device structure.
*/
void lepton_wait_until_eof(lepton_dev *dev) {
while (io_read_16(dev->base, LEPTON_REGS_STATUS_OFST) & 0x1);
}
/**
* lepton_save_capture
*
* Saves the captured frame on the host filesystem under the supplied filename.
* The frame will be saved in PGM format.
*
* @param dev lepton device structure.
* @param adjusted Setting this parameter to false will cause RAW sensor data to
* be written to the file.
* Setting this parameter to true will cause a preprocessed image
* (with a stretched dynamic range) to be saved to the file.
*
* @param fname the output file name.
*/
void lepton_save_capture(lepton_dev *dev, bool adjusted, FILE* file) {
assert(file);
const uint8_t num_rows = 60;
const uint8_t num_cols = 80;
uint16_t offset = LEPTON_REGS_RAW_BUFFER_OFST;
uint16_t max_value = io_read_16(dev->base, LEPTON_REGS_MAX_OFST);
if (adjusted) {
offset = LEPTON_REGS_ADJUSTED_BUFFER_OFST;
max_value = 0x3fff;
}
/* Write PGM header */
fprintf(file, "P2\n%" PRIu8 " %" PRIu8 "\n%" PRIu16, num_cols, num_rows, max_value);
/* Write body */
uint8_t row = 0;
for (row = 0; row < num_rows; ++row) {
fprintf(file, "\n");
uint8_t col = 0;
for (col = 0; col < num_cols; ++col) {
if (col > 0) {
fprintf(file, " ");
}
uint16_t current_ofst = offset + (row * num_cols + col) * sizeof(uint16_t);
uint16_t pix_value = io_read_16(dev->base, current_ofst);
fprintf(file, "%" PRIu16, pix_value);
}
}
assert(!fclose(file));
}
uint16_t* lepton_get_image(lepton_dev *dev, bool adjusted) {
size_t offset = adjusted ? LEPTON_REGS_ADJUSTED_BUFFER_OFST : LEPTON_REGS_RAW_BUFFER_OFST;
return (uint16_t*) ((uint8_t*) dev->base + offset);
}

View File

@@ -0,0 +1,26 @@
#ifndef __LEPTON_H__
#define __LEPTON_H__
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
/* lepton device structure */
typedef struct {
void *base; /* Base address of the component */
} lepton_dev;
/*******************************************************************************
* Public API
******************************************************************************/
lepton_dev lepton_inst(void *base);
void lepton_init(lepton_dev *dev);
void lepton_start_capture(lepton_dev *dev);
void lepton_wait_until_eof(lepton_dev *dev);
bool lepton_error_check(lepton_dev *dev);
void lepton_save_capture(lepton_dev *dev, bool adjusted, FILE* file);
uint16_t* lepton_get_image(lepton_dev *dev, bool adjusted);
#endif /* __LEPTON_H__ */

View File

@@ -0,0 +1,25 @@
#ifndef __LEPTON_REGS_H__
#define __LEPTON_REGS_H__
/* Register offsets */
#define LEPTON_REGS_COMMAND_OFST ( 0 * 2) /* WO */
#define LEPTON_REGS_STATUS_OFST ( 1 * 2) /* RO */
#define LEPTON_REGS_MIN_OFST ( 2 * 2) /* RO */
#define LEPTON_REGS_MAX_OFST ( 3 * 2) /* RO */
#define LEPTON_REGS_SUM_LSB_OFST ( 4 * 2) /* RO */
#define LEPTON_REGS_SUM_MSB_OFST ( 5 * 2) /* RO */
#define LEPTON_REGS_ROW_IDX_OFST ( 6 * 2) /* RO */
#define LEPTON_REGS_RAW_BUFFER_OFST ( 8 * 2) /* RO */
#define LEPTON_REGS_ADJUSTED_BUFFER_OFST (8192 * 2) /* RO */
/* Command register */
#define LEPTON_COMMAND_START (0x0001)
/* Status register */
#define LEPTON_STATUS_CAPTURE_IN_PROGRESS_MASK (1 << 0)
#define LEPTON_STATUS_ERROR_MASK (1 << 1)
#define LEPTON_REGS_BUFFER_NUM_PIXELS (80 * 60)
#define LEPTON_REGS_BUFFER_BYTELENGTH (LEPTON_REGS_BUFFER_NUM_PIXELS * 2)
#endif /* __LEPTON_REGS_H__ */

View File

@@ -0,0 +1,109 @@
#include "pantilt.h"
/**
* pantilt_inst
*
* Instantiate a pantilt device structure.
*
* @param pwm_v_base Base address of the vertical PWM component.
* @param pwm_h_base Base address of the horizontal PWM component.
*/
pantilt_dev pantilt_inst(void *pwm_v_base, void *pwm_h_base) {
pantilt_dev dev;
dev.pwm_v = pwm_inst(pwm_v_base);
dev.pwm_h = pwm_inst(pwm_h_base);
return dev;
}
/**
* pantilt_init
*
* Initializes the pantilt device.
*
* @param dev pantilt device structure.
*/
void pantilt_init(pantilt_dev *dev) {
pwm_init(&(dev->pwm_v));
pwm_init(&(dev->pwm_h));
}
/**
* pantilt_configure_vertical
*
* Configure the vertical PWM component.
*
* @param dev pantilt device structure.
* @param duty_cycle pwm duty cycle in us.
*/
void pantilt_configure_vertical(pantilt_dev *dev, uint32_t duty_cycle) {
// Need to compensate for inverted servo rotation.
duty_cycle = PANTILT_PWM_V_MAX_DUTY_CYCLE_US - duty_cycle + PANTILT_PWM_V_MIN_DUTY_CYCLE_US;
pwm_configure(&(dev->pwm_v),
duty_cycle,
PANTILT_PWM_PERIOD_US,
PANTILT_PWM_CLOCK_FREQ_HZ);
}
/**
* pantilt_configure_horizontal
*
* Configure the horizontal PWM component.
*
* @param dev pantilt device structure.
* @param duty_cycle pwm duty cycle in us.
*/
void pantilt_configure_horizontal(pantilt_dev *dev, uint32_t duty_cycle) {
// Need to compensate for inverted servo rotation.
duty_cycle = PANTILT_PWM_H_MAX_DUTY_CYCLE_US - duty_cycle + PANTILT_PWM_H_MIN_DUTY_CYCLE_US;
pwm_configure(&(dev->pwm_h),
duty_cycle,
PANTILT_PWM_PERIOD_US,
PANTILT_PWM_CLOCK_FREQ_HZ);
}
/**
* pantilt_start_vertical
*
* Starts the vertical pwm controller.
*
* @param dev pantilt device structure.
*/
void pantilt_start_vertical(pantilt_dev *dev) {
pwm_start(&(dev->pwm_v));
}
/**
* pantilt_start_horizontal
*
* Starts the horizontal pwm controller.
*
* @param dev pantilt device structure.
*/
void pantilt_start_horizontal(pantilt_dev *dev) {
pwm_start(&(dev->pwm_h));
}
/**
* pantilt_stop_vertical
*
* Stops the vertical pwm controller.
*
* @param dev pantilt device structure.
*/
void pantilt_stop_vertical(pantilt_dev *dev) {
pwm_stop(&(dev->pwm_v));
}
/**
* pantilt_stop_horizontal
*
* Stops the horizontal pwm controller.
*
* @param dev pantilt device structure.
*/
void pantilt_stop_horizontal(pantilt_dev *dev) {
pwm_stop(&(dev->pwm_h));
}

View File

@@ -0,0 +1,39 @@
#ifndef __PANTILT_H__
#define __PANTILT_H__
#include "pwm/pwm.h"
/* joysticks device structure */
typedef struct pantilt_dev {
pwm_dev pwm_v; /* Vertical PWM device handle */
pwm_dev pwm_h; /* Horizontal PWM device handle */
} pantilt_dev;
/*******************************************************************************
* Public API
******************************************************************************/
#define PANTILT_PWM_CLOCK_FREQ_HZ (50000000) // 50.00 MHz
#define PANTILT_PWM_PERIOD_US (25000) // 25.00 ms
/* Vertical servo */
#define PANTILT_PWM_V_MIN_DUTY_CYCLE_US (950) // 0.95 ms
#define PANTILT_PWM_V_MAX_DUTY_CYCLE_US (2150) // 2.15 ms
/* Horizontal servo */
#define PANTILT_PWM_H_MIN_DUTY_CYCLE_US (1000) // 1.00 ms
#define PANTILT_PWM_H_MAX_DUTY_CYCLE_US (2000) // 2.00 ms
pantilt_dev pantilt_inst(void *pwm_v_base, void *pwm_h_base);
void pantilt_init(pantilt_dev *dev);
void pantilt_configure_vertical(pantilt_dev *dev, uint32_t duty_cycle);
void pantilt_configure_horizontal(pantilt_dev *dev, uint32_t duty_cycle);
void pantilt_start_vertical(pantilt_dev *dev);
void pantilt_start_horizontal(pantilt_dev *dev);
void pantilt_stop_vertical(pantilt_dev *dev);
void pantilt_stop_horizontal(pantilt_dev *dev);
#endif /* __PANTILT_H__ */

View File

@@ -0,0 +1,68 @@
#include "pwm.h"
#include "pwm_regs.h"
#include "iorw.h"
#define MICROSEC_TO_CLK(time, freq) ((time) * ((freq) / 1000000))
/**
* pwm_inst
*
* Instantiate a pwm device structure.
*
* @param base Base address of the component.
*/
pwm_dev pwm_inst(void *base) {
pwm_dev dev;
dev.base = base;
return dev;
}
/**
* pwm_init
*
* Initializes the pwm device. This function stops the controller.
*
* @param dev pwm device structure.
*/
void pwm_init(pwm_dev *dev) {
pwm_stop(dev);
}
/**
* pwm_configure
*
* Configure pwm component.
*
* @param dev pwm device structure.
* @param duty_cycle pwm duty cycle in us.
* @param period pwm period in us.
* @param module_frequency frequency at which the component is clocked.
*/
void pwm_configure(pwm_dev *dev, uint32_t duty_cycle, uint32_t period, uint32_t module_frequency) {
io_write_32(dev->base, PWM_PERIOD_OFST, MICROSEC_TO_CLK(period, module_frequency));
io_write_32(dev->base, PWM_DUTY_CYCLE_OFST, MICROSEC_TO_CLK(duty_cycle, module_frequency));
}
/**
* pwm_start
*
* Starts the pwm controller.
*
* @param dev pwm device structure.
*/
void pwm_start(pwm_dev *dev) {
io_write_32(dev->base, PWM_CTRL_OFST, PWM_CTRL_START_MASK);
}
/**
* pwm_stop
*
* Stops the pwm controller.
*
* @param dev pwm device structure.
*/
void pwm_stop(pwm_dev *dev) {
io_write_32(dev->base, PWM_CTRL_OFST, PWM_CTRL_START_MASK);
}

View File

@@ -0,0 +1,21 @@
#ifndef __PWM_H__
#define __PWM_H__
#include <stdint.h>
/* pwm device structure */
typedef struct pwm_dev {
void *base; /* Base address of component */
} pwm_dev;
/*******************************************************************************
* Public API
******************************************************************************/
pwm_dev pwm_inst(void *base);
void pwm_init(pwm_dev *dev);
void pwm_configure(pwm_dev *dev, uint32_t duty_cycle, uint32_t period, uint32_t module_frequency);
void pwm_start(pwm_dev *dev);
void pwm_stop(pwm_dev *dev);
#endif /* __PWM_H__ */

View File

@@ -0,0 +1,11 @@
#ifndef __PWM_REGS_H__
#define __PWM_REGS_H__
#define PWM_PERIOD_OFST (0 * 4) /* RW */
#define PWM_DUTY_CYCLE_OFST (1 * 4) /* RW */
#define PWM_CTRL_OFST (2 * 4) /* WO */
#define PWM_CTRL_STOP_MASK (0)
#define PWM_CTRL_START_MASK (1)
#endif /* __PWM_REGS_H__ */

View File

@@ -0,0 +1,79 @@
#include "server.h"
#include <sys/socket.h> // for socket
#include <sys/types.h> // for AF_INET
#include <netinet/in.h> // for sockaddr_in
#include <arpa/inet.h> // for htonl
#include <stdint.h> // for uint16_t
#include <unistd.h> // for close
#include <string.h> // for memcpy
#include <poll.h> // for poll
#define ROW_SIZE (IMG_WIDTH * sizeof(uint16_t))
int create_upd_socket(uint16_t port) {
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == -1)
return -1;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock, (const struct sockaddr*) &addr, sizeof(addr))) {
close(sock);
return -1;
}
return sock;
}
int wait_for_event(int socket, struct sockaddr_in* addr, int timeout) {
char c = 0;
struct pollfd fds[2];
// Wait for a packet
fds[0].fd = socket;
fds[0].events = POLLIN;
fds[0].revents = 0;
// Wait for a command line input
fds[1].fd = STDIN_FILENO;
fds[1].events = POLLIN;
fds[1].revents = 0;
// Wait for the two file descriptors in parallel
int ret = poll(fds, 2, timeout);
if (ret <= 0) // error or timeout
return NO_EVENT;
if (fds[1].revents & POLLIN) {
read(STDIN_FILENO, &c, 1);
if (c == 'q')
return QUIT_EVENT;
}
if (fds[0].revents & POLLIN) {
socklen_t addr_len = sizeof(struct sockaddr_in);
recvfrom(socket, &c, 1, 0, (struct sockaddr*) addr, &addr_len);
return PACKET_EVENT;
}
return NO_EVENT;
}
void send_image(int socket, uint16_t* img, const struct sockaddr_in* addr) {
// This buffer is used to hold the packet for a row
char row_buffer[sizeof(uint32_t) + ROW_SIZE];
// We send the rows one by one
uint8_t i = 0;
for (i = 0; i < IMG_HEIGHT; i++) {
*((uint32_t*) row_buffer) = i; // The first bytes of the packet contain the row index
memcpy(row_buffer + sizeof(uint32_t), img + i * IMG_WIDTH, ROW_SIZE); // The rest contains the actual row
sendto(socket, row_buffer, sizeof(uint32_t) + ROW_SIZE, 0, (const struct sockaddr*) addr, sizeof(*addr));
}
}

View File

@@ -0,0 +1,32 @@
#ifndef __SERVER_H__
#define __SERVER_H__
#include <netinet/in.h>
#include <stdint.h>
/** Image definitions - needs to move to another file later */
#define IMG_WIDTH 80
#define IMG_HEIGHT 60
#define IMG_SIZE (IMG_WIDTH * IMG_HEIGHT)
/**
* Creates and binds a socket on the given port, using the UDP protocol.
* If an error occured, -1 is returned, otherwise the socket is returned.
*/
int create_upd_socket(in_port_t port);
/**
* Polls the given socket for a message, and check if the user wants to quit by pressing q
* in the console. Returns what happened in the form of an integer.
*/
#define NO_EVENT 0
#define QUIT_EVENT 1
#define PACKET_EVENT 2
int wait_for_event(int socket, struct sockaddr_in* addr, int timeout);
/**
* Sends the entire image over udp, row by row, through the given socket.
*/
void send_image(int socket, uint16_t* img, const struct sockaddr_in* addr);
#endif

View File

@@ -0,0 +1,9 @@
all: app
clean:
rm -rf *.o
rm -f app
server.o: server.c server.h
app.o: app.c server.h
app: app.o server.o

View File

@@ -0,0 +1,94 @@
#include "server.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <termios.h>
/** The port on which the server is available */
#define SERVER_PORT 25700
// Creates a moving fake image
void generate_image(uint16_t* img, size_t t);
int main(int argc, char* argv[]) {
// Set the input to non-canonical mode, so that the keypresses are instantaneously recorded
struct termios term_attr;
tcgetattr(fileno(stdin), &term_attr);
term_attr.c_lflag &= ~(ECHO | ICANON);
term_attr.c_cc[VTIME] = 0;
term_attr.c_cc[VMIN] = 0;
tcsetattr(fileno(stdin), TCSANOW, &term_attr);
// This is the image that will be sent
uint16_t img[IMG_WIDTH * IMG_HEIGHT];
size_t t = 0;
// Create the socket
printf("Creating and binding a UDP socket on port %d...\n", SERVER_PORT);
int socket = create_upd_socket(SERVER_PORT);
if (socket == -1) {
fprintf(stderr, "Failed to create the UDP socket. Exiting.\n");
return EXIT_FAILURE;
}
printf("Socket successfully bound.\n");
printf("Press 'q' to stop the server.\n");
while (1) {
// Wait for a client to connect
printf("Waiting for a new client to connect...\n");
struct sockaddr_in client_addr, sender_addr;
int event;
do {
// Wait for either a packet or the user quiting
event = wait_for_event(socket, &client_addr, -1);
} while (event == NO_EVENT);
if (event == QUIT_EVENT) {
printf("Stopping the server...\n");
close(socket);
return EXIT_SUCCESS;
}
// Inform the user about the connection
char addr_string[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &client_addr.sin_addr, addr_string, INET_ADDRSTRLEN);
printf("Connected to client at address %s:%d.\n", addr_string, client_addr.sin_port);
// We continuously send the stream to the client until stopping is requested
do {
generate_image(img, t++);
send_image(socket, img, &client_addr);
event = wait_for_event(socket, &sender_addr, 100);
if (event == PACKET_EVENT &&
(sender_addr.sin_addr.s_addr != client_addr.sin_addr.s_addr
|| sender_addr.sin_port != client_addr.sin_port))
event = NO_EVENT;
} while (event == NO_EVENT);
// Stop the server if the user wants to
if (event == QUIT_EVENT) {
printf("Stopping the server...\n");
close(socket);
return EXIT_SUCCESS;
}
printf("The client disconnected.\n");
}
return EXIT_SUCCESS;
}
void generate_image(uint16_t* img, size_t t) {
for (size_t x = 0; x < IMG_WIDTH; x++) {
uint16_t val = ((x + t) % IMG_WIDTH) * 0x3FFF / IMG_WIDTH;
for (size_t y = 0; y < IMG_HEIGHT; y++)
img[y * IMG_WIDTH + x] = val;
}
}

View File

@@ -0,0 +1,79 @@
#include "server.h"
#include <sys/socket.h> // for socket
#include <sys/types.h> // for AF_INET
#include <netinet/in.h> // for sockaddr_in
#include <arpa/inet.h> // for htonl
#include <stdint.h> // for uint16_t
#include <unistd.h> // for close
#include <string.h> // for memcpy
#include <poll.h> // for poll
#define ROW_SIZE (IMG_WIDTH * sizeof(uint16_t))
int create_upd_socket(uint16_t port) {
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == -1)
return -1;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock, (const struct sockaddr*) &addr, sizeof(addr))) {
close(sock);
return -1;
}
return sock;
}
int wait_for_event(int socket, struct sockaddr_in* addr, int timeout) {
char c = 0;
struct pollfd fds[2];
// Wait for a packet
fds[0].fd = socket;
fds[0].events = POLLIN;
fds[0].revents = 0;
// Wait for a command line input
fds[1].fd = STDIN_FILENO;
fds[1].events = POLLIN;
fds[1].revents = 0;
// Wait for the two file descriptors in parallel
int ret = poll(fds, 2, timeout);
if (ret <= 0) // error or timeout
return NO_EVENT;
if (fds[1].revents & POLLIN) {
read(STDIN_FILENO, &c, 1);
if (c == 'q')
return QUIT_EVENT;
}
if (fds[0].revents & POLLIN) {
socklen_t addr_len = sizeof(struct sockaddr_in);
recvfrom(socket, &c, 1, 0, (struct sockaddr*) addr, &addr_len);
return PACKET_EVENT;
}
return NO_EVENT;
}
void send_image(int socket, uint16_t* img, const struct sockaddr_in* addr) {
// This buffer is used to hold the packet for a row
char row_buffer[sizeof(uint32_t) + ROW_SIZE];
// We send the rows one by one
uint8_t i = 0;
for (i = 0; i < IMG_HEIGHT; i++) {
*((uint32_t*) row_buffer) = i; // The first bytes of the packet contain the row index
memcpy(row_buffer + sizeof(uint32_t), img + i * IMG_WIDTH, ROW_SIZE); // The rest contains the actual row
sendto(socket, row_buffer, sizeof(uint32_t) + ROW_SIZE, 0, (const struct sockaddr*) addr, sizeof(*addr));
}
}

View File

@@ -0,0 +1,32 @@
#ifndef __SERVER_H__
#define __SERVER_H__
#include <netinet/in.h>
#include <stdint.h>
/** Image definitions - needs to move to another file later */
#define IMG_WIDTH 80
#define IMG_HEIGHT 60
#define IMG_SIZE (IMG_WIDTH * IMG_HEIGHT)
/**
* Creates and binds a socket on the given port, using the UDP protocol.
* If an error occured, -1 is returned, otherwise the socket is returned.
*/
int create_upd_socket(in_port_t port);
/**
* Polls the given socket for a message, and check if the user wants to quit by pressing q
* in the console. Returns what happened in the form of an integer.
*/
#define NO_EVENT 0
#define QUIT_EVENT 1
#define PACKET_EVENT 2
int wait_for_event(int socket, struct sockaddr_in* addr, int timeout);
/**
* Sends the entire image over udp, row by row, through the given socket.
*/
void send_image(int socket, uint16_t* img, const struct sockaddr_in* addr);
#endif