уторак, 20. август 2024.

WiFi autić na daljinbsko upravljanje GUI app

Već duže vrijeme sakupljam kako stvari/djelove tako i programe/alate za realizaciju jednog skromnog projekta. Veliki sam poštovaoc softwarea pod GPL licencom tako da će i ovaj moj projekat biti dostupan pod uslovima koji su navedeni u GPL licenci. Dakle želim da napravim RC autić na kom će da se nalazi ruter koji je flešovan sa OperWrt/LEDE firmwareom i na kom će da bude prikopčana IP kamera čiji stream možete da gledate u web pretraživaču u realnom vremenu. Takođe na lap-topu će da se nalazi mala GUI aplikacija napisana u C/GTK-u momoću koje će mo da upravljamo RC autićem. Server koji će da se nalazi na ruteru možete da pogledate u mom predhodom postu Kako dodati aplikaciju u OpenWrt-u pa ću u ovom postu samo objaviti kod GUI aplikacije koja će da se nalazi na lap-top računaru 

 



#include 
#include 
#include 
#include 
#include 

GtkWidget *button_l;
GtkWidget *button_r;
GtkWidget *button_up;
GtkWidget *connect_button;
GtkWidget *label1;
GtkWidget *ip_entry;
gboolean left_arrow_pressed = FALSE;
gboolean right_arrow_pressed = FALSE;
gboolean up_arrow_pressed = FALSE;
guint key_check_timer = 0;

int sock = -1;
pthread_t recv_thread;

void *recv_thread_func(void *arg) {
    char buffer[1024] = {0};
    while (1) {
        int valread = read(sock, buffer, 1024);
        if (valread > 0) {
            buffer[valread] = '\0';
            gdk_threads_add_idle((GSourceFunc)gtk_label_set_text, label1);
            gdk_threads_add_idle((GSourceFunc)g_strdup_printf, g_strdup(buffer));
        } else {
            break;
        }
    }
    return NULL;
}

void send_message(const char *message) {
    if (sock != -1) {
        send(sock, message, strlen(message), 0);
    }
}

void set_button_icon(GtkWidget *button, const gchar *icon_name) {
    GdkPixbuf *icon = gdk_pixbuf_new_from_file(icon_name, NULL);
    if (icon == NULL) {
        g_printerr("Error loading image: %s\n", icon_name);
        return;
    }
    GtkWidget *current_image_widget = gtk_button_get_image(GTK_BUTTON(button));
    GtkWidget *new_image = gtk_image_new_from_pixbuf(icon);
    gtk_button_set_image(GTK_BUTTON(button), new_image);
    g_object_unref(icon);
    if (current_image_widget != NULL && GTK_IS_IMAGE(current_image_widget)) {
        GdkPixbuf *current_pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(current_image_widget));
        if (current_pixbuf != NULL && G_IS_OBJECT(current_pixbuf)) {
            g_object_unref(current_pixbuf);
        }
    }
}

gboolean check_key_states(gpointer user_data) {
    if (left_arrow_pressed) {
        send_message("left");
        g_print("Left arrow key held down.\n");
    }
    if (right_arrow_pressed) {
        send_message("right");
        g_print("Right arrow key held down.\n");
    }
    if (up_arrow_pressed) {
        send_message("up");
        g_print("Up arrow key held down.\n");
    }
    return TRUE;
}

gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
    if (event->keyval == GDK_KEY_Left) {
        if (!left_arrow_pressed) {
            left_arrow_pressed = TRUE;
            g_print("Left arrow key pressed.\n");
            set_button_icon(button_l, "pressed_icon_l.png");
        }
        return TRUE;
    } else if (event->keyval == GDK_KEY_Right) {
        if (!right_arrow_pressed) {
            right_arrow_pressed = TRUE;
            g_print("Right arrow key pressed.\n");
            set_button_icon(button_r, "pressed_icon_r.png");
        }
        return TRUE;
    } else if (event->keyval == GDK_KEY_Up) {
        if (!up_arrow_pressed) {
            up_arrow_pressed = TRUE;
            g_print("Up arrow key pressed.\n");
            set_button_icon(button_up, "pressed_icon_up.png");
        }
        return TRUE;
    }
    return FALSE;
}

gboolean on_key_release(GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
    if (event->keyval == GDK_KEY_Left) {
        left_arrow_pressed = FALSE;
        set_button_icon(button_l, "initial_icon_l.png");
        return TRUE;
    } else if (event->keyval == GDK_KEY_Right) {
        right_arrow_pressed = FALSE;
        set_button_icon(button_r, "initial_icon_r.png");
        return TRUE;
    } else if (event->keyval == GDK_KEY_Up) {
        up_arrow_pressed = FALSE;
        set_button_icon(button_up, "initial_icon_up.png");
        return TRUE;
    }
    return FALSE;
}

void set_label_color(GtkWidget *label, const gchar *color) {
    GtkCssProvider *provider = gtk_css_provider_new();
    gchar *css = g_strdup_printf("label { color: %s; }", color);
    gtk_css_provider_load_from_data(provider, css, -1, NULL);
    GtkStyleContext *context = gtk_widget_get_style_context(label);
    gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
    g_free(css);
    g_object_unref(provider);
}

void on_connect_button_clicked(GtkWidget *widget, gpointer user_data) {
    if (sock == -1) {
        const gchar *ip_address = gtk_entry_get_text(GTK_ENTRY(ip_entry));
        struct sockaddr_in serv_addr;
        fd_set fdset;
        struct timeval tv;
        int flags, res, valopt;
        socklen_t lon;

        if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            g_printerr("Socket creation error\n");
            return;
        }

        flags = fcntl(sock, F_GETFL, 0);
        fcntl(sock, F_SETFL, flags | O_NONBLOCK);

        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(5555);

        if (inet_pton(AF_INET, ip_address, &serv_addr.sin_addr) <= 0) {
            g_printerr("Invalid address/ Address not supported\n");
            return;
        }

        res = connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
        if (res < 0) {
            if (errno == EINPROGRESS) {
                FD_ZERO(&fdset);
                FD_SET(sock, &fdset);
                tv.tv_sec = 5; // 5 seconds timeout
                tv.tv_usec = 0;

                res = select(sock + 1, NULL, &fdset, NULL, &tv);
                if (res < 0 && errno != EINTR) {
                    g_printerr("Select error\n");
                    close(sock);
                    sock = -1;
                    return;
                } else if (res > 0) {
                    lon = sizeof(int);
                    if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon) < 0) {
                        g_printerr("getsockopt error\n");
                        close(sock);
                        sock = -1;
                        return;
                    }
                    if (valopt) {
                        g_printerr("Connection error: %d - %s\n", valopt, strerror(valopt));
                        close(sock);
                        sock = -1;
                        gtk_label_set_text(GTK_LABEL(label1), "Server not found");
                        set_label_color(label1, "red");
                        return;
                    }
                } else {
                    g_printerr("Connection timed out\n");
                    close(sock);
                    sock = -1;
                    gtk_label_set_text(GTK_LABEL(label1), "Server not found");
                    set_label_color(label1, "red");
                    return;
                }
            } else {
                g_printerr("Connection error\n");
                close(sock);
                sock = -1;
                return;
            }
        }

        fcntl(sock, F_SETFL, flags); // Set back to blocking mode

        gtk_button_set_label(GTK_BUTTON(connect_button), "Disconnect");
        gtk_label_set_text(GTK_LABEL(label1), "Connected");
        set_label_color(label1, "green");

        send_message("HI");

        if (pthread_create(&recv_thread, NULL, recv_thread_func, NULL) != 0) {
            g_printerr("Failed to create receive thread\n");
        }
    } else {
        close(sock);
        sock = -1;
        gtk_button_set_label(GTK_BUTTON(connect_button), "Connect");
        gtk_label_set_text(GTK_LABEL(label1), "Disconnected");
        set_label_color(label1, "red");
        pthread_cancel(recv_thread);
    }
}

int main(int argc, char *argv[]) {
    GtkBuilder *builder;
    GtkWidget *window;

    gtk_init(&argc, &argv);

    builder = gtk_builder_new();
    gtk_builder_add_from_file(builder, "GladeUI_3.glade", NULL);
    gtk_builder_connect_signals(builder, NULL);

    window = GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
    button_l = GTK_WIDGET(gtk_builder_get_object(builder, "button_l"));
    button_r = GTK_WIDGET(gtk_builder_get_object(builder, "button_r"));
    button_up = GTK_WIDGET(gtk_builder_get_object(builder, "button_up"));
    connect_button = GTK_WIDGET(gtk_builder_get_object(builder, "connect"));
    label1 = GTK_WIDGET(gtk_builder_get_object(builder, "label1"));
    ip_entry = GTK_WIDGET(gtk_builder_get_object(builder, "ip_adress"));

    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    gtk_window_set_default_size(GTK_WINDOW(window), 600, 500);

    set_button_icon(button_l, "initial_icon_l.png");
    set_button_icon(button_r, "initial_icon_r.png");
    set_button_icon(button_up, "initial_icon_up.png");

    g_signal_connect(window, "key-press-event", G_CALLBACK(on_key_press), NULL);
    g_signal_connect(window, "key-release-event", G_CALLBACK(on_key_release), NULL);
    g_signal_connect(connect_button, "clicked", G_CALLBACK(on_connect_button_clicked), NULL);

    key_check_timer = g_timeout_add(100, check_key_states, NULL);

    gtk_widget_show(window);
    gtk_main();

    g_object_unref(builder);

    if (sock != -1) {
        close(sock);
    }

    return 0;
}
Sledeći kod je iz GUI builder koji se zove Glade, samo ga sačuvajte pod imenom
GladeUI_3.glade
I da olakšamo sebi život tu je i Makefile
PROG = gtk_tcp_client_with_timeout
CC = gcc
CFLAGS = `pkg-config --cflags gtk+-3.0`
LIBS = `pkg-config --libs gtk+-3.0`
${PROG}: ${PROG}.c
		${CC} $(CFLAGS) -o ${PROG}  ${PROG}.c ${LIBS} -export-dynamic -rdynamic 
clean:
		rm ${PROG}
I tu je 6 sličica koje grafički prikazuju da je strelica pritisnuta

Нема коментара:

Постави коментар