Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / colonet / server / colonet_wireless.cpp @ 629

History | View | Annotate | Download (10.6 KB)

1
/** @file colonet_wireless.c
2
 *
3
 * @brief Implementation of server-side colonet wireless library
4
 *
5
 * @author Eugene Marinelli
6
 */
7

    
8
/********************************* Includes **********************************/
9
#include <string>
10
#include <pthread.h>
11
#include <iostream>
12
#include <fstream>
13
#include <unistd.h>
14
#include <fcntl.h>
15
#include <signal.h>
16

    
17
#include <ColonetServer.h>
18
#include <wireless.h> // Colonet wireless library.
19
#include <wl_token_ring.h>
20

    
21
#include <colonet_defs.h>
22
#include <colonet_wireless.h>
23

    
24
/******************************* Definitions *********************************/
25

    
26
//Enable debug printouts
27
#define DEBUG 1
28

    
29
#ifdef DEBUG
30
#define dbg_printf(...) printf(__VA_ARGS__)
31
#define dbg_fprintf(...) fprintf(__VA_ARGS__)
32
#else
33
#define dbg_printf(...)
34
#define dbg_fprintf(...)
35
#endif
36

    
37
extern ColonetServer colonet_server;
38

    
39
static bool logging_enabled;
40
static char log_filename[80];
41
static pthread_t listener_thread;
42
static char wl_port[40];
43

    
44
/************************* Internal prototypes *******************************/
45
static void* listen(void* args);
46
static void timeout_handler(void);
47
static void handle_response(int frame, int received);
48
static void handle_receive(char type, int source, unsigned char* packet, int len);
49
static void unregister(void);
50
static int log_packet(unsigned char* packet, int len);
51

    
52
/**************************** Public functions *******************************/
53
/**
54
 * @brief Initializes the wireless library
55
 *
56
 * @param wl_port_ The port to listen for wireless messages on
57
 * @param log_filename_ The name of the log file
58
 *
59
 * @return 0 on success, negative error code on failure
60
 */
61
int colonet_wl_init(char* wl_port_, char* log_filename_) {
62
  if (log_filename_ != NULL) {
63
    logging_enabled = true;
64
    strcpy(log_filename, log_filename_);
65
  }
66

    
67
  strncpy(wl_port, wl_port_, 40);
68

    
69
  wl_set_com_port(wl_port);
70

    
71
  fprintf(stderr, "Calling wl_init(%s)...\n", wl_port);
72
  if (wl_init() != 0) {
73
    fprintf(stderr, "wl_init failed.\n");
74
    return -1;
75
  }
76

    
77
  wl_token_ring_register();
78

    
79
  fprintf(stderr, "Joining token ring...\n");
80
  if (wl_token_ring_join() != 0) {
81
    fprintf(stderr, "Failed to join token ring.\n");
82
    return -1;
83
  }
84
  fprintf(stderr, "Joined token ring.\n");
85

    
86
  return 0;
87
}
88

    
89
/**
90
 * @brief This function will kill the thread that is listening for wireless messages
91
 */
92
void colonet_wl_kill_listener_thread() {
93
  pthread_kill(listener_thread, 9);
94
}
95

    
96
/**
97
 * @brief This function spawns a thread to listen for wireless messages
98
 *
99
 * @return 0 on success, negative error code on failure
100
 */
101
int colonet_wl_run_listener_thread() {
102
  dbg_printf("Spawning listener thread...\n");
103

    
104
  if (pthread_create(&listener_thread, NULL, listen, NULL)) {
105
    perror("pthread_create");
106
    return -1;
107
  }
108

    
109
  return 0;
110
}
111

    
112
/**
113
 * @brief This function sends a message out on the wireless
114
 *
115
 * @param client_source The index in the connection pool of the client that is sending the message
116
 * @param dest The robot that is meant to receive this message
117
 * @param msg_type The type of the message
118
 * @param msg_code The message code
119
 * @param args The arguments to send with the message
120
 *
121
 * @return 0 on success, a negative error code on failure
122
 */
123
int colonet_wl_send(short client_source, short dest, ColonetRobotMessageType msg_type, unsigned char msg_code,
124
                    unsigned char* args) {
125
  printf("colonet_wl_send: client_source:%d, dest:%d, msg_code:%d\n", client_source, dest, msg_code);
126

    
127
  //create and set up new packet to be sent.
128
  ColonetRobotServerPacket pkt;
129
  pkt.client_id = client_source;
130
  pkt.msg_code = msg_code;
131

    
132
  //copy over the args into the data portion of the packet
133
  for (int i = 0; i < PACKET_DATA_LEN; i++) {
134
    //printf("data %i: %u\n", i, args[i]);
135
    pkt.data[i] = args[i];
136
  }
137

    
138
  if (dest == GLOBAL_DEST) {
139
    //printf("sending to global dest\n");
140
    int ret = wl_send_global_packet(COLONET_PACKET_GROUP_ID, (char)msg_type, (char*)(&pkt),
141
                                    sizeof(ColonetRobotServerPacket), 0);
142
    if (ret != 0) {
143
      fprintf(stderr, "%s: wl_send_global_packet failed.\n", __FUNCTION__);
144
      return -1;
145
    }
146
  } else {
147
    //("sending to specific robot: %d.\n", dest);
148
    int ret = wl_send_robot_to_robot_global_packet(COLONET_PACKET_GROUP_ID, (char)msg_type, (char*)(&pkt),
149
                                                   sizeof(ColonetRobotServerPacket), dest,
150
                                                   COLONET_RESPONSE_PACKET_FRAME_ID);
151
    if (ret != 0) {
152
      fprintf(stderr, "%s: wl_send_robot_to_robot_global_packet failed.\n", __FUNCTION__);
153
      return -1;
154
    }
155
  }
156

    
157
  return 0;
158
}
159

    
160
/**
161
 * @brief Used to get the number of robots in the token ring
162
 *
163
 * @return The result of wl_token_get_num_robots()
164
 */
165
int colonet_get_num_robots(void) {
166
  return wl_token_get_num_robots();
167
}
168

    
169
/**
170
 * @brief Gets a list of the xbee ids of the ones in the token ring
171
 *
172
 * @param numrobots A pointer to the variable where you want the number of robots to be stored
173
 *
174
 * @return A dynamically allocated piece of memory that contains the list of xbee ids.
175
 *   The function calling this function must free this memory when done with it.
176
 */
177
int* colonet_get_xbee_ids(int* numrobots) {
178
  int num_robots = wl_token_get_num_robots();
179
  int* ids = (int*)malloc(num_robots * sizeof(int));
180

    
181
  wl_token_iterator_begin();
182

    
183
  int i = 0;
184
  while (wl_token_iterator_has_next()) {
185
    ids[i] = wl_token_iterator_next();
186
    i++;
187
  }
188

    
189
  *numrobots = num_robots;
190
  return ids;
191
}
192

    
193
/**
194
 * @brief Gets the sensor matrix from the wireless library
195
 *
196
 * @param numrobots A pointer to the variable where you want the number of robots to be stored
197
 * @param ids_ A pointer to a pointer that you want to point to the list of xbee ids.  This memory is dynamically
198
 * allocated and should be freed by the calling process when it is done with it
199
 *
200
 * @return The 2d matrix reprsenting the sensor matrix.  This memory is dynamically allocated and should be freed by
201
 * the calling process when it is done with it
202
 */
203
int** colonet_get_sensor_matrix(int* numrobots, int** ids_) {
204
  int num_robots;
205
  int* ids = colonet_get_xbee_ids(&num_robots);
206

    
207
  int** m = (int**)malloc(num_robots * sizeof(int*));
208
  for (int i = 0; i < num_robots; i++) {
209
    m[i] = (int*)malloc(num_robots * sizeof(int*));
210
  }
211

    
212
  for (int i = 0; i < num_robots; i++) {
213
    for (int j = 0; j < num_robots; j++) {
214
      m[i][j] = wl_token_get_sensor_reading(ids[i], ids[j]);
215
    }
216
  }
217

    
218
  *numrobots = num_robots;
219
  *ids_ = ids;
220
  return m;
221
}
222

    
223
/**************************** Private functions ******************************/
224

    
225
//TODO: fill in the doxygen comments
226
/**
227
 * @brief 
228
 *
229
 * @return Void
230
 */
231
static void timeout_handler() {
232
  // printf("colonet wireless - timeout!\n");
233
}
234

    
235
//TODO: fill in the doxygen comments
236
/**
237
 * @brief 
238
 *
239
 * @param frame
240
 * @param received
241
 *
242
 * @return Void
243
 */
244
static void handle_response(int frame, int received) {
245
  //TODO: These are just here to get rid of compiler warnings
246
  frame = frame;
247
  received = received;
248
  printf("handle_response\n");
249
}
250

    
251
/**
252
 * @brief When a packet is received via wireless, the data is passed to this function
253
 *
254
 * @param type 
255
 * @param source The robot the packet came from
256
 * @param data The data the robot sent
257
 * @param len The length of the data
258
 *
259
 * @return Void
260
 */
261
static void handle_receive(char type, int source, unsigned char* data, int len) {
262
  type = type; //TODO: This is just here to get rid of compiler warnings.
263

    
264
  printf("***Got packet from robot***\n");
265

    
266
  ColonetRobotServerPacket* pkt = (ColonetRobotServerPacket*)data;
267

    
268
  if (logging_enabled) {
269
    log_packet(data, len);
270
  }
271

    
272
  //see if a robot wants the server to tell it where it is
273
  if (pkt->msg_code == ROBOT_REQUEST_POSITION_FROM_SERVER) {
274
    /* Robot has requested its position. */
275
    int robot_x, robot_y;
276
    PositionMonitor* pm = colonet_server.getPositionMonitor();
277
    int num_robots = pm->getNumVisibleRobots();
278

    
279
    //ask the position monitor for where that robot is.
280
    int ret = pm->getRobotPosition(source, &robot_x, &robot_y);
281
    if (ret != 0 && num_robots != 1) {
282
      fprintf(stderr, "Robot %d requested position, but its position is not known.\n", source);
283
    } else {
284
      if (ret != 0 /* && num_robots == 1 */) {
285
        VisionPosition pos = pm->getFirstPosition();
286
        robot_x = pos.x;
287
        robot_y = pos.y;
288
      }
289

    
290
      unsigned char response[80];
291
      response[0] = (robot_x >> 8) & 0xFF;
292
      response[1] = robot_x & 0xFF;
293
      response[2] = (robot_y >> 8) & 0xFF;
294
      response[3] = robot_y & 0xFF;
295

    
296
      fprintf(stderr, "Robot %d requested position.  Its position is %d,%d.\n", source, robot_x, robot_y);
297

    
298
      if (colonet_wl_send(-1, source, COLONET_COMMAND, SERVER_REPORT_POSITION_TO_ROBOT, response) != 0) {
299
        fprintf(stderr, "colonet_wl_send failed!\n");
300
        exit(1);
301
      }
302
    }
303
  } else {
304
    printf("Calling colonet_server.process_received_wireless_message\n");
305
    char processed_data[80];
306
    sprintf(processed_data, "%d %d %d %s\n", RESPONSE_TO_CLIENT_REQUEST, pkt->msg_code, source, pkt->data);
307

    
308
    fprintf(stderr, "client_id=%d; processed_data: %s\n", pkt->client_id, processed_data);
309

    
310
    colonet_server.process_received_wireless_message(pkt->client_id, processed_data, strlen(processed_data));
311
  }
312
}
313

    
314
//TODO: fill in the doxygen comments
315
/**
316
 * @brief 
317
 *
318
 * @return Void
319
 */
320
static void unregister(void) {
321
  printf("unregister\n");
322
}
323

    
324
/** @brief Analogous to the "SIGNAL" or "ISR" function on the robots.
325
 * Listens for bytes on the wireless port and constructs packets based on them.
326
 * Not part of the ColonetWireless class since a function pointer must be
327
 * passed in starting the thread that runs it (tricky or impossible if it's
328
 * a class function).
329
 *
330
 * @param args Pointer to arguments.  Can be safely casted to ListenerArgs type
331
 * @return NULL
332
 */
333
static void* listen(void* args) {
334
  args = args; //TODO: These are just here to get rid of compiler warnings.
335

    
336
  fprintf(stderr, "Called listen.\n");
337

    
338
  PacketGroupHandler pgh = {COLONET_PACKET_GROUP_ID, timeout_handler, handle_response, handle_receive, unregister};
339
  wl_register_packet_group(&pgh);
340

    
341
  while (1) {
342
    wl_do();
343

    
344
    //this sleep is here so the thread this runs in doesn't hog the cpu
345
    usleep(1000);
346
  }
347

    
348
  fprintf(stderr, "Listen is returning.\n");
349

    
350
  wl_terminate();
351
  return NULL;
352
}
353

    
354
/** 
355
 * @brief
356
 *
357
 * @param pkt Packet to be logged
358
 *
359
 * @return 0 on success, -1 on failure
360
 */
361
int log_packet(unsigned char* packet, int len) {
362
  FILE* logfile = fopen(log_filename, "a");
363

    
364
  if (logfile == NULL) {
365
    dbg_printf("%s: Error - fopen %s failed.\n", log_filename, __FUNCTION__);
366
    return -1;
367
  }
368

    
369
  for (int i = 0; i < len; i++) {
370
    fprintf(logfile, "%d ", *((unsigned char*)packet + i));
371
  }
372
  fprintf(logfile, "\n");
373

    
374
  fclose(logfile);
375
  return 0;
376
}