aboutsummaryrefslogtreecommitdiff
path: root/interface.c
blob: 79510c9ffc2ada39c2c91fff9bb7aea98dc77b3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/*
 *
 * Copyright (C) 2022 Jeremias Stotter <jeremias@stotter.eu>
 *
 * This file is part of network-simulator.
 *
 * network-simulator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * network-simulator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with network-simulator. If not, see <https://www.gnu.org/licenses/>. 
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

#include "shared.h"
#include "template.h"
#include "lua_functions.h"
#include "device.h"
#include "connection.h"
#include "gui.h"
#include "interface.h"
#include "helpers.h"

void setup_interface_functions(lua_State *lua_vm);

// Insert a new interface into device parent_device at slot slot_index
int delete_interface(struct interface* del_interface) {
	if(!del_interface->parent_device) return 1;
	delete_connection(del_interface->connection);
	
	if(del_interface->lua_vm) lua_close(del_interface->lua_vm);
	memset(del_interface, 0, sizeof(struct interface));
	return 0;
}

int new_interface_from_template_name(struct device* parent_device, int slot_index, const char* template_name) {
	struct interface_template* cur_template = interface_templates;
	bool template_found = false;
	for(int i = 0; i < interface_template_n; i++, cur_template = &interface_templates[i]) {
		if(strcmp(cur_template->name, template_name) == 0) {
			template_found = true;
			break;
		}
	}

	if(!template_found) {
		fprintf(stderr, "Template %s was not found", template_name);
		return -1;
	}
	
	return new_interface(parent_device, slot_index, cur_template);
}

int new_interface(struct device* parent_device, int slot_index, struct interface_template* cur_template) {
	if(!parent_device) return -1;
	if(slot_index > parent_device->template->slots - 1) {
		fprintf(stderr, "Slot %d is not available in device %s with %d slots", slot_index, parent_device->name, parent_device->template->slots);
		return -1;
	}

	if(!cur_template) {
		fprintf(stderr, "Invalid interface template\n");
		return -1;
	}
	
	// Remove any old interfaces still there
	delete_interface(&parent_device->interfaces[slot_index]);

	struct interface* new_interface = &(parent_device->interfaces[slot_index]);

	new_interface->parent_device = parent_device;
	new_interface->parent_index = slot_index;
	new_interface->template = cur_template;
	new_interface->connection = NULL;
	new_interface->start_queue = NULL;
	// initiate the firmware for this device
	lua_State *lua_vm = luaL_newstate();
	register_lua_helpers(lua_vm);
	setup_interface_functions(lua_vm);
	luaL_openlibs(lua_vm);
	if(luaL_dofile(lua_vm, new_interface->template->firmware) != 0) {
		printf("LUA ERROR: %s\n", lua_tostring(lua_vm, -1));
	}

	new_interface->lua_vm = lua_vm;

	return 0;
}

// This function gets called by the device wehn we have a frame to send
int interface_send_frame(struct interface* send_interface, const char* frame, int frame_len, const char* frame_type) {
	// If this device doesn't exist or has no lua vm don't do anything
	if(!send_interface->lua_vm) return -1;

	if(!my_lua_call(send_interface->lua_vm, "send_frame", 1, LUA_TSTRING, frame_len, frame,
					LUA_TNUMBER, frame_len,
					LUA_TSTRING, strlen(frame_type), frame_type, -1))
		return -1;
	
	// Get the result
	return lua_tointeger(send_interface->lua_vm, -1);
}

struct interface* interface_from_luaptr(const struct lua_State* lua_vm) {
	// Iterate through all devices
	LL_FOR(struct device, start_device, test_device) {
		for(int i = 0; i < test_device->template->slots; i++) {
			if(test_device->interfaces[i].lua_vm == lua_vm)
				return (&test_device->interfaces[i]);
		}
	}
	return NULL;
}

// This will get called by the interface to send data through a connection
int interface_send_data(lua_State* lua_vm) {
	// Get the sending interface from the lua_state
	struct interface* sending_interface = interface_from_luaptr(lua_vm);
	// Don't even bother sending if the interface is not connected
	if(!sending_interface->connection) {
		return -1;
	}
	int largc = lua_gettop(lua_vm);
	if(largc != 3) {
		lua_pushliteral(lua_vm, "Wrong amount of arguments passed to the send_data function");
		lua_error(lua_vm);
		return -1;
	}

	const char* send_data = lua_tostring(lua_vm, 1);
	int data_length = lua_tointeger(lua_vm, 2);
	const char* data_type = lua_tostring(lua_vm, 3);
	
	// Add the sending frame to the queue
	// Search to the end of the queue
	struct send_queue_entry* new_entry = malloc_or_abort(sizeof(struct send_queue_entry));
	struct send_queue_entry* last_entry;
	LL_LAST(sending_interface->start_queue, last_entry);
	if(!last_entry)
		sending_interface->start_queue = new_entry;
	else
		last_entry->next = new_entry;
	// Send on the next timestep
	new_entry->parent_interface = sending_interface;
	new_entry->data = send_data;
	new_entry->data_length = data_length;
	new_entry->next = NULL;
	new_entry->timestamp = timestamp;
	snprintf(new_entry->data_type, sizeof(new_entry->data_type), "%s", data_type);
	// The color will be computed by taking the type string and turning it into the 3 components
	// Kinda shit but it is what it is...
	for(int i = 0; i < 3; i++) {
		int component = 0;
		for(char* c = (char*)data_type; *c != 0; c++) {
			component += *c;
		}
		component %= 100 + i;
		new_entry->color[i] = (double)component / (double)(90+i);
	}
	new_entry->gui_index = gui_send_info(sending_interface, send_data, data_length, data_type);
	/*
	// Tell the connection to queue sending, the data will then get send with the next logical step
	// Connection side is the side of the connection that is sending the data
	// It is either 1 for interface1 or 2 for interface2 in the connection
	connection_send(send_connection, connection_side, send_data, data_length);
	*/
	return 0;
}

// This gets called by an interface to send data to its device
int recv_device(lua_State* lua_vm) {
	struct interface* recv_interface = interface_from_luaptr(lua_vm);
	if(!recv_interface) {
		fprintf(stderr, "Couldn't find the interface that called recv_device'");
		return -1;
	}
	int largc = lua_gettop(lua_vm);
	if(largc != 3) {
		lua_pushliteral(lua_vm, "Wrong amount of arguments passed to recv_device");
		lua_error(lua_vm);
		return -1;
	}
	const char* data = lua_tostring(lua_vm, 1);
	int data_length = lua_tointeger(lua_vm, 2);
	const char* data_type = lua_tostring(lua_vm, 3);
	
	// call the parent device
	struct device* receiving_device = recv_interface->parent_device;

	if(!my_lua_call(receiving_device->lua_vm, "recv_frame", 1, LUA_TNUMBER, recv_interface->parent_index,
					LUA_TSTRING, data_length, data,
					LUA_TNUMBER, data_length,
					LUA_TSTRING, strlen(data_type), data_type, -1)) return -1;
	
	int result = lua_tointeger(receiving_device->lua_vm, -1);
	lua_pushinteger(recv_interface->lua_vm, result);
	return 0;
}

void setup_interface_functions(lua_State *lua_vm) {
	lua_register(lua_vm, "send_data", interface_send_data);
	lua_register(lua_vm, "recv_device", recv_device);
}

// This function gets called by a connection to the interface it has data
int interface_recv_data(struct interface* recv_interface, const char* data, int data_length, const char* data_type) {
	if(!my_lua_call(recv_interface->lua_vm, "recv_data", 1, LUA_TSTRING, data_length, data,
					LUA_TNUMBER, data_length,
					LUA_TSTRING, strlen(data_type), data_type, -1)) return -1;
	// Get the result
	return lua_tointeger(recv_interface->lua_vm, -1);
}
Jeremias Stotters git repositories generated by CGIT