A messenger application for Raspberry Pi Zerofor A.U.TH (Real time Embedded systems).
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 

376 Zeilen
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. }