A messenger application for Raspberry Pi Zerofor A.U.TH (Real time Embedded systems).
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 

429 linhas
11 KiB

  1. /*!
  2. * \file core.c
  3. *
  4. * \author Christos Choutouridis AEM:8997 <cchoutou@ece.auth.gr>
  5. */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <stdarg.h>
  10. #include <pthread.h>
  11. #include "core.h"
  12. pthread_mutex_t lock_msgList;
  13. pthread_mutex_t lock_stderr;
  14. pthread_mutex_t lock_stdout;
  15. pthread_mutex_t lock_stats;
  16. //! Helper API
  17. //! @{
  18. #define _ADHOC_SUBNET(A, B, C, D) (((A)<<24) | ((B)<<16) | ((C)<<8) | (D))
  19. devAEM_t addr2devAEM (uint32_t in_addr) {
  20. return (in_addr & 0x000000FF) + ((in_addr >> 8) & 0x000000FF) * 100;
  21. }
  22. in_addr_t devAEM2addr (devAEM_t dev) {
  23. uint32_t add = _ADHOC_SUBNET (ADHOC_NET_A, ADHOC_NET_B, ADHOC_NET_C, ADHOC_NET_D);
  24. add |= (dev % 100) & 0x000000FF;
  25. add |= ((dev / 100) & 0x000000FF) << 8;
  26. return add;
  27. }
  28. devAEM_t ip2AEM (devIP_t* ip) {
  29. return ip->C*100 + ip->D;
  30. }
  31. devIP_t AEM2ip (devAEM_t dev) {
  32. devIP_t ip = {
  33. .A =ADHOC_NET_A, .B=ADHOC_NET_B, .C=dev/100, .D=dev%100
  34. };
  35. return ip;
  36. }
  37. devIP_t addr2ip (in_addr_t in_addr) {
  38. devIP_t ip = {
  39. .A = ADHOC_NET_A,
  40. .B = ADHOC_NET_B,
  41. .C = (in_addr >> 8) & 0x000000FF,
  42. .D = in_addr & 0x000000FF
  43. };
  44. return ip;
  45. }
  46. //! @}
  47. //! log API
  48. //! @{
  49. static char_t* _frm_msg_io = "dev=%d, message: from=%d, to=%d, timestamp=%lld, text=%s";
  50. static char_t* _frm_msg_new = "new message: from=%d, to=%d, timestamp=%lld, text=%s";
  51. status_t log_init (void) {
  52. if (pthread_mutex_init(&lock_stderr, NULL) != 0) {
  53. fprintf (stderr, "Error %s: mutex init has failed\n", __FUNCTION__ );
  54. return MSG_ERROR;
  55. }
  56. if (pthread_mutex_init(&lock_stdout, NULL) != 0) {
  57. fprintf (stderr, "Error %s: mutex init has failed\n", __FUNCTION__ );
  58. return MSG_ERROR;
  59. }
  60. return MSG_OK;
  61. }
  62. void log_msg_io (msg_t* msg) {
  63. if (settings.outLevel >= OUTLEVEL_1) {
  64. char_t head[16];
  65. strncpy (head, cMsg_getText(&msg->cMsg), sizeof(head));
  66. head[16] = 0;
  67. pthread_mutex_lock(&lock_stdout);
  68. fprintf (stdout, _frm_msg_io,
  69. msg->sender,
  70. cMsg_getFrom (&msg->cMsg),
  71. cMsg_getTo (&msg->cMsg),
  72. cMsg_getTs (&msg->cMsg),
  73. head
  74. );
  75. fflush(stdout);
  76. pthread_mutex_unlock(&lock_stdout);
  77. }
  78. }
  79. void log_msg_new (msg_t* msg) {
  80. if (settings.outLevel >= OUTLEVEL_1) {
  81. char_t head[16];
  82. strncpy (head, cMsg_getText(&msg->cMsg), sizeof(head));
  83. head[16] = 0;
  84. pthread_mutex_lock(&lock_stdout);
  85. fprintf (stdout, _frm_msg_new,
  86. cMsg_getFrom (&msg->cMsg),
  87. cMsg_getTo (&msg->cMsg),
  88. cMsg_getTs (&msg->cMsg),
  89. head
  90. );
  91. fflush(stdout);
  92. pthread_mutex_unlock(&lock_stdout);
  93. }
  94. }
  95. void log_debug (const char *fmt, ...) {
  96. if (settings.outLevel >= OUTLEVEL_2) {
  97. va_list ap;
  98. va_start(ap, fmt);
  99. pthread_mutex_lock(&lock_stdout);
  100. vfprintf (stdout, fmt, ap);
  101. fflush(stdout);
  102. pthread_mutex_unlock(&lock_stdout);
  103. va_end(ap);
  104. }
  105. }
  106. void log_error (const char *fmt, ...) {
  107. va_list ap;
  108. va_start(ap, fmt);
  109. pthread_mutex_lock(&lock_stderr);
  110. vfprintf (stderr, fmt, ap);
  111. fflush(stderr);
  112. pthread_mutex_unlock(&lock_stderr);
  113. va_end(ap);
  114. }
  115. //! @}
  116. //! cMsg_t API
  117. //! @{
  118. /*!
  119. * Make a new message
  120. * @param msg Pointer to message to create
  121. */
  122. void cMsg_make (cMsg_t* msg) {
  123. static int msgID =0; // unique msg ID
  124. msg->from = settings.me; // from me
  125. msg->to = devList[rand()%AEMLIST_SIZE].dev; // randomly select device
  126. msg->ts = time(NULL);
  127. // stream the first fields and take the quote text iterator
  128. msg->text_it = sprintf (msg->text, "%d_%d_%lld_",
  129. msg->from,
  130. msg->to,
  131. msg->ts
  132. );
  133. // stream out the quote with a unique ID
  134. sprintf (&msg->text[msg->text_it], MESSAGE_BODY" #%d", msgID++);
  135. }
  136. /*!
  137. * Parse an incoming message
  138. *
  139. * @param cMsg Pointer to cMsg object to store the parsed data
  140. * @param rawMsg Pointer to raw message
  141. * @param size The size f raw message buffer
  142. * @return The status of the operation
  143. * @arg MSG_OK Success
  144. * @arg MSG_ERROR Parse failure, incoming message format error
  145. */
  146. status_t cMsg_parse (cMsg_t* cMsg, char_t* rawMsg, size_t size) {
  147. // Check message integrity
  148. if (size > MSG_TEXT_SIZE)
  149. return MSG_ERROR;
  150. int d =0;
  151. for (size_t i =0; rawMsg[i] && i<size; ++i) {
  152. d += (rawMsg[i] == MSG_DELIMITER) ? 1:0;
  153. }
  154. if (d != 3)
  155. return MSG_ERROR;
  156. // Get message
  157. strcpy(cMsg->text, rawMsg);
  158. // Parse message
  159. char_t del[2] = {MSG_DELIMITER, '\0'};
  160. char_t* tok;
  161. tok = strtok (cMsg->text, del);
  162. cMsg->from = atoi (tok);
  163. tok = strtok(NULL, del);
  164. cMsg->to = atoi (tok);
  165. tok = strtok(NULL, del);
  166. cMsg->ts = atoll (tok);
  167. tok = strtok(NULL, del);
  168. cMsg->text_it = tok - cMsg->text;
  169. return MSG_OK;
  170. }
  171. /*! getter for cMsg_t member fromAEM */
  172. uint32_t cMsg_getFrom(cMsg_t* cMsg) { return cMsg->from; }
  173. /*! getter for cMsg_t member toAEM */
  174. uint32_t cMsg_getTo(cMsg_t* cMsg) { return cMsg->to; }
  175. /*! getter for cMsg_t member fromAEM */
  176. uint64_t cMsg_getTs(cMsg_t* cMsg) { return cMsg->ts; }
  177. /*! getter for payload text member */
  178. char_t* cMsg_getText(cMsg_t* cMsg) { return (char_t*)& cMsg->text[cMsg->text_it]; }
  179. /*!
  180. * Predicate to check core message equality
  181. * @param m1 Pointer to message 1
  182. * @param m2 Pointer to message 2
  183. * @return Equality result (true, false)
  184. */
  185. bool_t cMsg_equal (cMsg_t* m1, cMsg_t* m2) {
  186. if (m1->from != m2->from) return false;
  187. if (m1->to != m2->to) return false;
  188. if (m1->ts != m2->ts) return false;
  189. if (strncmp (cMsg_getText(m1), cMsg_getText(m2), sizeof(m1->text)))
  190. return false;
  191. return true;
  192. }
  193. //! @}
  194. /*!
  195. * mgs_t API
  196. */
  197. //! @{
  198. void msg_init (msg_t* msg) {
  199. memset ((void*)msg, 0, sizeof(msg_t));
  200. }
  201. //! @}
  202. /*!
  203. * Create a message list for our application.
  204. */
  205. msgList_t msgList;
  206. //! msgList API
  207. //! @{
  208. /*! Macro helper to saturate increased values */
  209. #define _top_saturate(test, apply, value) do { \
  210. if (test >= value) apply = value; \
  211. } while (0)
  212. /*! Macro helper to saturate decreased values */
  213. #define _btm_saturate(test, apply, value) do { \
  214. if (test < value) apply = value; \
  215. while (0)
  216. dIter_t devList_getIter (devAEM_t dev) {
  217. for (dIter_t i =0 ; i<AEMLIST_SIZE ; ++i) {
  218. if (devList[i].dev == dev)
  219. return i;
  220. }
  221. return -1; // return end()
  222. }
  223. status_t msgList_init (msgList_t* msgList) {
  224. if (pthread_mutex_init(&lock_msgList, NULL) != 0) {
  225. log_error ("Error: mutex init has failed\n");
  226. return MSG_ERROR;
  227. }
  228. memset((void*)msgList, 0, sizeof(msgList_t));
  229. msgList->first =-1;
  230. msgList->last =-1;
  231. srand (time(NULL));
  232. return MSG_OK;
  233. }
  234. /*!
  235. * @brief msgList iterator pre-increment in the msg_t direction
  236. *
  237. * This iterator force a ring buffer behavior. This function takes pointer
  238. * to iterator to alter but return the altered value so it can be directly
  239. * used in expressions
  240. *
  241. * @param it Pointer to iterator to increase
  242. * @return The iterator values
  243. */
  244. mIter_t msgList_preInc (mIter_t* it) {
  245. if (++*it >= MSG_LIST_SIZE) *it = 0;
  246. return *it;
  247. }
  248. /*!
  249. * @brief msgList iterator pre-decrement in the msg_t direction
  250. *
  251. * This iterator force a ring buffer behavior. This function takes pointer
  252. * to iterator to alter but return the altered value so it can be directly
  253. * used in expressions
  254. *
  255. * @param it Pointer to iterator to decrease
  256. * @return The iterator values
  257. */
  258. mIter_t msgList_preDec (mIter_t* it) {
  259. if (--*it < 0) *it = MSG_LIST_SIZE;
  260. return *it;
  261. }
  262. mIter_t msgList_begin (msgList_t* this) {
  263. return this->first;
  264. }
  265. mIter_t msgList_last (msgList_t* this) {
  266. return this->last;
  267. }
  268. size_t msgList_size (msgList_t* this) {
  269. return this->size;
  270. }
  271. /*!
  272. * Searches for a message in the message list.
  273. *
  274. * @param this The msgList object to work with
  275. * @param msg Pointer to message to search
  276. * @return Iterator to message if found, or -1 if not
  277. */
  278. mIter_t msgList_find (msgList_t* this, msg_t* msg) {
  279. mIter_t it =this->last; // get iterator
  280. // search from end to start to find msg, return on success
  281. for (size_t i=0 ; i < this->size ; ++i) {
  282. if (cMsg_equal (&this->m[it].cMsg, &msg->cMsg))
  283. return it;
  284. msgList_preDec(&it);
  285. // We start from the end as we think, its more possible
  286. // to find msg in the recent messages.
  287. }
  288. return (mIter_t)-1; // fail to find
  289. }
  290. /*!
  291. * Add a new message in the message list
  292. *
  293. * @param this The msgList object to work with
  294. * @param msg Pointer to message
  295. * @return Iterator to the added item (last)
  296. */
  297. mIter_t msgList_add (msgList_t* this, msg_t* msg) {
  298. if (this->first == -1) // if its first time init "first" iterator
  299. this->first = 0;
  300. this->m[msgList_preInc(&this->last)] = *msg; // store data *++it = *msg;
  301. _top_saturate(++this->size, this->size, MSG_LIST_SIZE); // count the items with saturation
  302. // if we reacher full capacity, move along first also
  303. if ((this->first == this->last) && (this->size > 1))
  304. msgList_preInc(&this->first);
  305. return this->last; // return the iterator to newly created slot
  306. }
  307. void msgList_acquire () { pthread_mutex_lock (&lock_msgList); }
  308. void msgList_release () { pthread_mutex_unlock (&lock_msgList); }
  309. //! @}
  310. //! Statistics API
  311. //! @{
  312. status_t stats_init (stats_t* s) {
  313. memset ((void*)s, 0, sizeof (stats_t));
  314. if (pthread_mutex_init(&lock_stats, NULL) != 0) {
  315. log_error ("Error: mutex init has failed\n");
  316. return MSG_ERROR;
  317. }
  318. return MSG_OK;
  319. }
  320. void statsUpdateCreate (msg_t* msg) {
  321. pthread_mutex_lock (&lock_stats);
  322. ++stats.totalMsg;
  323. ++stats.myMsg;
  324. // average message size
  325. uint32_t saved = stats.totalMsg - stats.duplicateMsg;
  326. stats.avMsgSize += strlen(cMsg_getText(&msg->cMsg)) / (saved -1);
  327. stats.avMsgSize *= (saved-1)/saved;
  328. pthread_mutex_unlock (&lock_stats);
  329. }
  330. void statsUpdateIn (msg_t* msg, bool_t dup) {
  331. pthread_mutex_lock (&lock_stats);
  332. bool_t forMe;
  333. stats.totalMsg++;
  334. stats.duplicateMsg += (dup) ? 1:0;
  335. stats.forMeMsg += ((forMe = msg->cMsg.to == settings.me)) ? 1:0;
  336. stats.inDirectMsg += (forMe && (msg->cMsg.from == msg->sender)) ? 1:0;
  337. // averages
  338. uint32_t saved = stats.totalMsg - stats.duplicateMsg;
  339. stats.avMsgSize += strlen(cMsg_getText(&msg->cMsg)) / (saved -1);
  340. stats.avMsgSize *= (saved-1)/saved;
  341. if (settings.trackTime) {
  342. stats.avTimeToMe += ((tstamp_t)time(NULL) - msg->cMsg.ts) / (saved -1);
  343. stats.avTimeToMe *= (saved-1)/saved;
  344. }
  345. pthread_mutex_unlock (&lock_stats);
  346. }
  347. void statsUpdateOut (msg_t* msg, devAEM_t dev) {
  348. pthread_mutex_lock (&lock_stats);
  349. stats.outDirectMsg += (msg->cMsg.to == dev) ? 1:0;
  350. pthread_mutex_unlock (&lock_stats);
  351. }
  352. //! @}