44 * Created on: Dec 25, 2020
55 * Author: andrey
66 */
7+ #include < ctype.h>
78#include < stdarg.h>
89#include " board.h"
910#include " usbd_cdc_if.h"
1011#include " spi1106.h"
12+ #include " settings.h"
1113
1214extern I2C_HandleTypeDef hi2c1;
15+ extern USBD_HandleTypeDef hUsbDeviceFS;
1316
1417static volatile bool i2c_tx_completed = false ;
1518static volatile bool i2c_rx_completed = false ;
1619
20+ const uint32_t flash_settings_page = 0x0800F7C2 ;
21+ static settings current_settings;
22+
23+ const auto app_title = " TCS34725 PAR meter 1.1" ;
24+
1725void HAL_I2C_MasterTxCpltCallback (I2C_HandleTypeDef *hi2c)
1826{
1927 i2c_tx_completed = true ;
@@ -81,14 +89,26 @@ uint32_t i2c_read_word(uint8_t reg)
8189 return (uint32_t )(res[1 ] << 8 ) + (uint32_t )res[0 ];
8290}
8391
84- char log_buf[256 ];
92+ const uint32_t log_buf_size = 512 ;
93+ char log_buf[log_buf_size];
8594
8695void log (const char * format, ...)
8796{
97+ auto hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData ;
98+ if (hcdc == nullptr )
99+ {
100+ return ;
101+ }
102+
88103 va_list args;
89104 va_start (args, format);
90- int nn = vsnprintf (log_buf, 256 , format, args);
105+ int nn = vsnprintf (log_buf, log_buf_size , format, args);
91106 va_end (args);
107+
108+ while (hcdc->TxState != 0 )
109+ {
110+ HAL_Delay (1 );
111+ }
92112 CDC_Transmit_FS ((uint8_t *)log_buf, nn);
93113}
94114
@@ -99,7 +119,7 @@ void read_par()
99119 auto green = i2c_read_word (0x18 );
100120 auto blue = i2c_read_word (0x1a );
101121
102- log (" w:%d r:%d g:%d b:%d\n\r " , white, red, green, blue);
122+ // log("w:%d r:%d g:%d b:%d\n\r", white, red, green, blue);
103123
104124 const uint32_t buf_size = 64 ;
105125 uint8_t y = 2 ;
@@ -117,40 +137,282 @@ void read_par()
117137 snprintf (buf, buf_size, " B %d " , (int )blue);
118138 sh1106SmallPrint (0 , y++, (uint8_t *)buf);
119139
120- double par = (double )white * (double )0.045067 ;
140+ double par = current_settings.m_total_factor * current_settings.calc_normalized_from_raw (white, red, green, blue);
141+ // double par = (double)white * (double)0.045067;
121142 int ipar = par;
122143 snprintf (buf, buf_size, " %d " , ipar);
123144 sh1106MediumPrint (0 , y++, (uint8_t *)buf);
124145}
125146
126- void main_loop ( void )
147+ void send_status ( )
127148{
128- sh1106Init (40 ,0x22 ,1 );
129- sh1106Clear (0 ,7 );
130- sh1106SmallPrint (0 , 0 , (uint8_t *) " TCS34725 PAR meter 1.0" );
149+ log (" \n\r\n\r %s build %s %s\n\r " , app_title, __DATE__, __TIME__);
150+
151+ auto chip_id = i2c_read_register (0x12 );
152+ log (" chip id:%X\n\r " , chip_id);
131153
132- // sh1106MediumPrint(0,1,(uint8_t *) "Hi SH1106");
133- // sh1106MediumPrint(0,3,(uint8_t *) "Hello SH1106");
154+ log (" Integration time %x %lfms\n\r " , current_settings.m_integration_time , current_settings.get_integration_time ());
155+ log (" Wait time %x %lfms\n\r " , current_settings.m_wait_time , current_settings.get_wait_time ());
156+ log (" Gain %x x%lf\n\r " , current_settings.m_gain , current_settings.get_gain ());
157+ log (" PAR = K[%lf] * W[%lf] * R[%lf] * G[%lf] * B[%lf]\n\r " ,
158+ current_settings.m_total_factor ,
159+ current_settings.m_white ,
160+ current_settings.m_red ,
161+ current_settings.m_green ,
162+ current_settings.m_blue );
163+ log (" Usage:\n\r " );
164+ log (" k <value> - set K factor\n\r " );
165+ log (" w <value> - set W factor, 0..1\n\r " );
166+ log (" r <value> - set R factor, 0..1\n\r " );
167+ log (" g <value> - set G factor, 0..1\n\r " );
168+ log (" b <value> - set B factor, 0..1\n\r " );
169+ log (" int <value> - set integration time, 0..255\n\r " );
170+ log (" wait <value> - set wait time, 0..255\n\r " );
171+ log (" gain <value> - set gain, 0..3\n\r " );
172+ log (" def - reset to defaults\n\r " );
173+ log (" flash - write changes to flash\n\r " );
174+ log (" par <par value> <raw w> <raw r> <raw g> <raw b>\n\r " );
175+ log (" - calculate K factor from measured PAR\n\r " );
176+ }
134177
135- HAL_GPIO_WritePin (GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
136- HAL_Delay (1000 );
178+ const uint32_t cmd_buf_size = 512 ;
179+ char cmd_buf[cmd_buf_size];
180+ char current_cmd_buf[cmd_buf_size];
181+ uint32_t cmd_input_size = 0 ;
182+ char * current_cmd = nullptr ;
137183
138- HAL_GPIO_WritePin (GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
139- HAL_Delay (1000 );
184+ void process_cdc_input (char c)
185+ {
186+ c = tolower (c);
140187
141- CDC_Transmit_FS ((uint8_t *)" TCS34725 PAR meter 1.0\n\r " , 39 );
188+ if (c == ' \r ' )
189+ {
190+ cmd_buf[cmd_input_size] = 0 ;
142191
143- auto chip_id = i2c_read_register (0x12 );
144- log (" chip id:%X\n\r " , chip_id);
192+ memcpy (current_cmd_buf, cmd_buf, cmd_input_size + 1 );
193+ current_cmd = current_cmd_buf;
194+
195+ cmd_input_size = 0 ;
196+ }
197+ else if (c == ' \b ' )
198+ {
199+ if (cmd_input_size > 0 ) cmd_input_size--;
200+ }
201+ else
202+ {
203+ cmd_buf[cmd_input_size] = c;
204+ cmd_input_size++;
205+ }
145206
207+ if (cmd_input_size >= cmd_buf_size)
208+ {
209+ cmd_input_size = 0 ;
210+ }
211+ }
212+
213+ void CDC_OnDataReceived (uint8_t * pbuf, uint32_t *Len)
214+ {
215+ CDC_Transmit_FS (pbuf, *Len);
216+
217+ for (uint32_t i = 0 ; i < *Len; i++)
218+ {
219+ process_cdc_input ((char )pbuf[i]);
220+ }
221+ }
222+
223+ bool starts (const char * buf, const char * probe)
224+ {
225+ auto probe_len = strlen (probe);
226+ return strncmp (buf, probe, probe_len) == 0 ;
227+ }
228+
229+ bool factor_cmd (const char * buf, const char * probe, double * factor)
230+ {
231+ auto probe_len = strlen (probe);
232+
233+ if (strncmp (buf, probe, probe_len) != 0 )
234+ {
235+ return false ;
236+ }
237+
238+ double k = 0 ;
239+ if (sscanf (buf + probe_len, " %lf" , &k) < 1 )
240+ {
241+ log (" \n\r error\n\r " );
242+ send_status ();
243+ return true ;
244+ }
245+ *factor = k;
246+ log (" \n\r ok\n\r " );
247+ return true ;
248+ }
249+
250+ void init_tcs ()
251+ {
146252 i2c_write_register (0x00 , 0x03 );
147- i2c_write_register (0x01 , 0xf6 );
148- i2c_write_register (0x03 , 0xf6 );
149- i2c_write_register (0x0f , 0x00 );
253+ i2c_write_register (0x01 , current_settings.m_integration_time );
254+ i2c_write_register (0x03 , current_settings.m_wait_time );
255+ i2c_write_register (0x0f , current_settings.m_gain );
256+ }
150257
258+ bool reg_cmd (const char * buf, const char * probe, uint8_t * reg)
259+ {
260+ auto probe_len = strlen (probe);
261+
262+ if (strncmp (buf, probe, probe_len) != 0 )
263+ {
264+ return false ;
265+ }
266+
267+ unsigned int x = 0 ;
268+ if (sscanf (buf + probe_len, " %x" , &x) < 1 )
269+ {
270+ log (" \n\r error\n\r " );
271+ send_status ();
272+ return true ;
273+ }
274+ *reg = (uint8_t )x;
275+ init_tcs ();
276+ log (" \n\r ok\n\r " );
277+ return true ;
278+ }
279+
280+ bool flash_current_settings ()
281+ {
282+ current_settings.make_valid ();
283+
284+ HAL_FLASH_Unlock ();
285+
286+ FLASH_EraseInitTypeDef erase_init;
287+ erase_init.TypeErase = FLASH_TYPEERASE_PAGES;
288+ erase_init.Banks = 0 ;
289+ erase_init.PageAddress = flash_settings_page;
290+ erase_init.NbPages = 1 ;
291+ uint32_t error = 0 ;
292+ if (HAL_FLASHEx_Erase (&erase_init, &error) != HAL_OK)
293+ {
294+ while (HAL_FLASH_Lock () != HAL_OK) ;
295+ return false ;
296+ }
297+
298+ FLASH_WaitForLastOperation (500 );
299+
300+ auto data = reinterpret_cast <uint32_t *>(¤t_settings);
301+ uint32_t flash_addr = flash_settings_page;
302+ uint32_t i = 0 ;
303+ while (i < sizeof (settings))
304+ {
305+ if (HAL_FLASH_Program (FLASH_TYPEPROGRAM_WORD, flash_addr, *data) != HAL_OK)
306+ {
307+ while (HAL_FLASH_Lock () != HAL_OK) ;
308+ return false ;
309+ }
310+ data++;
311+ flash_addr += 4 ;
312+ i += 4 ;
313+ }
314+ HAL_FLASH_Lock ();
315+ return true ;
316+ }
317+
318+ void try_exec_received_command ()
319+ {
320+ if (current_cmd == nullptr )
321+ {
322+ return ;
323+ }
324+
325+ auto cmd = current_cmd;
326+ current_cmd = nullptr ;
327+
328+ if (factor_cmd (cmd, " k " , ¤t_settings.m_total_factor )) return ;
329+ if (factor_cmd (cmd, " w " , ¤t_settings.m_white )) return ;
330+ if (factor_cmd (cmd, " r " , ¤t_settings.m_red )) return ;
331+ if (factor_cmd (cmd, " g " , ¤t_settings.m_green )) return ;
332+ if (factor_cmd (cmd, " b " , ¤t_settings.m_blue )) return ;
333+ if (reg_cmd (cmd, " int " , ¤t_settings.m_integration_time )) return ;
334+ if (reg_cmd (cmd, " wait " , ¤t_settings.m_wait_time )) return ;
335+ if (reg_cmd (cmd, " gain " , ¤t_settings.m_gain )) return ;
336+
337+ if (starts (cmd, " def" ))
338+ {
339+ current_settings.set_default ();
340+ init_tcs ();
341+ log (" \n\r ok\n\r " );
342+ return ;
343+ }
344+
345+ if (starts (cmd, " flash" ))
346+ {
347+ if (!flash_current_settings ())
348+ {
349+ log (" \n\r error\n\r " );
350+ }
351+ else
352+ {
353+ auto fl_settings = reinterpret_cast <settings*>(flash_settings_page);
354+ if (fl_settings->is_valid ())
355+ {
356+ log (" \n\r ok\n\r " );
357+ }
358+ else
359+ {
360+ log (" \n\r error\n\r " );
361+ }
362+ }
363+ return ;
364+ }
365+
366+ if (starts (cmd, " par " ))
367+ {
368+ double par = 0 ;
369+ double w = 0 ;
370+ double r = 0 ;
371+ double g = 0 ;
372+ double b = 0 ;
373+ if (sscanf (cmd + 4 , " %lf %lf %lf %lf %lf" , &par, &w, &r, &g, &b) < 5 )
374+ {
375+ log (" \n\r error\n\r " );
376+ send_status ();
377+ return ;
378+ }
379+
380+ auto raw = current_settings.calc_normalized_from_raw ((uint32_t )w, (uint32_t )r, (uint32_t )g, (uint32_t )b);
381+ if (raw == 0 )
382+ {
383+ log (" \n\r error: bad raw values\n\r " );
384+ return ;
385+ }
386+
387+ current_settings.m_total_factor = par / raw;
388+
389+ log (" \n\r ok\n\r " );
390+ return ;
391+ }
392+
393+ send_status ();
394+ }
395+
396+ void main_loop (void )
397+ {
398+ current_settings.set_default ();
399+
400+ auto fl_settings = reinterpret_cast <settings*>(flash_settings_page);
401+ if (fl_settings->is_valid ())
402+ {
403+ memcpy (¤t_settings, fl_settings, sizeof (settings));
404+ }
405+
406+ sh1106Init (40 ,0x22 ,1 );
407+ sh1106Clear (0 ,7 );
408+ sh1106SmallPrint (0 , 0 , (uint8_t *)app_title);
409+
410+ init_tcs ();
151411
152412 while (true )
153413 {
414+ try_exec_received_command ();
415+
154416 HAL_GPIO_WritePin (GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
155417 read_par ();
156418
0 commit comments