led.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-3-08 GuEe-GUI the first version
  9. */
  10. #include <rtthread.h>
  11. #define DBG_TAG "rtdm.led"
  12. #define DBG_LVL DBG_INFO
  13. #include <rtdbg.h>
  14. #include <drivers/led.h>
  15. #include <drivers/core/dm.h>
  16. struct blink_timer
  17. {
  18. rt_bool_t toggle;
  19. rt_bool_t enabled;
  20. rt_uint32_t count;
  21. struct rt_timer timer;
  22. };
  23. static struct rt_dm_ida led_ida = RT_DM_IDA_INIT(LED);
  24. static const char * const _led_states[] =
  25. {
  26. [RT_LED_S_OFF] = "off",
  27. [RT_LED_S_ON] = "on",
  28. [RT_LED_S_TOGGLE] = "toggle",
  29. [RT_LED_S_BLINK] = "blink",
  30. };
  31. static rt_ssize_t _led_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  32. {
  33. rt_ssize_t res;
  34. rt_size_t state_len;
  35. enum rt_led_state state;
  36. struct rt_led_device *led = rt_container_of(dev, struct rt_led_device, parent);
  37. if ((res = rt_led_get_state(led, &state)))
  38. {
  39. return res;
  40. }
  41. state_len = rt_strlen(_led_states[state]);
  42. if (pos < state_len)
  43. {
  44. size = rt_min_t(rt_size_t, size, size - pos);
  45. ((char *)buffer)[size - 1] = '\0';
  46. rt_strncpy(buffer, &_led_states[state][pos], size);
  47. return size;
  48. }
  49. else
  50. {
  51. return 0;
  52. }
  53. }
  54. static rt_ssize_t _led_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  55. {
  56. rt_uint32_t brightness = 0;
  57. const char *value = buffer;
  58. struct rt_led_device *led = rt_container_of(dev, struct rt_led_device, parent);
  59. for (int i = 0; i < RT_ARRAY_SIZE(_led_states); ++i)
  60. {
  61. if (!rt_strncmp((char *)_led_states[i], buffer, size))
  62. {
  63. return rt_led_set_state(led, i) ? : size;
  64. }
  65. }
  66. while (*value)
  67. {
  68. if (*value < '0' || *value > '9')
  69. {
  70. return -RT_EINVAL;
  71. }
  72. brightness *= 10;
  73. brightness += *value - '0';
  74. ++value;
  75. }
  76. rt_led_set_brightness(led, brightness);
  77. return size;
  78. }
  79. #ifdef RT_USING_DEVICE_OPS
  80. const static struct rt_device_ops _led_ops =
  81. {
  82. .read = _led_read,
  83. .write = _led_write,
  84. };
  85. #endif
  86. static void _led_blink_timerout(void *param)
  87. {
  88. rt_tick_t tick;
  89. struct rt_led_device *led = param;
  90. struct blink_timer *btimer = led->sysdata;
  91. if (btimer->toggle)
  92. {
  93. led->ops->set_state(led, RT_LED_S_OFF);
  94. if (btimer->count++ & 1)
  95. {
  96. btimer->count = 0;
  97. tick = rt_tick_from_millisecond(1000);
  98. goto _set_timeout;
  99. }
  100. }
  101. else
  102. {
  103. led->ops->set_state(led, RT_LED_S_ON);
  104. if (!btimer->count)
  105. {
  106. tick = rt_tick_from_millisecond(80);
  107. goto _set_timeout;
  108. }
  109. }
  110. _toggle:
  111. btimer->toggle = !btimer->toggle;
  112. return;
  113. _set_timeout:
  114. rt_timer_stop(&btimer->timer);
  115. rt_timer_control(&btimer->timer, RT_TIMER_CTRL_SET_TIME, &tick);
  116. rt_timer_start(&btimer->timer);
  117. goto _toggle;
  118. }
  119. rt_err_t rt_led_register(struct rt_led_device *led)
  120. {
  121. rt_err_t err;
  122. int device_id;
  123. const char *dev_name;
  124. struct blink_timer *btimer = RT_NULL;
  125. if (!led || !led->ops)
  126. {
  127. return -RT_EINVAL;
  128. }
  129. if ((device_id = rt_dm_ida_alloc(&led_ida)) < 0)
  130. {
  131. return -RT_EFULL;
  132. }
  133. rt_dm_dev_set_name(&led->parent, "led%u", device_id);
  134. dev_name = rt_dm_dev_get_name(&led->parent);
  135. led->sysdata = RT_NULL;
  136. rt_spin_lock_init(&led->spinlock);
  137. if (!led->ops->set_period && led->ops->set_state)
  138. {
  139. btimer = rt_malloc(sizeof(*btimer));
  140. if (!btimer)
  141. {
  142. LOG_E("%s create blink timer failed", dev_name);
  143. err = -RT_ENOMEM;
  144. goto _fail;
  145. }
  146. led->sysdata = btimer;
  147. btimer->toggle = RT_FALSE;
  148. btimer->enabled = RT_FALSE;
  149. btimer->count = 0;
  150. rt_timer_init(&btimer->timer, dev_name, _led_blink_timerout, led,
  151. rt_tick_from_millisecond(1000), RT_TIMER_FLAG_PERIODIC);
  152. }
  153. led->parent.type = RT_Device_Class_Char;
  154. #ifdef RT_USING_DEVICE_OPS
  155. led->parent.ops = &_led_ops;
  156. #else
  157. led->parent.read = _led_read;
  158. led->parent.write = _led_write;
  159. #endif
  160. led->parent.master_id = led_ida.master_id;
  161. led->parent.device_id = device_id;
  162. if ((err = rt_device_register(&led->parent, dev_name, RT_DEVICE_FLAG_RDWR)))
  163. {
  164. goto _fail;
  165. }
  166. return RT_EOK;
  167. _fail:
  168. rt_dm_ida_free(&led_ida, device_id);
  169. if (btimer)
  170. {
  171. rt_timer_detach(&btimer->timer);
  172. rt_free(btimer);
  173. led->sysdata = RT_NULL;
  174. }
  175. return err;
  176. }
  177. rt_err_t rt_led_unregister(struct rt_led_device *led)
  178. {
  179. if (!led)
  180. {
  181. return -RT_EINVAL;
  182. }
  183. rt_led_set_state(led, RT_LED_S_OFF);
  184. if (led->sysdata)
  185. {
  186. struct blink_timer *btimer = led->sysdata;
  187. rt_timer_detach(&btimer->timer);
  188. rt_free(btimer);
  189. }
  190. rt_dm_ida_free(&led_ida, led->parent.device_id);
  191. rt_device_unregister(&led->parent);
  192. return RT_EOK;
  193. }
  194. rt_err_t rt_led_set_state(struct rt_led_device *led, enum rt_led_state state)
  195. {
  196. rt_err_t err;
  197. struct blink_timer *btimer;
  198. if (!led)
  199. {
  200. return -RT_EINVAL;
  201. }
  202. if (!led->ops->set_state)
  203. {
  204. return -RT_ENOSYS;
  205. }
  206. rt_spin_lock(&led->spinlock);
  207. btimer = led->sysdata;
  208. if (btimer && btimer->enabled)
  209. {
  210. rt_timer_stop(&btimer->timer);
  211. }
  212. err = led->ops->set_state(led, state);
  213. if (state == RT_LED_S_BLINK)
  214. {
  215. if (err == -RT_ENOSYS && btimer && !btimer->enabled)
  216. {
  217. btimer->enabled = RT_TRUE;
  218. rt_timer_start(&btimer->timer);
  219. }
  220. }
  221. else if (btimer && btimer->enabled)
  222. {
  223. if (err)
  224. {
  225. rt_timer_start(&btimer->timer);
  226. }
  227. else
  228. {
  229. btimer->enabled = RT_FALSE;
  230. }
  231. }
  232. rt_spin_unlock(&led->spinlock);
  233. return err;
  234. }
  235. rt_err_t rt_led_get_state(struct rt_led_device *led, enum rt_led_state *out_state)
  236. {
  237. rt_err_t err;
  238. if (!led || !out_state)
  239. {
  240. return -RT_EINVAL;
  241. }
  242. if (!led->ops->get_state)
  243. {
  244. return -RT_ENOSYS;
  245. }
  246. rt_spin_lock(&led->spinlock);
  247. err = led->ops->get_state(led, out_state);
  248. rt_spin_unlock(&led->spinlock);
  249. return err;
  250. }
  251. rt_err_t rt_led_set_period(struct rt_led_device *led, rt_uint32_t period_ms)
  252. {
  253. rt_err_t err;
  254. if (!led)
  255. {
  256. return -RT_EINVAL;
  257. }
  258. if (!led->ops->set_period && !led->sysdata)
  259. {
  260. return -RT_ENOSYS;
  261. }
  262. rt_spin_lock(&led->spinlock);
  263. if (led->ops->set_period)
  264. {
  265. err = led->ops->set_period(led, period_ms);
  266. }
  267. else
  268. {
  269. struct blink_timer *btimer = led->sysdata;
  270. rt_tick_t tick = rt_tick_from_millisecond(period_ms);
  271. err = rt_timer_control(&btimer->timer, RT_TIMER_CTRL_SET_TIME, &tick);
  272. }
  273. rt_spin_unlock(&led->spinlock);
  274. return err;
  275. }
  276. rt_err_t rt_led_set_brightness(struct rt_led_device *led, rt_uint32_t brightness)
  277. {
  278. rt_err_t err;
  279. if (!led)
  280. {
  281. return -RT_EINVAL;
  282. }
  283. if (!led->ops->set_brightness)
  284. {
  285. return -RT_ENOSYS;
  286. }
  287. rt_spin_lock(&led->spinlock);
  288. err = led->ops->set_brightness(led, brightness);
  289. rt_spin_unlock(&led->spinlock);
  290. return err;
  291. }