cli_command_gpio.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #include "cli_command_gpio.h"
  2. #include "core/string.h"
  3. #include <furi.h>
  4. #include <furi_hal.h>
  5. #include <lib/toolbox/args.h>
  6. typedef struct {
  7. const GpioPin* pin;
  8. const char* name;
  9. const bool debug;
  10. } CliCommandGpio;
  11. const CliCommandGpio cli_command_gpio_pins[] = {
  12. {.pin = &gpio_ext_pc0, .name = "PC0", .debug = false},
  13. {.pin = &gpio_ext_pc1, .name = "PC1", .debug = false},
  14. {.pin = &gpio_ext_pc3, .name = "PC3", .debug = false},
  15. {.pin = &gpio_ext_pb2, .name = "PB2", .debug = false},
  16. {.pin = &gpio_ext_pb3, .name = "PB3", .debug = false},
  17. {.pin = &gpio_ext_pa4, .name = "PA4", .debug = false},
  18. {.pin = &gpio_ext_pa6, .name = "PA6", .debug = false},
  19. {.pin = &gpio_ext_pa7, .name = "PA7", .debug = false},
  20. /* Dangerous pins, may damage hardware */
  21. {.pin = &gpio_infrared_rx, .name = "PA0", .debug = true},
  22. {.pin = &gpio_usart_rx, .name = "PB7", .debug = true},
  23. {.pin = &gpio_speaker, .name = "PB8", .debug = true},
  24. {.pin = &gpio_infrared_tx, .name = "PB9", .debug = true},
  25. };
  26. void cli_command_gpio_print_usage() {
  27. printf("Usage:\r\n");
  28. printf("gpio <cmd> <args>\r\n");
  29. printf("Cmd list:\r\n");
  30. printf("\tmode <pin_name> <0|1>\t - Set gpio mode: 0 - input, 1 - output\r\n");
  31. printf("\tset <pin_name> <0|1>\t - Set gpio value\r\n");
  32. printf("\tread <pin_name>\t - Read gpio value\r\n");
  33. }
  34. static bool pin_name_to_int(FuriString* pin_name, size_t* result) {
  35. bool is_debug_mode = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug);
  36. for(size_t i = 0; i < COUNT_OF(cli_command_gpio_pins); i++) {
  37. if(furi_string_equal(pin_name, cli_command_gpio_pins[i].name)) {
  38. if(!cli_command_gpio_pins[i].debug || is_debug_mode) {
  39. *result = i;
  40. return true;
  41. }
  42. }
  43. }
  44. return false;
  45. }
  46. static void gpio_print_pins(void) {
  47. printf("Wrong pin name. Available pins: ");
  48. bool is_debug_mode = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug);
  49. for(size_t i = 0; i < COUNT_OF(cli_command_gpio_pins); i++) {
  50. if(!cli_command_gpio_pins[i].debug || is_debug_mode) {
  51. printf("%s ", cli_command_gpio_pins[i].name);
  52. }
  53. }
  54. }
  55. typedef enum {
  56. GpioParseReturnOk,
  57. GpioParseReturnCmdSyntaxError,
  58. GpioParseReturnPinError,
  59. GpioParseReturnValueError
  60. } GpioParseReturn;
  61. static GpioParseReturn gpio_command_parse(FuriString* args, size_t* pin_num, uint8_t* value) {
  62. GpioParseReturn ret = GpioParseReturnOk;
  63. FuriString* pin_name = furi_string_alloc();
  64. do {
  65. if(!args_read_string_and_trim(args, pin_name)) {
  66. ret = GpioParseReturnCmdSyntaxError;
  67. break;
  68. } else if(!pin_name_to_int(pin_name, pin_num)) {
  69. ret = GpioParseReturnPinError;
  70. break;
  71. }
  72. int pin_mode; //-V779
  73. if(!args_read_int_and_trim(args, &pin_mode) || pin_mode < 0 || pin_mode > 1) {
  74. ret = GpioParseReturnValueError;
  75. break;
  76. }
  77. *value = pin_mode;
  78. } while(false);
  79. furi_string_free(pin_name);
  80. return ret;
  81. }
  82. void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) {
  83. UNUSED(cli);
  84. UNUSED(context);
  85. size_t num = 0;
  86. uint8_t value = 255;
  87. GpioParseReturn err = gpio_command_parse(args, &num, &value);
  88. if(err == GpioParseReturnCmdSyntaxError) {
  89. cli_print_usage("gpio mode", "<pin_name> <0|1>", furi_string_get_cstr(args));
  90. return;
  91. } else if(err == GpioParseReturnPinError) { //-V547
  92. gpio_print_pins();
  93. return;
  94. } else if(err == GpioParseReturnValueError) {
  95. printf("Value is invalid. Enter 1 for input or 0 for output");
  96. return;
  97. }
  98. if(cli_command_gpio_pins[num].debug) { //-V779
  99. printf(
  100. "Changing this pin mode may damage hardware. Are you sure you want to continue? (y/n)?\r\n");
  101. char c = cli_getc(cli);
  102. if(c != 'y' && c != 'Y') {
  103. printf("Cancelled.\r\n");
  104. return;
  105. }
  106. }
  107. if(value == 1) { // output
  108. furi_hal_gpio_write(cli_command_gpio_pins[num].pin, false);
  109. furi_hal_gpio_init_simple(cli_command_gpio_pins[num].pin, GpioModeOutputPushPull);
  110. printf("Pin %s is now an output (low)", cli_command_gpio_pins[num].name);
  111. } else { // input
  112. furi_hal_gpio_init_simple(cli_command_gpio_pins[num].pin, GpioModeInput);
  113. printf("Pin %s is now an input", cli_command_gpio_pins[num].name);
  114. }
  115. }
  116. void cli_command_gpio_read(Cli* cli, FuriString* args, void* context) {
  117. UNUSED(cli);
  118. UNUSED(context);
  119. size_t num = 0;
  120. if(!pin_name_to_int(args, &num)) {
  121. gpio_print_pins();
  122. return;
  123. }
  124. if(LL_GPIO_MODE_INPUT != //-V779
  125. LL_GPIO_GetPinMode(
  126. cli_command_gpio_pins[num].pin->port, cli_command_gpio_pins[num].pin->pin)) {
  127. printf("Err: pin %s is not set as an input.", cli_command_gpio_pins[num].name);
  128. return;
  129. }
  130. uint8_t val = !!furi_hal_gpio_read(cli_command_gpio_pins[num].pin);
  131. printf("Pin %s <= %u", cli_command_gpio_pins[num].name, val);
  132. }
  133. void cli_command_gpio_set(Cli* cli, FuriString* args, void* context) {
  134. UNUSED(context);
  135. size_t num = 0;
  136. uint8_t value = 0;
  137. GpioParseReturn err = gpio_command_parse(args, &num, &value);
  138. if(err == GpioParseReturnCmdSyntaxError) {
  139. cli_print_usage("gpio set", "<pin_name> <0|1>", furi_string_get_cstr(args));
  140. return;
  141. } else if(err == GpioParseReturnPinError) { //-V547
  142. gpio_print_pins();
  143. return;
  144. } else if(err == GpioParseReturnValueError) {
  145. printf("Value is invalid. Enter 1 for high or 0 for low");
  146. return;
  147. }
  148. if(LL_GPIO_MODE_OUTPUT != //-V779
  149. LL_GPIO_GetPinMode(
  150. cli_command_gpio_pins[num].pin->port, cli_command_gpio_pins[num].pin->pin)) {
  151. printf("Err: pin %s is not set as an output.", cli_command_gpio_pins[num].name);
  152. return;
  153. }
  154. // Extra check if debug pins used
  155. if(cli_command_gpio_pins[num].debug) {
  156. printf(
  157. "Setting this pin may damage hardware. Are you sure you want to continue? (y/n)?\r\n");
  158. char c = cli_getc(cli);
  159. if(c != 'y' && c != 'Y') {
  160. printf("Cancelled.\r\n");
  161. return;
  162. }
  163. }
  164. furi_hal_gpio_write(cli_command_gpio_pins[num].pin, !!value);
  165. printf("Pin %s => %u", cli_command_gpio_pins[num].name, !!value);
  166. }
  167. void cli_command_gpio(Cli* cli, FuriString* args, void* context) {
  168. FuriString* cmd;
  169. cmd = furi_string_alloc();
  170. do {
  171. if(!args_read_string_and_trim(args, cmd)) {
  172. cli_command_gpio_print_usage();
  173. break;
  174. }
  175. if(furi_string_cmp_str(cmd, "mode") == 0) {
  176. cli_command_gpio_mode(cli, args, context);
  177. break;
  178. }
  179. if(furi_string_cmp_str(cmd, "set") == 0) {
  180. cli_command_gpio_set(cli, args, context);
  181. break;
  182. }
  183. if(furi_string_cmp_str(cmd, "read") == 0) {
  184. cli_command_gpio_read(cli, args, context);
  185. break;
  186. }
  187. cli_command_gpio_print_usage();
  188. } while(false);
  189. furi_string_free(cmd);
  190. }