1 /*
2  * Copyright (c) 2019 Alexander Wachter
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/sys/printk.h>
8 #include <zephyr/shell/shell.h>
9 #include <zephyr/drivers/hwinfo.h>
10 #include <zephyr/types.h>
11 #include <zephyr/logging/log.h>
12 
cmd_get_device_id(const struct shell * sh,size_t argc,char ** argv)13 static int cmd_get_device_id(const struct shell *sh, size_t argc, char **argv)
14 {
15 	uint8_t dev_id[16];
16 	ssize_t length;
17 	int i;
18 
19 	length = hwinfo_get_device_id(dev_id, sizeof(dev_id));
20 
21 	if (length == -ENOTSUP) {
22 		shell_error(sh, "Not supported by hardware");
23 		return -ENOTSUP;
24 	} else if (length < 0) {
25 		shell_error(sh, "Error: %zd", length);
26 		return length;
27 	}
28 
29 	shell_fprintf(sh, SHELL_NORMAL, "Length: %zd\n", length);
30 	shell_fprintf(sh, SHELL_NORMAL, "ID: 0x");
31 
32 	for (i = 0 ; i < length ; i++) {
33 		shell_fprintf(sh, SHELL_NORMAL, "%02x", dev_id[i]);
34 	}
35 
36 	shell_fprintf(sh, SHELL_NORMAL, "\n");
37 
38 	return 0;
39 }
40 
cause_to_string(uint32_t cause)41 static inline const char *cause_to_string(uint32_t cause)
42 {
43 	switch (cause) {
44 	case RESET_PIN:
45 		return "pin";
46 
47 	case RESET_SOFTWARE:
48 		return "software";
49 
50 	case RESET_BROWNOUT:
51 		return "brownout";
52 
53 	case RESET_POR:
54 		return "power-on reset";
55 
56 	case RESET_WATCHDOG:
57 		return "watchdog";
58 
59 	case RESET_DEBUG:
60 		return "debug";
61 
62 	case RESET_SECURITY:
63 		return "security";
64 
65 	case RESET_LOW_POWER_WAKE:
66 		return "low power wake-up";
67 
68 	case RESET_CPU_LOCKUP:
69 		return "CPU lockup";
70 
71 	case RESET_PARITY:
72 		return "parity error";
73 
74 	case RESET_PLL:
75 		return "PLL error";
76 
77 	case RESET_CLOCK:
78 		return "clock";
79 
80 	case RESET_HARDWARE:
81 		return "hardware";
82 
83 	case RESET_USER:
84 		return "user";
85 
86 	case RESET_TEMPERATURE:
87 		return "temperature";
88 
89 	default:
90 		return "unknown";
91 	}
92 }
93 
print_all_reset_causes(const struct shell * sh,uint32_t cause)94 static void print_all_reset_causes(const struct shell *sh, uint32_t cause)
95 {
96 	for (uint32_t cause_mask = 1; cause_mask; cause_mask <<= 1) {
97 		if (cause & cause_mask) {
98 			shell_print(sh, "- %s",
99 				    cause_to_string(cause & cause_mask));
100 		}
101 	}
102 }
103 
cmd_show_reset_cause(const struct shell * sh,size_t argc,char ** argv)104 static int cmd_show_reset_cause(const struct shell *sh, size_t argc,
105 				char **argv)
106 {
107 	int res;
108 	uint32_t cause;
109 
110 	ARG_UNUSED(argc);
111 	ARG_UNUSED(argv);
112 
113 	res = hwinfo_get_reset_cause(&cause);
114 	if (res == -ENOTSUP) {
115 		shell_error(sh, "Not supported by hardware");
116 		return res;
117 	} else if (res != 0) {
118 		shell_error(sh, "Error reading the cause [%d]", res);
119 		return res;
120 	}
121 
122 	if (cause != 0) {
123 		shell_print(sh, "reset caused by:");
124 		print_all_reset_causes(sh, cause);
125 	} else {
126 		shell_print(sh, "No reset cause set");
127 	}
128 
129 	return 0;
130 }
131 
cmd_clear_reset_cause(const struct shell * sh,size_t argc,char ** argv)132 static int cmd_clear_reset_cause(const struct shell *sh, size_t argc,
133 				 char **argv)
134 {
135 	int res;
136 
137 	ARG_UNUSED(argc);
138 	ARG_UNUSED(argv);
139 
140 	res = hwinfo_clear_reset_cause();
141 	if (res == -ENOTSUP) {
142 		shell_error(sh, "Not supported by hardware");
143 	} else if (res != 0) {
144 		shell_error(sh, "Error clearing the reset causes [%d]", res);
145 		return res;
146 	}
147 
148 	return 0;
149 }
150 
cmd_supported_reset_cause(const struct shell * sh,size_t argc,char ** argv)151 static int cmd_supported_reset_cause(const struct shell *sh, size_t argc,
152 				     char **argv)
153 {
154 	uint32_t cause;
155 	int res;
156 
157 	ARG_UNUSED(argc);
158 	ARG_UNUSED(argv);
159 
160 	res = hwinfo_get_supported_reset_cause(&cause);
161 	if (res == -ENOTSUP) {
162 		shell_error(sh, "Not supported by hardware");
163 	} else if (res != 0) {
164 		shell_error(sh, "Could not get the supported reset causes [%d]", res);
165 		return res;
166 	}
167 
168 	if (cause != 0) {
169 		shell_print(sh, "supported reset causes:");
170 		print_all_reset_causes(sh, cause);
171 	} else {
172 		shell_print(sh, "No causes supported");
173 	}
174 
175 	return 0;
176 }
177 
178 SHELL_STATIC_SUBCMD_SET_CREATE(sub_reset_cause,
179 	SHELL_CMD_ARG(show, NULL, "Show persistent reset causes",
180 		      cmd_show_reset_cause, 1, 0),
181 	SHELL_CMD_ARG(clear, NULL, "Clear all persistent reset causes",
182 		      cmd_clear_reset_cause, 1, 0),
183 	SHELL_CMD_ARG(supported, NULL,
184 		      "Get a list of all supported reset causes",
185 		      cmd_supported_reset_cause, 1, 0),
186 	SHELL_SUBCMD_SET_END /* Array terminated. */
187 );
188 
189 SHELL_STATIC_SUBCMD_SET_CREATE(sub_hwinfo,
190 	SHELL_CMD_ARG(devid, NULL, "Show device id", cmd_get_device_id, 1, 0),
191 	SHELL_CMD_ARG(reset_cause, &sub_reset_cause, "Reset cause commands",
192 		      cmd_show_reset_cause, 1, 0),
193 	SHELL_SUBCMD_SET_END /* Array terminated. */
194 );
195 
196 SHELL_CMD_ARG_REGISTER(hwinfo, &sub_hwinfo, "HWINFO commands", NULL, 2, 0);
197