1+ #include  <furi.h> 
2+ #include  <furi_hal.h> 
3+ #include  <furi_hal_clock.h> 
4+ #include  <furi_hal_pwm.h> 
5+ #include  <gui/gui.h> 
6+ #include  <input/input.h> 
7+ #include  <notification/notification_messages.h> 
8+ #include  <stdio.h> 
9+ 
10+ #define  DEFAULT_FREQ  50
11+ #define  DEFAULT_DUTY  1
12+ 
13+ uint16_t  pWidth  =  1500 ;
14+ int8_t  dir  =  1 ;
15+ 
16+ enum  Modes  {
17+     Manual ,
18+     Center ,
19+     Auto ,
20+ };
21+ 
22+ const  char *  const  modes_text [Auto  +  1 ] =  {
23+     "Manual" ,
24+     "Center" ,
25+     "Auto" ,
26+ };
27+ 
28+ uint8_t  mode  =  Manual ;
29+ 
30+ typedef  enum  {
31+     EventTypeTick ,
32+     EventTypeInput ,
33+ } EventType ;
34+ 
35+ typedef  struct  {
36+     EventType  type ;
37+     InputEvent  input ;
38+ } ServoTesterEvent ;
39+ 
40+ static  void  draw_callback (Canvas *  canvas , void *  ctx ) {
41+     UNUSED (ctx );
42+ 
43+     char  temp_str [36 ];
44+ 
45+     canvas_clear (canvas );
46+     canvas_set_font (canvas , FontPrimary );
47+ 
48+     canvas_draw_frame (canvas , 0 , 0 , 128 , 64 );
49+     canvas_draw_str (canvas , 35 , 10 , "Servo tester" );
50+     canvas_draw_line (canvas , 14 , 30 , 114 , 30 );
51+     canvas_draw_line (canvas , 14 , 30 , 14 , 20 );
52+     canvas_draw_line (canvas , 114 , 30 , 114 , 20 );
53+ 
54+     /* 
55+         14-1000 
56+         104-2000 
57+ 
58+ 
59+ 
60+         (pWidth-1000)/10+10 === 0-1 
61+          
62+ 
63+     */ 
64+     canvas_draw_frame (canvas , (pWidth  -  1000 ) / 10.2  +  14 , 20 , 3 , 10 );
65+ 
66+     snprintf (temp_str , sizeof (temp_str ), "%i us" , pWidth );
67+ 
68+     canvas_draw_str (canvas , 50 , 40 , temp_str );
69+ 
70+     canvas_draw_str (canvas , 50 , 50 , modes_text [mode ]);
71+ }
72+ 
73+ static  void  input_callback (InputEvent *  input_event , void *  ctx ) {
74+     furi_assert (ctx );
75+     FuriMessageQueue *  event_queue  =  ctx ;
76+     ServoTesterEvent  event  =  {.type  =  EventTypeInput , .input  =  * input_event };
77+     furi_message_queue_put (event_queue , & event , FuriWaitForever );
78+ }
79+ 
80+ static  void  timer_callback (FuriMessageQueue *  event_queue ) {
81+     furi_assert (event_queue );
82+ 
83+     ServoTesterEvent  event  =  {.type  =  EventTypeTick };
84+     furi_message_queue_put (event_queue , & event , 0 );
85+ }
86+ 
87+ void  setServoPWM (uint32_t  freq , uint32_t  compare ) {
88+     uint32_t  freq_div  =  64000000LU  / freq ;
89+     uint32_t  prescaler  =  freq_div  / 0x10000LU ;
90+     uint32_t  period  =  freq_div  / (prescaler  +  1 );
91+ 
92+     LL_TIM_SetPrescaler (TIM1 , prescaler );
93+     LL_TIM_SetAutoReload (TIM1 , period  -  1 );
94+     LL_TIM_OC_SetCompareCH1 (TIM1 , compare );
95+ }
96+ 
97+ void  updatePwm () {
98+     setServoPWM (DEFAULT_FREQ , pWidth  *  3.2 );
99+ }
100+ 
101+ int32_t  servotester_app (void *  p ) {
102+     UNUSED (p );
103+ 
104+     ServoTesterEvent  event ;
105+ 
106+     FuriMessageQueue *  event_queue  =  furi_message_queue_alloc (8 , sizeof (ServoTesterEvent ));
107+ 
108+     ViewPort *  view_port  =  view_port_alloc ();
109+ 
110+     // callbacks init 
111+     view_port_draw_callback_set (view_port , draw_callback , NULL );
112+     view_port_input_callback_set (view_port , input_callback , event_queue );
113+ 
114+     Gui *  gui  =  furi_record_open (RECORD_GUI );
115+     gui_add_view_port (gui , view_port , GuiLayerFullscreen );
116+ 
117+     FuriTimer *  timer  =  furi_timer_alloc (timer_callback , FuriTimerTypePeriodic , event_queue );
118+     furi_timer_start (timer , 5 );
119+ 
120+     //GPIO init 
121+     furi_hal_power_enable_otg ();
122+     furi_hal_pwm_start (FuriHalPwmOutputIdTim1PA7 , 50 , 4 );
123+     setServoPWM (DEFAULT_FREQ , pWidth  *  3.2 );
124+ 
125+     while (1 ) {
126+         furi_check (furi_message_queue_get (event_queue , & event , FuriWaitForever ) ==  FuriStatusOk );
127+         if (event .type  ==  EventTypeInput ) {
128+             if (event .input .key  ==  InputKeyBack ) {
129+                 furi_hal_power_disable_otg ();
130+                 furi_hal_pwm_stop (FuriHalPwmOutputIdTim1PA7 );
131+                 break ;
132+             } else  if (event .input .key  ==  InputKeyOk ) {
133+                 if (event .input .type  ==  InputTypeRelease ) {
134+                     if (mode  ==  Auto ) {
135+                         mode  =  Manual ;
136+                     } else  {
137+                         mode ++ ;
138+                     }
139+ 
140+                     if (mode  ==  Center ) {
141+                         pWidth  =  1500 ;
142+                         updatePwm ();
143+                     }
144+                 }
145+             } else  if (event .input .key  ==  InputKeyLeft ) {
146+                 if (pWidth  >  1000 ) pWidth -- ;
147+                 updatePwm ();
148+             } else  if (event .input .key  ==  InputKeyRight ) {
149+                 if (pWidth  <  2000 ) pWidth ++ ;
150+                 updatePwm ();
151+             } else  if (event .input .key  ==  InputKeyDown ) {
152+                 if (pWidth  >= 1010 ) pWidth  -=  10 ;
153+                 updatePwm ();
154+             } else  if (event .input .key  ==  InputKeyUp ) {
155+                 if (pWidth  <= 1990 ) pWidth  +=  10 ;
156+                 updatePwm ();
157+             }
158+         } else  if (event .type  ==  EventTypeTick ) {
159+             if (mode  ==  Auto ) {
160+                 pWidth  +=  dir ;
161+                 if (pWidth  >  1990  ||  pWidth  <  1010 ) {
162+                     dir  =  dir  *  -1 ;
163+                 }
164+                 updatePwm ();
165+             }
166+         }
167+     }
168+ 
169+     furi_timer_free (timer );
170+     furi_message_queue_free (event_queue );
171+ 
172+     gui_remove_view_port (gui , view_port );
173+     view_port_free (view_port );
174+     furi_record_close (RECORD_GUI );
175+ 
176+     return  0 ;
177+ }
0 commit comments