1 /*---------------------------------------------------------------------------*\
2 
3   FILE........: sm1000_leds_switches.c
4   AUTHOR......: David Rowe
5   DATE CREATED: 18 July 2014
6 
7   Functions for controlling LEDs and reading switches on the SM1000.
8 
9 \*---------------------------------------------------------------------------*/
10 
11 /*
12   Copyright (C) 2014 David Rowe
13 
14   All rights reserved.
15 
16   This program is free software; you can redistribute it and/or modify
17   it under the terms of the GNU Lesser General Public License version 2.1, as
18   published by the Free Software Foundation.  This program is
19   distributed in the hope that it will be useful, but WITHOUT ANY
20   WARRANTY; without even the implied warranty of MERCHANTABILITY or
21   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
22   License for more details.
23 
24   You should have received a copy of the GNU Lesser General Public License
25   along with this program; if not, see <http://www.gnu.org/licenses/>.
26 */
27 
28 #define _CPTT          GPIO_Pin_10
29 #define LED_PWR        GPIO_Pin_12
30 #define LED_PTT        GPIO_Pin_13
31 #define LED_RT         GPIO_Pin_14
32 #define LED_ERR        GPIO_Pin_15
33 #define SWITCH_PTT     GPIO_Pin_7
34 #define SWITCH_SELECT  GPIO_Pin_0
35 #define SWITCH_BACK    GPIO_Pin_1
36 #define EXT_PTT        GPIO_Pin_8
37 
38 #include <stm32f4xx.h>
39 #include <stm32f4xx_gpio.h>
40 #include "sm1000_leds_switches.h"
41 
sm1000_leds_switches_init(void)42 void sm1000_leds_switches_init(void) {
43     GPIO_InitTypeDef GPIO_InitStruct;
44 
45     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
46 
47     /* output pins */
48 
49     GPIO_InitStruct.GPIO_Pin = LED_PWR | LED_PTT | LED_RT | LED_ERR | _CPTT;
50     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
51     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
52     GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
53     GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
54     GPIO_Init(GPIOD, &GPIO_InitStruct);
55 
56     /* input pins */
57 
58     GPIO_InitStruct.GPIO_Pin = SWITCH_PTT | SWITCH_SELECT | SWITCH_BACK;
59     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
60     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
61     GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; /* we have our own external pull ups */
62     GPIO_Init(GPIOD, &GPIO_InitStruct);
63 
64     GPIO_InitStruct.GPIO_Pin = EXT_PTT;
65     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
66     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
67     GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;     /* use internal pull up */
68     GPIO_Init(GPIOD, &GPIO_InitStruct);
69 
70 
71 }
72 
led_pwr(int state)73 void led_pwr(int state) {
74     if (state > 0)
75         GPIOD->ODR |= (1 << 12);
76     else if (state < 0)
77         GPIOD->ODR ^= (1 << 12);
78     else
79         GPIOD->ODR &= ~(1 << 12);
80 }
81 
led_ptt(int state)82 void led_ptt(int state) {
83     if (state > 0)
84         GPIOD->ODR |= (1 << 13);
85     else if (state < 0)
86         GPIOD->ODR |= (1 << 13);
87     else
88         GPIOD->ODR &= ~(1 << 13);
89 }
90 
led_rt(int state)91 void led_rt(int state) {
92     if (state > 0)
93         GPIOD->ODR |= (1 << 14);
94     else if (state < 0)
95         GPIOD->ODR ^= (1 << 14);
96     else
97         GPIOD->ODR &= ~(1 << 14);
98 }
99 
led_err(int state)100 void led_err(int state) {
101     if (state > 0)
102         GPIOD->ODR |= (1 << 15);
103     else if (state < 0)
104         GPIOD->ODR ^= (1 << 15);
105     else
106         GPIOD->ODR &= ~(1 << 15);
107 }
108 
not_cptt(int state)109 void not_cptt(int state) {
110     if (state)
111         GPIOD->ODR |= (1 << 10);
112     else
113         GPIOD->ODR &= ~(1 << 10);
114 }
115 
switch_ptt(void)116 int switch_ptt(void) {
117     return GPIOD->IDR & (1 << 7);
118 }
119 
switch_select(void)120 int switch_select(void) {
121     return GPIOD->IDR & (1 << 0);
122 }
123 
switch_back(void)124 int switch_back(void) {
125     return GPIOD->IDR & (1 << 1);
126 }
127 
ext_ptt(void)128 int ext_ptt(void) {
129     return GPIOD->IDR & (1 << 8);
130 }
131 
132 /*
133   FUNCTION: ColorfulRingOfDeath()
134   AUTHOR..: xenovacivus
135 
136   Colourful ring of death, blink LEDs like crazy forever if something
137   really nasty happens.  Adapted from USB Virtual COM Port (VCP)
138   module adapted from code I found here:
139 
140     https://github.com/xenovacivus/STM32DiscoveryVCP
141 
142   Call this to indicate a failure.  Blinks the STM32F4 discovery LEDs
143   in sequence.  At 168Mhz, the blinking will be very fast - about 5
144   Hz.  Keep that in mind when debugging, knowing the clock speed
145   might help with debugging.
146 */
147 
148 int mycode; /* examine this with debugger if it dies */
149 
ColorfulRingOfDeath(int code)150 void ColorfulRingOfDeath(int code) {
151     mycode = code;
152     uint16_t ring = 1;
153     while (1) {
154         uint32_t count = 0;
155         while (count++ < 5000000);
156 
157         GPIOD->BSRRH = (ring << 12);
158         ring = ring << 1;
159         if (ring >= 1<<4) {
160             ring = 1;
161         }
162         GPIOD->BSRRL = (ring << 12);
163     }
164 }
HardFault_Handler(void)165 void HardFault_Handler(void) { ColorfulRingOfDeath(1); }
MemManage_Handler(void)166 void MemManage_Handler(void) { ColorfulRingOfDeath(2); }
BusFault_Handler(void)167 void BusFault_Handler(void)  { ColorfulRingOfDeath(3); }
UsageFault_Handler(void)168 void UsageFault_Handler(void){ ColorfulRingOfDeath(4); }
169 
170 
switch_tick(struct switch_t * const sw)171 void switch_tick(struct switch_t* const sw)
172 {
173     if (sw->sw != sw->raw) {
174         /* State transition, reset timer */
175         if (sw->state == SW_STEADY)
176             sw->last = sw->sw;
177         sw->state = SW_DEBOUNCE;
178         sw->timer = DEBOUNCE_DELAY;
179         sw->sw = sw->raw;
180     } else if (sw->state == SW_DEBOUNCE) {
181         if (sw->timer > 0) {
182             /* Steady so far, keep waiting */
183             sw->timer--;
184         } else {
185             /* Steady state reached */
186             sw->state = SW_STEADY;
187         }
188     } else if (sw->sw) {
189         /* Hold state.  Yes this will wrap, but who cares? */
190         sw->timer++;
191     }
192 }
193 
switch_update(struct switch_t * const sw,uint8_t state)194 void switch_update(struct switch_t* const sw, uint8_t state)
195 {
196     sw->raw = state;
197     if (sw->raw == sw->sw)
198         return;
199 
200     if (sw->state == SW_STEADY)
201         sw->last = sw->sw;
202     sw->timer = DEBOUNCE_DELAY;
203     sw->sw = sw->raw;
204     sw->state = SW_DEBOUNCE;
205 }
206 
switch_pressed(const struct switch_t * const sw)207 uint32_t switch_pressed(const struct switch_t* const sw)
208 {
209     if ((sw->state == SW_STEADY) && sw->sw)
210         return sw->timer;
211     return 0;
212 }
213 
switch_released(const struct switch_t * const sw)214 int switch_released(const struct switch_t* const sw)
215 {
216     if (sw->state != SW_STEADY)
217         return 0;
218     if (!sw->last)
219         return 0;
220     if (sw->sw)
221         return 0;
222     return 1;
223 }
224 
switch_ack(struct switch_t * const sw)225 void switch_ack(struct switch_t* const sw)
226 {
227     if (sw->state == SW_STEADY)
228         sw->last = sw->sw;
229 }
230