A messenger application for Raspberry Pi Zerofor A.U.TH (Real time Embedded systems).
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

376 lines
10 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. //! Helper API
  14. //! @{
  15. #define _ADHOC_SUBNET(A, B, C, D) (((A)<<24) | ((B)<<16) | ((C)<<8) | (D))
  16. device_t addr2device (uint32_t in_addr) {
  17. device_t dev = {
  18. .id = (in_addr & 0x000000FF) + ((in_addr >> 8) & 0x000000FF) * 100,
  19. .next = NULL
  20. };
  21. return dev;
  22. }
  23. uint32_t device2addr (const device_t* dev) {
  24. uint32_t add = _adhoc_subnet;
  25. add |= (dev->id % 100) & 0x000000FF;
  26. add |= ((dev->id / 100) & 0x000000FF) << 8;
  27. return add;
  28. }
  29. device_t ip2device (devIP_t* ip) {
  30. device_t dev = {
  31. .id = ip->C*100 + ip->D,
  32. .next = NULL
  33. };
  34. return dev;
  35. }
  36. devIP_t device2ip (const device_t* dev) {
  37. devIP_t ip = {
  38. .A=0, .B=0, .C=dev->id/100, .D=dev->id%100
  39. };
  40. return ip;
  41. }
  42. devIP_t addr2ip (uint32_t in_addr) {
  43. devIP_t ip = {
  44. .A=0, .B=0,
  45. .C=(in_addr >> 8) & 0x000000FF,
  46. .D=in_addr & 0x000000FF
  47. };
  48. return ip;
  49. }
  50. //! @}
  51. //! cMsg_t API
  52. //! @{
  53. /*!
  54. * Parse an incoming message
  55. *
  56. * @param cMsg Pointer to cMsg object to store the parsed data
  57. * @param rawMsg Pointer to raw message
  58. * @param size The size f raw message buffer
  59. * @return The status of the operation
  60. * @arg MSG_OK Success
  61. * @arg MSG_ERROR Parse failure, incoming message format error
  62. */
  63. status_t cMsg_parse (cMsg_t* cMsg, char_t* rawMsg, size_t size) {
  64. // Check message integrity
  65. if (size > MSG_TEXT_SIZE)
  66. return MSG_ERROR;
  67. int d =0;
  68. for (size_t i =0; rawMsg[i] && i<size; ++i) {
  69. d += (rawMsg[i] == MSG_DELIMITER) ? 1:0;
  70. }
  71. if (d != 3)
  72. return MSG_ERROR;
  73. // Get message
  74. strcpy(cMsg->msg, rawMsg);
  75. // Parse message
  76. char_t del[2] = {MSG_DELIMITER, '\0'};
  77. char_t* tok;
  78. tok = strtok (cMsg->msg, del);
  79. cMsg->from = atoi (tok);
  80. tok = strtok(NULL, del);
  81. cMsg->to = atoi (tok);
  82. tok = strtok(NULL, del);
  83. cMsg->ts = atoll (tok);
  84. tok = strtok(NULL, del);
  85. cMsg->text = tok - cMsg->msg;
  86. return MSG_OK;
  87. }
  88. /*! getter for cMsg_t member fromAEM */
  89. uint32_t cMsg_getFrom(cMsg_t* cMsg) { return cMsg->from; }
  90. /*! getter for cMsg_t member toAEM */
  91. uint32_t cMsg_getTo(cMsg_t* cMsg) { return cMsg->to; }
  92. /*! getter for cMsg_t member fromAEM */
  93. uint64_t cMsg_getTs(cMsg_t* cMsg) { return cMsg->ts; }
  94. /*! getter for payload text member */
  95. char_t* cMsg_getText(cMsg_t* cMsg) { return (char_t*)& cMsg->msg[cMsg->text]; }
  96. /*!
  97. * Predicate to check core message equality
  98. * @param m1 Pointer to message 1
  99. * @param m2 Pointer to message 2
  100. * @return Equality result (true, false)
  101. */
  102. bool cMsg_equal (cMsg_t* m1, cMsg_t* m2) {
  103. if (m1->from != m2->from) return false;
  104. if (m1->to != m2->to) return false;
  105. if (m1->ts != m2->ts) return false;
  106. if (strncmp (cMsg_getText(m1), cMsg_getText(m2), sizeof(m1->msg)))
  107. return false;
  108. return true;
  109. }
  110. //! @}
  111. /*!
  112. * Create a message list for our application.
  113. */
  114. msgList_t msgList;
  115. //! msgList API
  116. //! @{
  117. /*! Macro helper to saturate increased values */
  118. #define _top_saturate(test, apply, value) do { \
  119. if (test >= value) apply = value; \
  120. } while (0)
  121. /*! Macro helper to saturate decreased values */
  122. #define _btm_saturate(test, apply, value) do { \
  123. if (test < value) apply = value; \
  124. while (0)
  125. /*!
  126. * @brief msgList iterator pre-increment in the msg_t direction
  127. *
  128. * This iterator force a ring buffer behavior. This function takes pointer
  129. * to iterator to alter but return the altered value so it can be directly
  130. * used in expressions
  131. *
  132. * @param it Pointer to iterator to increase
  133. * @return The iterator values
  134. */
  135. static mIter_t _preInc(mIter_t* it) {
  136. if (++*it >= MSG_LIST_SIZE) *it = 0;
  137. return *it;
  138. }
  139. /*!
  140. * @brief msgList iterator pre-decrement in the msg_t direction
  141. *
  142. * This iterator force a ring buffer behavior. This function takes pointer
  143. * to iterator to alter but return the altered value so it can be directly
  144. * used in expressions
  145. *
  146. * @param it Pointer to iterator to decrease
  147. * @return The iterator values
  148. */
  149. static mIter_t _preDec(mIter_t* it) {
  150. if (--*it < 0) *it = MSG_LIST_SIZE;
  151. return *it;
  152. }
  153. /*!
  154. * @brief Access devices in the device_t direction.
  155. *
  156. * This function returns the first device on the recipient list if there is one.
  157. *
  158. * @param this The msgList object to work with
  159. * @param it The iterator value [msg_t direction]
  160. * @return Pointer to first device on the list, or NULL if the list is empty
  161. */
  162. static device_t* devList_get (msgList_t* this, mIter_t it) {
  163. device_t* d = this->m[it].recipients;
  164. return (d) ? d->next : NULL;
  165. }
  166. /*!
  167. * Iterate through device list.
  168. *
  169. * This function return the next device on the recipient list if there is one.
  170. * [device direction]
  171. *
  172. * @param d Pointer to current device
  173. * @return Pointer to next device on the list, or NULL if the list is empty
  174. */
  175. //static device_t* devList_getNext (device_t* d) {
  176. // return (d) ? d->next : NULL;
  177. //}
  178. /*!
  179. * @brief Adds a new device on the recipients list
  180. *
  181. * @param this The msgList object to work with
  182. * @param it The iterator value [msg_t direction]
  183. * @param dev Pointer to device to add [device direction]
  184. * @return The status of the operation
  185. * @arg MSG_OK Success
  186. * @arg MSG_ERROR memory allocation error
  187. */
  188. status_t devList_add (msgList_t* this, mIter_t it, device_t* dev) {
  189. pthread_mutex_lock (&lock_msgList);
  190. device_t* last = devList_get (this, it);
  191. while (last && last->next)
  192. last = last->next;
  193. last = (device_t*)malloc (sizeof(device_t));
  194. *last = *dev;
  195. pthread_mutex_unlock (&lock_msgList);
  196. return (last) ? MSG_OK : MSG_ERROR;
  197. }
  198. /*!
  199. * Frees up all allocated memory in a device list.
  200. *
  201. * @param this The msgList object to work with
  202. * @param it The iterator value [msg_t direction]
  203. */
  204. static void devList_free (msgList_t* this, mIter_t it) {
  205. device_t* last = devList_get (this, it);
  206. while (last) {
  207. device_t* next = last->next;
  208. free(last);
  209. last = next;
  210. }
  211. }
  212. status_t msgList_init (msgList_t* msgList) {
  213. if (pthread_mutex_init(&lock_msgList, NULL) != 0) {
  214. fprintf (stderr, "Error %s: mutex init has failed\n", __FUNCTION__ );
  215. return MSG_ERROR;
  216. }
  217. memset((void*)msgList, 0, sizeof(msgList_t));
  218. msgList->last =-1;
  219. return MSG_OK;
  220. }
  221. /*!
  222. * Searches for a message in the message list.
  223. *
  224. * @param this The msgList object to work with
  225. * @param msg Pointer to message to search
  226. * @return Iterator to message if found, or -1 if not
  227. */
  228. mIter_t msgList_find (msgList_t* this, msg_t* msg) {
  229. pthread_mutex_lock (&lock_msgList);
  230. mIter_t it =this->last; // get iterator
  231. // search from end to start to find msg, return on success
  232. for (size_t i=0 ; i < this->size ; ++i) {
  233. if (cMsg_equal (&this->m[it].cMsg, &msg->cMsg)) {
  234. pthread_mutex_unlock (&lock_msgList);
  235. return it;
  236. }
  237. _preDec(&it);
  238. // We start from the end as we think, its more possible
  239. // to find msg in the recent messages.
  240. }
  241. pthread_mutex_unlock (&lock_msgList);
  242. return (mIter_t)-1; // fail to find
  243. }
  244. /*!
  245. * Add a new message in the message list
  246. *
  247. * @param this The msgList object to work with
  248. * @param msg Pointer to message
  249. */
  250. void msgList_add (msgList_t* this, msg_t* msg) {
  251. pthread_mutex_lock (&lock_msgList);
  252. devList_free (this, _preInc(&this->last)); // free up possible previous recipients list
  253. this->m[this->last] = *msg; // store data
  254. pthread_mutex_unlock (&lock_msgList);
  255. _top_saturate(++this->size, this->size, MSG_LIST_SIZE); // count the items
  256. }
  257. //! @}
  258. static char_t* _frm_msg_io = "dev=%d, message: from=%d, to=%d, timestamp=%lld, text=%s";
  259. static char_t* _frm_msg_new = "new message: from=%d, to=%d, timestamp=%lld, text=%s";
  260. pthread_mutex_t lock_stderr;
  261. pthread_mutex_t lock_stdout;
  262. status_t log_init (void) {
  263. if (pthread_mutex_init(&lock_stderr, NULL) != 0) {
  264. fprintf (stderr, "Error %s: mutex init has failed\n", __FUNCTION__ );
  265. return MSG_ERROR;
  266. }
  267. if (pthread_mutex_init(&lock_stdout, NULL) != 0) {
  268. fprintf (stderr, "Error %s: mutex init has failed\n", __FUNCTION__ );
  269. return MSG_ERROR;
  270. }
  271. return MSG_OK;
  272. }
  273. void log_msg_io (msg_t* msg) {
  274. if (settings.outLevel >= OUTLEVEL_1) {
  275. char_t head[16];
  276. strncpy (head, cMsg_getText(&msg->cMsg), sizeof(head));
  277. head[16] = 0;
  278. pthread_mutex_lock(&lock_stdout);
  279. fprintf (stdout, _frm_msg_io,
  280. msg->sender.id,
  281. cMsg_getFrom (&msg->cMsg),
  282. cMsg_getTo (&msg->cMsg),
  283. cMsg_getTs (&msg->cMsg),
  284. head
  285. );
  286. fflush(stdout);
  287. pthread_mutex_unlock(&lock_stdout);
  288. }
  289. }
  290. void log_msg_new (msg_t* msg) {
  291. if (settings.outLevel >= OUTLEVEL_1) {
  292. char_t head[16];
  293. strncpy (head, cMsg_getText(&msg->cMsg), sizeof(head));
  294. head[16] = 0;
  295. pthread_mutex_lock(&lock_stdout);
  296. fprintf (stdout, _frm_msg_new,
  297. cMsg_getFrom (&msg->cMsg),
  298. cMsg_getTo (&msg->cMsg),
  299. cMsg_getTs (&msg->cMsg),
  300. head
  301. );
  302. fflush(stdout);
  303. pthread_mutex_unlock(&lock_stdout);
  304. }
  305. }
  306. void log_debug (const char *fmt, ...) {
  307. if (settings.outLevel >= OUTLEVEL_2) {
  308. va_list ap;
  309. va_start(ap, fmt);
  310. pthread_mutex_lock(&lock_stdout);
  311. vfprintf (stdout, fmt, ap);
  312. fflush(stdout);
  313. pthread_mutex_unlock(&lock_stdout);
  314. va_end(ap);
  315. }
  316. }
  317. void log_error (const char *fmt, ...) {
  318. va_list ap;
  319. va_start(ap, fmt);
  320. pthread_mutex_lock(&lock_stderr);
  321. vfprintf (stderr, fmt, ap);
  322. fflush(stderr);
  323. pthread_mutex_unlock(&lock_stderr);
  324. va_end(ap);
  325. }