@@ -46,7 +46,11 @@ static bool_t ping (devAEM_t dev) { | |||
*/ | |||
static size_t seeker (void) { | |||
size_t cnt =0; // count devices on range | |||
sleep (settings.seekerInterval); | |||
log_debug ("Debug: Pinging devices...\n"); | |||
devList_acquire (); | |||
for (int i=0 ; i<AEMLIST_SIZE ; ++i) { | |||
if (devList[i].dev == settings.me) {// Don't ping me, I'm not here, go away... | |||
devList[i].onRange = false; | |||
@@ -59,11 +63,16 @@ static size_t seeker (void) { | |||
if (!devList[i].begin) | |||
devList[i].begin = time(NULL); // first time only | |||
devList[i].end = time(NULL); // every time | |||
log_debug ("Debug: Device %u found\n", devList[i].dev); | |||
devList_t cDev = devList[i]; | |||
devList_release (); | |||
log_debug ("Debug: Device %u found\n", cDev.dev); | |||
devList_acquire (); | |||
} | |||
else | |||
devList[i].onRange = false; // Where is everybody? | |||
} | |||
statsTimesPrint (devList); | |||
devList_release (); | |||
log_debug ("Debug: %d devices found\n", cnt); | |||
return cnt; | |||
} | |||
@@ -209,32 +218,31 @@ static void client (void) { | |||
msgList_release (); | |||
log_debug ("Debug: Message added to msgList at %d\n", at); | |||
if (!seeker ()) // If we are alone skip the rest | |||
continue; | |||
log_debug ("Debug: Devices found on range\n"); | |||
msgList_acquire (); | |||
mIter_t it = msgList_begin (&msgList); // get a message iterator | |||
// for each message -> for each recipient | |||
for (size_t i=0 ; i<msgList_size(&msgList) ; ++i, msgList_preInc (&it)) { | |||
for (size_t j=0 ; j<AEMLIST_SIZE ; ++j) { | |||
// get current dev instance | |||
devList_acquire (); | |||
devList_t currentDev = devList[j]; | |||
devList_release (); | |||
// check when to send | |||
if (devList[j].onRange // is on range | |||
if (currentDev.onRange // is on range | |||
&& !msgList.m[it].recipients[j] // we haven't send the message to that device | |||
&& msgList.m[it].cMsg.to != settings.me // the message it's not for me | |||
) { | |||
if (sendMsg (devList[j].dev, &msgList.m[it].cMsg)) { | |||
if (sendMsg (currentDev.dev, &msgList.m[it].cMsg)) { | |||
msgList.m[it].recipients[j] = true; | |||
msgList_release (); | |||
statsUpdateOut (&msg, devList[j].dev); | |||
log_msg_out (&msg, devList[j].dev); | |||
log_debug ("Debug: Send message to device %u succeed\n", devList[j].dev); | |||
statsUpdateOut (&msg, currentDev.dev); | |||
log_msg_out (&msg, currentDev.dev); | |||
log_debug ("Debug: Send message to device %u succeed\n", currentDev.dev); | |||
msgList_acquire (); | |||
} | |||
else { | |||
msgList_release (); | |||
log_debug ("Debug: Send message to device %u failed\n", devList[j].dev); | |||
log_debug ("Debug: Send message to device %u failed\n", currentDev.dev); | |||
msgList_acquire (); | |||
} | |||
//^ we try to send the message and mark the transmission on success | |||
@@ -249,6 +257,19 @@ static void client (void) { | |||
return; | |||
} | |||
/*! | |||
* pthread wrapper for \sa seeker() | |||
* @param ptr | |||
*/ | |||
void* pthSeeker (void* ptr) { | |||
(void)&ptr; // use parameter | |||
while (true) | |||
seeker (); | |||
exit(1); // we should not be here | |||
return NULL; | |||
} | |||
/*! | |||
* pthread wrapper for \sa client() | |||
* @param ptr | |||
@@ -10,7 +10,7 @@ | |||
#include "core.h" | |||
#include "msg_impl.h" | |||
void* pthSeeker (void* ptr); | |||
void* pthClient (void* ptr); | |||
#endif /* __client_h__ */ |
@@ -23,6 +23,7 @@ msgList_t msgList; //!< The message list for our application. | |||
* Local data types | |||
*/ | |||
static pthread_mutex_t lock_msgList; //!< mutex for msgList locking | |||
static pthread_mutex_t lock_devList; //!< mutex for devList locking | |||
static pthread_mutex_t lock_stderr; //!< mutex for stderr locking | |||
static pthread_mutex_t lock_stdout; //!< mutex for stderr locking | |||
static pthread_mutex_t lock_stats; //!< mutex for stats locking | |||
@@ -366,18 +367,26 @@ void msg_init (msg_t* msg) { | |||
//! @} | |||
//! msgList API | |||
//! devList API | |||
//! @{ | |||
/*! Macro helper to saturate increased values */ | |||
#define _top_saturate(test, apply, value) do { \ | |||
if (test >= value) apply = value; \ | |||
} while (0) | |||
/*! | |||
* Initialize the devList | |||
* @param msgList Pointer to mesList t initialize | |||
* @return The status of the operation | |||
*/ | |||
status_t devList_init (devList_t* devList) { | |||
devAEM_t l[] = AEMLIST; | |||
if (pthread_mutex_init(&lock_devList, NULL) != 0) { | |||
log_error ("Error: mutex init has failed\n"); | |||
return MSG_ERROR; | |||
} | |||
memset ((void*)devList, 0, sizeof(devList_t)); | |||
for (size_t i =0 ; i<AEMLIST_SIZE ; ++i) | |||
devList[i].dev = l[i]; | |||
/*! Macro helper to saturate decreased values */ | |||
#define _btm_saturate(test, apply, value) do { \ | |||
if (test < value) apply = value; \ | |||
while (0) | |||
return MSG_OK; | |||
} | |||
/*! | |||
* Returns an iterator for \sa devList AND \sa msg_t.recipients | |||
@@ -392,6 +401,26 @@ dIter_t devList_getIter (devAEM_t dev) { | |||
return -1; // return end() | |||
} | |||
//! Acquires devList resources | |||
void devList_acquire (void) { pthread_mutex_lock(&lock_devList); } | |||
//! Releases devList resources | |||
void devList_release (void) { pthread_mutex_unlock(&lock_devList); } | |||
//! @} | |||
//! msgList API | |||
//! @{ | |||
/*! Macro helper to saturate increased values */ | |||
#define _top_saturate(test, apply, value) do { \ | |||
if (test >= value) apply = value; \ | |||
} while (0) | |||
/*! Macro helper to saturate decreased values */ | |||
#define _btm_saturate(test, apply, value) do { \ | |||
if (test < value) apply = value; \ | |||
while (0) | |||
/*! | |||
* Initialize the msgList | |||
* @param msgList Pointer to mesList t initialize | |||
@@ -643,14 +672,28 @@ status_t statsPrint (stats_t* stats) { | |||
fprintf (fp, "Out direct messages: %d\n", stats->outDirectMsg); | |||
fprintf (fp, "Average message size: %g\n", stats->avMsgSize); | |||
fprintf (fp, "Average time to me: %g\n", stats->avTimeToMe); | |||
fclose (fp); | |||
return MSG_OK; | |||
} | |||
/*! | |||
* Device online timing print functionality | |||
* @param devList Pointer to devList to print | |||
* @return The status of the operation | |||
*/ | |||
status_t statsTimesPrint (devList_t *devList) { | |||
FILE* fp = fopen ("devices.txt", "w"); | |||
if (fp == NULL) { | |||
fclose (fp); | |||
return MSG_ERROR; | |||
} | |||
fprintf (fp, "\n Device timings\n================\n"); | |||
for (size_t i =0 ; i<AEMLIST_SIZE ; ++i) { | |||
fprintf (fp, " Device %u found on %lld, last: %lld\n", | |||
fprintf (fp, "Device %u found on %lld, last: %lld\n", | |||
devList[i].dev, devList[i].begin, devList[i].end); | |||
} | |||
fclose (fp); | |||
return MSG_OK; | |||
} | |||
//! @} | |||
@@ -29,7 +29,10 @@ bool_t cMsg_equal (cMsg_t* m1, cMsg_t* m2); | |||
void msg_init (msg_t* msg); | |||
status_t devList_init (devList_t* devList); | |||
dIter_t devList_getIter (devAEM_t dev); | |||
void devList_acquire (void); | |||
void devList_release (void); | |||
mIter_t msgList_preInc (mIter_t* it); | |||
mIter_t msgList_preDec (mIter_t* it); | |||
@@ -47,6 +50,7 @@ void statsUpdateCreate (msg_t* msg); | |||
void statsUpdateIn (msg_t* msg, bool_t dup); | |||
void statsUpdateOut (msg_t* msg, devAEM_t dev); | |||
status_t statsPrint (stats_t* stats); | |||
status_t statsTimesPrint (devList_t *devList); | |||
status_t log_init(void); | |||
void log_msg_in (msg_t* msg); | |||
@@ -43,14 +43,19 @@ static void listen_handler (devAEM_t dev, char_t* buffer, size_t size) { | |||
// We have a copy | |||
msgList_release (); | |||
statsUpdateIn (&msg, true); // message process | |||
log_debug("Debug: Duplicate message from: %d\n", msg.sender); | |||
log_debug ("Debug: Duplicate message from: %d\n", msg.sender); | |||
} | |||
// Processing... | |||
devList_acquire(); | |||
dIter_t d = devList_getIter (dev); | |||
dIter_t f = devList_getIter (msg.cMsg.from); | |||
devList_release(); | |||
msgList_acquire (); | |||
// Do not echo message to sender, he already has it | |||
msgList.m[myCopy].recipients[devList_getIter (dev)] = true; | |||
msgList.m[myCopy].recipients[d] = true; | |||
// don't push back message to creator, he already has it | |||
msgList.m[myCopy].recipients[devList_getIter (msg.cMsg.from)] = true; | |||
msgList.m[myCopy].recipients[f] = true; | |||
msgList_release (); | |||
} | |||
@@ -1,6 +1,6 @@ | |||
/*! | |||
* \file main.c | |||
* This is the main file of the RTES final task | |||
* This is the main file of the RTES final task. | |||
* | |||
* \author Christos Choutouridis AEM:8997 <cchoutou@ece.auth.gr> | |||
*/ | |||
@@ -21,24 +21,23 @@ | |||
*/ | |||
//! @{ | |||
settings_t settings_init (settings); | |||
devList_t devList_init(devList[AEMLIST_SIZE]); | |||
stats_t stats; | |||
settings_t settings_init (settings); //!< Application settings | |||
devList_t devList[AEMLIST_SIZE]; //!< Device list | |||
stats_t stats; //!< Statistical data | |||
//! @} | |||
/*! | |||
* CLI short options | |||
*/ | |||
const char *short_opt = "li:v:p:s:w:th"; | |||
const char *short_opt = "v:i:p:s:w:th"; | |||
/*! | |||
* CLI long options | |||
*/ | |||
const struct option long_opt[] = { | |||
{"port", required_argument, NULL, 'l'}, | |||
{"interval", required_argument, NULL, 'i'}, | |||
{"outlevel", required_argument, NULL, 'v'}, | |||
{"interval", required_argument, NULL, 'i'}, | |||
{"pingtimeout",required_argument, NULL, 'p'}, | |||
{"sendtimeout",required_argument, NULL, 's'}, | |||
{"who", required_argument, NULL, 'w'}, | |||
@@ -50,7 +49,7 @@ const struct option long_opt[] = { | |||
/*! | |||
* \brief | |||
* Parse input argument and fill the kcli_input_t struct | |||
* \param in Pointer to \ref kcli_input_t structure to fill | |||
* \param s Pointer to settings_t data to fill | |||
* \param argc The argument count as passed to the main() | |||
* \param argv Argument array as passed to the main() | |||
* \return The status of the operation | |||
@@ -65,13 +64,12 @@ int parse_args (settings_t *s, int argc, char const *argv[]) { | |||
case -1: /* no more arguments */ | |||
case 0: /* long options toggles */ | |||
break; | |||
case 'l': s->port = atoi(optarg); break; | |||
case 'i': s->msgInterval = atoi (optarg); break; | |||
case 'v': | |||
s->outLevel = atoi (optarg); | |||
if (s->outLevel >= OUTLEVEL_2) s->outLevel = OUTLEVEL_2; | |||
if (s->outLevel < OUTLEVEL_0) s->outLevel = OUTLEVEL_0; | |||
break; | |||
case 'i': s->seekerInterval = atoi (optarg); break; | |||
case 'p': s->pingTimeout = atoi (optarg); break; | |||
case 's': s->sendTimeout.tv_sec = atoi (optarg); break; | |||
case 'w': s->me = atoi (optarg); break; | |||
@@ -89,22 +87,26 @@ int parse_args (settings_t *s, int argc, char const *argv[]) { | |||
} | |||
int main(int argc, char const *argv[]) { | |||
int main (int argc, char const *argv[]) { | |||
// get command line arguments | |||
parse_args (&settings, argc, argv); | |||
// Initialize all subsystems | |||
log_init (); | |||
stats_init (&stats); | |||
devList_init (devList); | |||
msgList_init (&msgList); | |||
// Create threads | |||
pthread_t ptL, ptC; | |||
pthread_t ptL, ptS, ptC; | |||
pthread_create (&ptL, NULL, pthListener, NULL); | |||
pthread_create (&ptS, NULL, pthSeeker, NULL); | |||
pthread_create (&ptC, NULL, pthClient, NULL); | |||
// block here | |||
pthread_join (ptL, NULL); | |||
pthread_join (ptS, NULL); | |||
pthread_join (ptC, NULL); | |||
return 0; | |||
} |
@@ -21,17 +21,17 @@ | |||
*/ | |||
#define AEMLIST_SIZE (10) | |||
#define devList_init(l) l = { \ | |||
{ 7700, 0, 0, 0}, \ | |||
{ 8261, 0, 0, 0}, \ | |||
{ 8765, 0, 0, 0}, \ | |||
{ 8844, 0, 0, 0}, \ | |||
{ 8880, 0, 0, 0}, \ | |||
{ 8861, 0, 0, 0}, \ | |||
{ 8877, 0, 0, 0}, \ | |||
{ 8941, 0, 0, 0}, \ | |||
{ 8934, 0, 0, 0}, \ | |||
{ 8997, 0, 0, 0} \ | |||
#define AEMLIST { \ | |||
7700, \ | |||
8261, \ | |||
8765, \ | |||
8844, \ | |||
8880, \ | |||
8861, \ | |||
8877, \ | |||
8941, \ | |||
8934, \ | |||
8997 \ | |||
} | |||
/*! | |||
@@ -217,6 +217,7 @@ typedef enum { | |||
typedef struct { | |||
devAEM_t me; | |||
uint16_t port; | |||
time_t seekerInterval; | |||
time_t msgInterval; | |||
time_t msgRand; | |||
outLevel_en outLevel; | |||
@@ -230,6 +231,7 @@ extern settings_t settings; | |||
#define settings_init(s) s = { \ | |||
.me = 8997, \ | |||
.port = 2288, \ | |||
.seekerInterval = 30, \ | |||
.msgInterval = 60, \ | |||
.msgRand = 240, \ | |||
.outLevel = OUTLEVEL_1, \ | |||