U.B.O.R
The [U]seless [B]ox [O]rganizing [R]obot. A FreeRTOS study project written in C which implements a multitasked control unit for a belt conveyor system with robotic sorting arms.
display.c
Go to the documentation of this file.
1 
6 
7 
8 /*****************************************************************************
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23  * MA 02110-1301, USA.
24  *
25  *****************************************************************************/
26 #include "display.h"
27 #include <FreeRTOS.h>
28 #include <stdio.h>
29 #include <task.h>
30 #include <queue.h>
31 #include <lcd.h>
32 #include <stdbool.h>
33 #include <string.h>
34 #include <semphr.h>
35 
36 
37 // -------------------- Configuration ------------
38 #define STACKSIZE_TASK ( 256 )
39 #define PRIORITY_TASK ( 3 )
40 
41 #define QUEUE_SIZE 10
42 
43 #define DISPLAY_LINES 30
44 #define DISPLAY_CHARS 64
45 
46 
47 // ------------------ Implementation ------------------------
48 
52 typedef struct {
53  const char* taskname;
54  uint8_t id;
55  char message[DISPLAY_CHARS+1];
57 
58 static uint8_t last_given_id = 0;
59 static QueueHandle_t display_queue;
60 static SemaphoreHandle_t display_id_mutex;
61 
70 uint8_t display_log(uint8_t id, const char *fmtstr, ...)
71 {
72  log_message_t msg; //Buffer for message. must be on stack (multi-task env)
73 
74  //Generate string from formatstring + arguments
75  va_list args;
76  va_start (args, fmtstr);
77  vsprintf(msg.message,fmtstr, args);
78  va_end(args);
79 
80  msg.taskname = pcTaskGetName(xTaskGetCurrentTaskHandle());
81 
82 
83  //Assign a new id to the message
84  uint8_t newId;
85 
86  xSemaphoreTake(display_id_mutex,portMAX_DELAY);
87 
88  if(id == DISPLAY_NEWLINE) {
89  newId = ++last_given_id;
90  if(last_given_id == 0xFF) {
91  last_given_id = 0;
92  }
93  } else {
94  newId = id;
95  }
96  xSemaphoreGive(display_id_mutex);
97 
98 
99  msg.id = newId;
100 
101  //Send message to display task
102  xQueueSend(display_queue, &msg, portMAX_DELAY );
103 
104  return newId;
105 
106 }
107 
108 
116 static void display_print_message(uint8_t line, log_message_t* msg)
117 {
118  uint8_t x=0;
119 
120  //Print task name in gray
121  LCD_SetTextColor(GUI_COLOR_LIGHT_GRAY);
122  const char* charPtr = msg->taskname;
123  while(*charPtr!=0) {
124  LCD_DisplayCharLine(line,x++,*charPtr++);
125  }
126  LCD_DisplayCharLine(line,x++,':');
127  LCD_DisplayCharLine(line,x++,' ');
128 
129  //Print message
130  LCD_SetTextColor(GUI_COLOR_WHITE);
131  charPtr = msg->message;
132  while(*charPtr!=0) {
133  LCD_DisplayCharLine(line,x++,*charPtr++);
134  }
135 
136  while(x<DISPLAY_CHARS) {
137  LCD_DisplayCharLine(line,x++,' ');
138  }
139 }
140 
141 
142 uint8_t visible_messages=0;
143 uint8_t buffer_offset = 0;
145 
146 
152 static void display_task()
153 {
154 
155  while(true) {
156  uint8_t top_id = message_buffer[buffer_offset].id;
157  uint8_t bottom_id = message_buffer[(buffer_offset + visible_messages -1 )%DISPLAY_LINES].id;
158  static log_message_t tmp_message;
159  xQueueReceive(display_queue,&tmp_message,portMAX_DELAY);
160  uint8_t new_id = tmp_message.id;
161 
162  //Check if message has the same id as a message that is currently beeing displayed
163  if((top_id <= bottom_id && new_id >= top_id && new_id <= bottom_id) ||
164  (top_id > bottom_id && new_id >= top_id)) {
165  //Replace message
166  uint8_t replace_buffer_index =(buffer_offset + (new_id-top_id)) % DISPLAY_LINES;
167  memcpy(&message_buffer[replace_buffer_index],&tmp_message,sizeof(log_message_t));
168  display_print_message(new_id-top_id, &message_buffer[replace_buffer_index]);
169  } else if(top_id > bottom_id && new_id <= bottom_id ) {
170  //Replace message (and handle index wraping)
171  uint8_t replace_buffer_index =(buffer_offset + visible_messages -1 - (bottom_id-new_id)) % DISPLAY_LINES;
172  memcpy(&message_buffer[replace_buffer_index],&tmp_message,sizeof(log_message_t));
173  display_print_message(visible_messages -1 - (bottom_id-new_id), &message_buffer[replace_buffer_index]);
174  } else { //message is new
176  memcpy(&message_buffer[buffer_offset],&tmp_message,sizeof(log_message_t));
177  buffer_offset = (buffer_offset +1) % DISPLAY_LINES;
178  for(uint8_t i =0; i< DISPLAY_LINES; i++) {
179  uint8_t buffer_index = (buffer_offset + i) % DISPLAY_LINES;
180  display_print_message(i,&message_buffer[buffer_index]);
181  }
182  } else { // Display not full yet
183  uint8_t buffer_index = (buffer_offset + visible_messages) % DISPLAY_LINES;
184  memcpy(&message_buffer[buffer_index],&tmp_message,sizeof(log_message_t));
185  display_print_message(visible_messages,&message_buffer[buffer_index]);
187  }
188  }
189  }
190 }
191 
192 
193 
200 {
201  LCD_Init();
202  LCD_Clear(GUI_COLOR_BLACK);
203  xTaskCreate(display_task,
204  "Display Task",
206  NULL,
208  NULL);
209 
210  display_queue = xQueueCreate(QUEUE_SIZE,sizeof(log_message_t));
211  display_id_mutex = xSemaphoreCreateMutex();
212 
213 }
214 
#define DISPLAY_NEWLINE
Definition: display.h:10
#define QUEUE_SIZE
Size of the message queue.
Definition: display.c:41
const char * taskname
Name of the task that wrote the message.
Definition: display.c:53
#define STACKSIZE_TASK
Stack size of the display task.
Definition: display.c:38
uint8_t buffer_offset
Offset in the message_buffer to get to the top message.
Definition: display.c:143
char message[DISPLAY_CHARS+1]
Message (formatted)
Definition: display.c:55
#define DISPLAY_CHARS
Number of horizontal characters that can be displayed.
Definition: display.c:44
uint8_t id
Id that was assigned to the task.
Definition: display.c:54
#define PRIORITY_TASK
Priority of the Display task (low priority number denotes low priority task)
Definition: display.c:39
void display_init()
Initializes the display and starts the display task global.
Definition: display.c:199
uint8_t visible_messages
Number of currently visible messages.
Definition: display.c:142
log_message_t message_buffer[DISPLAY_LINES]
buffer of all visible messages (ring buffer!)
Definition: display.c:144
uint8_t display_log(uint8_t id, const char *fmtstr,...)
Logs a message to the display global.
Definition: display.c:70
#define DISPLAY_LINES
Number of lines that fit on the display (vertically)
Definition: display.c:43
Structure to describe a log message.
Definition: display.c:52