1 /* This is a small demo of the high-performance GUIX graphics framework. */
2
3 #include <stdio.h>
4 #include "gx_api.h"
5
6 #include "guix_medical_resources.h"
7 #include "guix_medical_specifications.h"
8 #include "demo_guix_medical.h"
9
10 /* Define timer ids. */
11 #define EKG_WAVEFORM_TIMER 2
12 #define PULSE_WAVEFORM_TIMER 3
13 #define HEART_RATE_TIMER 4
14 #define SPO2_TIMER 5
15 #define VALUE_ANIMATION_TIMER 6
16
17 /* Define constants. */
18 #define CHART_SCROLL 4
19 #define VALUE_ANIOMATION_TOTAL_STEPS 10
20
21 #define CARDIO_DOT_WIDTH 9
22 #define CARDIO_DOT_HEIGHT 10
23
24 /* Define a macro to calculate the current value according to the animation step. */
25 #define GET_NEW_VALUE(info) (info.start_value + (info.end_value - info.current_value) * value_animation_step / VALUE_ANIOMATION_TOTAL_STEPS)
26
27 /* Define a waveform information structure for waveform drawing. */
28 typedef struct WAVE_INFO_STRUCT
29 {
30 GX_COLOR *capture_memory;
31 INT capture_memory_size;
32 INT capture_xpos;
33 INT capture_ypos;
34 INT *value_array;
35 INT total_values;
36 INT index;
37 INT retrace_xpos;
38 GX_RESOURCE_ID color_id;
39 }WAVE_INFO;
40
41 /* Define a value information structure for value animation. */
42 typedef struct VALUE_INFO_STRUCT
43 {
44 INT start_value;
45 INT end_value;
46 INT current_value;
47 }VALUE_INFO;
48
49 /* Define ekg waveform values. */
50 INT ekg_values[] = {
51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 5, 4, 2, 0, 0, 0, 0, -3, 30, -7, 0, 0, 0, 0, 5, 8, 10, 8, 5
52 };
53
54 /* Define pulse waveform values. */
55 INT pulse_values[] = {
56 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 5, 4, 2, 0, 0, 0, 0, -3, 30, -7, 0, 0, 0, 0, 5, 8, 10, 8, 5
57 };
58
59 /* Define heart rate values. */
60 INT heart_rate_values[] = {
61 88, 87, 86, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 94, 93, 92, 90, 89
62 };
63
64 /* Define spo2 values. */
65 INT spo2_values[] = {
66 94, 95, 96, 97, 96, 95, 94, 93
67 };
68
69 /* Define waveform capture memory. */
70 GX_COLOR ekg_capture_memory[CARDIO_DOT_WIDTH * CARDIO_DOT_HEIGHT];
71 GX_COLOR pulse_capture_memory[CARDIO_DOT_WIDTH * CARDIO_DOT_HEIGHT];
72
73 /* Define and initialize ekg waveform information instance. */
74 WAVE_INFO ekg_wave_info = {
75 ekg_capture_memory,
76 CARDIO_DOT_WIDTH* CARDIO_DOT_HEIGHT * sizeof(GX_COLOR),
77 0,
78 0,
79 ekg_values,
80 (INT)(sizeof(ekg_values) / sizeof(INT)),
81 0,
82 0,
83 GX_COLOR_ID_GREEN
84 };
85
86 /* Define and initialize pulse waveform information instance. */
87 WAVE_INFO pulse_wave_info = {
88 pulse_capture_memory,
89 CARDIO_DOT_WIDTH* CARDIO_DOT_HEIGHT * sizeof(GX_COLOR),
90 0,
91 0,
92 pulse_values,
93 (INT)(sizeof(pulse_values) / sizeof(INT)),
94 0,
95 0,
96 GX_COLOR_ID_BLUE
97 };
98
99 INT heart_rate_index = 0;
100 INT spo2_index = 0;
101 INT value_animation_step = 0;
102 VALUE_INFO insulin = { 48, 71, 48 };
103 VALUE_INFO heart_rate = { 0, 88, 0 };
104 VALUE_INFO spo2 = { 0, 94, 0 };
105 VALUE_INFO medtype1 = { 0, 55, 0 };
106 VALUE_INFO medtype2 = { 0, 25, 0 };
107 VALUE_INFO medtype3 = { 0, 45, 0 };
108
109 /* Define prototypes. */
110 extern VOID GetPatientName(GX_STRING* string);
111 extern VOID GetPatientDOB(GX_STRING* string);
112 extern VOID GetPatientAge(INT* age);
113
114 /******************************************************************************************/
115 /* Capture canvas under cardio dot. */
116 /******************************************************************************************/
capture_memory(GX_CANVAS * canvas,WAVE_INFO * info)117 static VOID capture_memory(GX_CANVAS *canvas, WAVE_INFO *info)
118 {
119 GX_COLOR *get;
120 GX_COLOR *put;
121 INT copy_width;
122 INT y;
123
124 get = canvas->gx_canvas_memory;
125 get += info->capture_ypos * canvas->gx_canvas_x_resolution;
126 get += info->capture_xpos;
127
128 put = info->capture_memory;
129 copy_width = CARDIO_DOT_WIDTH * sizeof(GX_COLOR);
130
131 for (y = 0; y < CARDIO_DOT_HEIGHT; y++)
132 {
133 memcpy(put, get, copy_width);
134
135 put += CARDIO_DOT_WIDTH;
136 get += canvas->gx_canvas_x_resolution;
137 }
138 }
139
140 /******************************************************************************************/
141 /* Restore canvas under cardio dot. */
142 /******************************************************************************************/
restore_memory(GX_CANVAS * canvas,WAVE_INFO * info)143 static VOID restore_memory(GX_CANVAS *canvas, WAVE_INFO *info)
144 {
145 GX_PIXELMAP pixelmap;
146
147 memset(&pixelmap, 0, sizeof(GX_PIXELMAP));
148 pixelmap.gx_pixelmap_data = (GX_UBYTE *)info->capture_memory;
149 pixelmap.gx_pixelmap_data_size = info->capture_memory_size;
150 pixelmap.gx_pixelmap_width = CARDIO_DOT_WIDTH;
151 pixelmap.gx_pixelmap_height = CARDIO_DOT_HEIGHT;
152 pixelmap.gx_pixelmap_format = GX_COLOR_FORMAT_24XRGB;
153
154 gx_canvas_pixelmap_draw(info->capture_xpos, info->capture_ypos, &pixelmap);
155 }
156
157 /******************************************************************************************/
158 /* Update waveform. */
159 /******************************************************************************************/
update_waveform(GX_WINDOW * win,WAVE_INFO * info)160 static VOID update_waveform(GX_WINDOW *win, WAVE_INFO *info)
161 {
162 GX_CANVAS *canvas;
163 GX_PIXELMAP *map;
164 GX_RECTANGLE *chart_area;
165 INT xpos;
166 INT ycenter;
167 INT line_start_offset;
168 INT line_end_offset;
169
170 chart_area = &win->gx_window_client;
171
172 /* pick up the canvas pointer. */
173 gx_widget_canvas_get(win, &canvas);
174
175 /* Initiate drawing on this canvas. */
176 gx_canvas_drawing_initiate(canvas, win, chart_area);
177
178 /* Erase the rectangle ahead of the line. */
179 xpos = chart_area->gx_rectangle_left + info->retrace_xpos + 10;
180 gx_context_pixelmap_get(GX_PIXELMAP_ID_CHART_ERASE, &map);
181 gx_context_fill_color_set(GX_COLOR_ID_CANVAS);
182 gx_canvas_pixelmap_draw(xpos, chart_area->gx_rectangle_top, map);
183
184 if (xpos + map->gx_pixelmap_width > chart_area->gx_rectangle_right)
185 {
186 gx_canvas_pixelmap_draw(chart_area->gx_rectangle_left + xpos - chart_area->gx_rectangle_right,
187 chart_area->gx_rectangle_top, map);
188 }
189
190 xpos = chart_area->gx_rectangle_left +info->retrace_xpos;
191
192 /* Define brush for line draw. */
193 gx_context_brush_define(info->color_id, info->color_id, GX_BRUSH_SOLID_FILL | GX_BRUSH_ROUND | GX_BRUSH_ALIAS);
194 gx_context_brush_width_set(2);
195
196 ycenter = (chart_area->gx_rectangle_top + chart_area->gx_rectangle_bottom) >> 1;
197 line_start_offset = info->value_array[info->index++];
198 if (info->index >= info->total_values)
199 {
200 info->index = 0;
201 }
202 line_end_offset = info->value_array[info->index];;
203
204 /* Restore canvas under previous cardio dot. */
205 restore_memory(canvas, info);
206
207 gx_canvas_line_draw(xpos, ycenter - line_start_offset, xpos + CHART_SCROLL, ycenter - line_end_offset);
208
209 /* Draw cardio dot. */
210 gx_context_fill_color_set(info->color_id);
211 info->capture_xpos = xpos + CHART_SCROLL - (CARDIO_DOT_WIDTH / 2);
212 info->capture_ypos = ycenter - line_end_offset - (CARDIO_DOT_HEIGHT / 2);
213
214 /* Capture canvas under new cardio dot. */
215 capture_memory(canvas, info);
216
217 /* Draw cardio dot. */
218 gx_context_pixelmap_get(GX_PIXELMAP_ID_CARDIO_DOT, &map);
219 gx_canvas_pixelmap_draw(info->capture_xpos, info->capture_ypos, map);
220
221 /* Indicate that drawing on this canvas is complete. */
222 gx_canvas_drawing_complete(canvas, GX_TRUE);
223
224 info->retrace_xpos += CHART_SCROLL;
225
226 if (chart_area->gx_rectangle_left + info->retrace_xpos + CHART_SCROLL > chart_area->gx_rectangle_right)
227 {
228 info->retrace_xpos = 0;
229 }
230 }
231
232 /******************************************************************************************/
233 /* Update heart rate. */
234 /******************************************************************************************/
update_heart_rate()235 static VOID update_heart_rate()
236 {
237 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_hr_value, heart_rate_values[heart_rate_index++]);
238
239 if (heart_rate_index > (sizeof(heart_rate_values) / sizeof(INT)))
240 {
241 heart_rate_index = 0;
242 }
243 }
244
245 /******************************************************************************************/
246 /* Update spo2 value. */
247 /******************************************************************************************/
update_spo2()248 static VOID update_spo2()
249 {
250 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_spo2_value, spo2_values[spo2_index++]);
251
252 if (spo2_index > (sizeof(spo2_values) / sizeof(INT)))
253 {
254 spo2_index = 0;
255 }
256 }
257
258 /******************************************************************************************/
259 /* Start value animation. */
260 /******************************************************************************************/
start_value_animation()261 static VOID start_value_animation()
262 {
263 gx_system_timer_start((GX_WIDGET*)&vitals_screen, VALUE_ANIMATION_TIMER, 200 / GX_SYSTEM_TIMER_MS, 40 / GX_SYSTEM_TIMER_MS);
264
265 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_insulin_value, insulin.start_value);
266 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_hr_value, heart_rate.start_value);
267 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_spo2_value, spo2.start_value);
268 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_medtype1_value, medtype1.start_value);
269 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_medtype2_value, medtype2.start_value);
270 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_medtype3_value, medtype3.start_value);
271 gx_slider_value_set((GX_SLIDER *)&vitals_screen.vitals_screen_medtype1_slider, &vitals_screen.vitals_screen_medtype1_slider.gx_slider_info, medtype1.start_value);
272 gx_slider_value_set((GX_SLIDER*)&vitals_screen.vitals_screen_medtype2_slider, &vitals_screen.vitals_screen_medtype2_slider.gx_slider_info, medtype2.start_value);
273 gx_slider_value_set((GX_SLIDER*)&vitals_screen.vitals_screen_medtype3_slider, &vitals_screen.vitals_screen_medtype3_slider.gx_slider_info, medtype3.start_value);
274
275 value_animation_step = 0;
276 }
277
278 /******************************************************************************************/
279 /* Update value animation. */
280 /******************************************************************************************/
update_value_animation()281 static VOID update_value_animation()
282 {
283 INT new_value;
284
285 value_animation_step++;
286
287 new_value = GET_NEW_VALUE(insulin);
288 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_insulin_value, new_value);
289
290 new_value = GET_NEW_VALUE(heart_rate);
291 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_hr_value, new_value);
292
293 new_value = GET_NEW_VALUE(spo2);
294 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_spo2_value, new_value);
295
296 new_value = GET_NEW_VALUE(medtype1);
297 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_medtype1_value, new_value);
298 gx_slider_value_set((GX_SLIDER*)&vitals_screen.vitals_screen_medtype1_slider, &vitals_screen.vitals_screen_medtype1_slider.gx_slider_info, new_value);
299
300 new_value = GET_NEW_VALUE(medtype2);
301 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_medtype2_value, medtype2.start_value);
302 gx_slider_value_set((GX_SLIDER*)&vitals_screen.vitals_screen_medtype2_slider, &vitals_screen.vitals_screen_medtype2_slider.gx_slider_info, new_value);
303
304 new_value = GET_NEW_VALUE(medtype3);
305 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_medtype3_value, medtype3.start_value);
306 gx_slider_value_set((GX_SLIDER*)&vitals_screen.vitals_screen_medtype3_slider, &vitals_screen.vitals_screen_medtype3_slider.gx_slider_info, new_value);
307
308 if (value_animation_step == VALUE_ANIOMATION_TOTAL_STEPS)
309 {
310 gx_system_timer_stop((GX_WIDGET*)&vitals_screen, VALUE_ANIMATION_TIMER);
311 }
312 }
313
314 /******************************************************************************************/
315 /* Start ekg waveform drawing. */
316 /******************************************************************************************/
start_ekg_waveform()317 static VOID start_ekg_waveform()
318 {
319 ekg_wave_info.index = 0;
320 ekg_wave_info.retrace_xpos = 0;
321 memset(ekg_wave_info.capture_memory, 0, ekg_wave_info.capture_memory_size);
322
323 gx_system_timer_start((GX_WIDGET*)&vitals_screen, EKG_WAVEFORM_TIMER, 80 / GX_SYSTEM_TIMER_MS, 80 / GX_SYSTEM_TIMER_MS);
324 gx_system_timer_start((GX_WIDGET*)&vitals_screen, HEART_RATE_TIMER, GX_TICKS_SECOND * 2, GX_TICKS_SECOND * 2);
325 }
326
327 /******************************************************************************************/
328 /* Start pulse waveform drawing. */
329 /******************************************************************************************/
start_pulse_waveform()330 static VOID start_pulse_waveform()
331 {
332 pulse_wave_info.index = 0;
333 pulse_wave_info.retrace_xpos = 0;
334 memset(pulse_wave_info.capture_memory, 0, pulse_wave_info.capture_memory_size);
335
336 gx_system_timer_start((GX_WIDGET *)&vitals_screen, PULSE_WAVEFORM_TIMER, 80 / GX_SYSTEM_TIMER_MS, 80 / GX_SYSTEM_TIMER_MS);
337 gx_system_timer_start((GX_WIDGET*)&vitals_screen, SPO2_TIMER, GX_TICKS_SECOND, GX_TICKS_SECOND);
338 }
339
340 /******************************************************************************************/
341 /* Update patient information. */
342 /******************************************************************************************/
update_patient_information()343 static VOID update_patient_information()
344 {
345 GX_STRING string;
346 INT age;
347
348 /* Get patient's name. */
349 GetPatientName(&string);
350
351 /* Set patient's name. */
352 gx_prompt_text_set_ext(&vitals_screen.vitals_screen_patient_name, &string);
353
354 /* Get patient's date of birth. */
355 GetPatientDOB(&string);
356
357 /* Set patient's date of birth. */
358 gx_prompt_text_set_ext(&vitals_screen.vitals_screen_patient_dob, &string);
359
360 /* Get patient's age. */
361 GetPatientAge(&age);
362
363 /* Set patient's age. */
364 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_patient_age, age);
365 }
366
367 /******************************************************************************************/
368 /* Override the default event processing of "vitals_screen" to handle signals from my */
369 /* child widgets. */
370 /******************************************************************************************/
vitals_screen_event_process(GX_WINDOW * window,GX_EVENT * myevent)371 UINT vitals_screen_event_process(GX_WINDOW *window, GX_EVENT *myevent)
372 {
373 UINT status = GX_SUCCESS;
374
375 switch(myevent->gx_event_type)
376 {
377 case GX_EVENT_SHOW:
378
379 /* Call the event process of the template on which the vitals screen is based. */
380 template_event_handler(window, myevent);
381
382 /* Update patient's information. */
383 update_patient_information();
384
385 /* Start value animation. */
386 start_value_animation();
387 break;
388
389 case GX_EVENT_HIDE:
390
391 /* Call the event process of the template on which the vitals screen is based. */
392 template_event_handler(window, myevent);
393
394 /* Stop all timers that belongs to the window. */
395 gx_system_timer_stop((GX_WIDGET*)window, 0);
396 break;
397
398 case GX_SIGNAL(ID_MEDTYPE1_SLIDER, GX_EVENT_SLIDER_VALUE):
399 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_medtype1_value, myevent->gx_event_payload.gx_event_longdata);
400 break;
401
402 case GX_SIGNAL(ID_MEDTYPE2_SLIDER, GX_EVENT_SLIDER_VALUE):
403 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_medtype2_value, myevent->gx_event_payload.gx_event_longdata);
404 break;
405
406 case GX_SIGNAL(ID_MEDTYPE3_SLIDER, GX_EVENT_SLIDER_VALUE):
407 gx_numeric_prompt_value_set(&vitals_screen.vitals_screen_medtype3_value, myevent->gx_event_payload.gx_event_longdata);
408 break;
409
410 case GX_EVENT_TIMER:
411 switch(myevent ->gx_event_payload.gx_event_timer_id)
412 {
413 case EKG_WAVEFORM_TIMER:
414 update_waveform(&vitals_screen.vitals_screen_ekg_waveform_win, &ekg_wave_info);
415 break;
416
417 case PULSE_WAVEFORM_TIMER:
418 update_waveform(&vitals_screen.vitals_screen_pulse_waveform_win, &pulse_wave_info);
419 break;
420
421 case HEART_RATE_TIMER:
422 update_heart_rate();
423 break;
424
425 case SPO2_TIMER:
426 update_spo2();
427 break;
428
429 case VALUE_ANIMATION_TIMER:
430 update_value_animation();
431 break;
432 }
433 break;
434
435 case GX_EVENT_ANIMATION_COMPLETE:
436 if (myevent->gx_event_sender == ID_EKG_WIN_SLIDE_IN)
437 {
438 start_ekg_waveform();
439 }
440 else if (myevent->gx_event_sender = ID_PULSE_WIN_SLIDE_IN)
441 {
442 start_pulse_waveform();
443 }
444 break;
445
446 default:
447 status = template_event_handler(window, myevent);
448 }
449 return status;
450 }
451
452 /******************************************************************************************/
453 /* Callback function to format insulin value. */
454 /******************************************************************************************/
insulin_value_format(GX_NUMERIC_PROMPT * prompt,INT value)455 VOID insulin_value_format(GX_NUMERIC_PROMPT *prompt, INT value)
456 {
457 prompt->gx_numeric_prompt_buffer[0] = '0';
458 prompt->gx_numeric_prompt_buffer[1] = '.';
459 gx_utility_ltoa(value, prompt->gx_numeric_prompt_buffer + 2, GX_NUMERIC_PROMPT_BUFFER_SIZE - 1);
460 }
461
462
463