Merge remote-tracking branch 'upstream/edge' into feature/filament-detector
[clinton/Smoothieware.git] / src / libs / Pin.cpp
1 #include "Pin.h"
2 #include "utils.h"
3
4 // mbed libraries for hardware pwm
5 #include "PwmOut.h"
6 #include "InterruptIn.h"
7 #include "PinNames.h"
8 #include "port_api.h"
9
10 Pin::Pin(){
11 this->inverting= false;
12 this->valid= false;
13 this->pin= 32;
14 this->port= nullptr;
15 }
16
17 // Make a new pin object from a string
18 Pin* Pin::from_string(std::string value){
19 LPC_GPIO_TypeDef* gpios[5] ={LPC_GPIO0,LPC_GPIO1,LPC_GPIO2,LPC_GPIO3,LPC_GPIO4};
20
21 // cs is the current position in the string
22 const char* cs = value.c_str();
23 // cn is the position of the next char after the number we just read
24 char* cn = NULL;
25 valid= true;
26
27 // grab first integer as port. pointer to first non-digit goes in cn
28 this->port_number = strtol(cs, &cn, 10);
29 // if cn > cs then strtol read at least one digit
30 if ((cn > cs) && (port_number <= 4)){
31 // translate port index into something useful
32 this->port = gpios[(unsigned int) this->port_number];
33 // if the char after the first integer is a . then we should expect a pin index next
34 if (*cn == '.'){
35 // move pointer to first digit (hopefully) of pin index
36 cs = ++cn;
37
38 // grab pin index.
39 this->pin = strtol(cs, &cn, 10);
40
41 // if strtol read some numbers, cn will point to the first non-digit
42 if ((cn > cs) && (pin < 32)){
43 this->port->FIOMASK &= ~(1 << this->pin);
44
45 // now check for modifiers:-
46 // ! = invert pin
47 // o = set pin to open drain
48 // ^ = set pin to pull up
49 // v = set pin to pull down
50 // - = set pin to no pull up or down
51 // @ = set pin to repeater mode
52 for (;*cn;cn++) {
53 switch(*cn) {
54 case '!':
55 this->inverting = true;
56 break;
57 case 'o':
58 as_open_drain();
59 break;
60 case '^':
61 pull_up();
62 break;
63 case 'v':
64 pull_down();
65 break;
66 case '-':
67 pull_none();
68 break;
69 case '@':
70 as_repeater();
71 break;
72 default:
73 // skip any whitespace following the pin index
74 if (!is_whitespace(*cn))
75 return this;
76 }
77 }
78 return this;
79 }
80 }
81 }
82
83 // from_string failed. TODO: some sort of error
84 valid= false;
85 port_number = 0;
86 port = gpios[0];
87 pin = 32;
88 inverting = false;
89 return this;
90 }
91
92 // Configure this pin as OD
93 Pin* Pin::as_open_drain(){
94 if (!this->valid) return this;
95 if( this->port_number == 0 ){ LPC_PINCON->PINMODE_OD0 |= (1<<this->pin); }
96 if( this->port_number == 1 ){ LPC_PINCON->PINMODE_OD1 |= (1<<this->pin); }
97 if( this->port_number == 2 ){ LPC_PINCON->PINMODE_OD2 |= (1<<this->pin); }
98 if( this->port_number == 3 ){ LPC_PINCON->PINMODE_OD3 |= (1<<this->pin); }
99 if( this->port_number == 4 ){ LPC_PINCON->PINMODE_OD4 |= (1<<this->pin); }
100 pull_none(); // no pull up by default
101 return this;
102 }
103
104
105 // Configure this pin as a repeater
106 Pin* Pin::as_repeater(){
107 if (!this->valid) return this;
108 // Set the two bits for this pin as 01
109 if( this->port_number == 0 && this->pin < 16 ){ LPC_PINCON->PINMODE0 |= (1<<( this->pin*2)); LPC_PINCON->PINMODE0 &= ~(2<<( this->pin *2)); }
110 if( this->port_number == 0 && this->pin >= 16 ){ LPC_PINCON->PINMODE1 |= (1<<( this->pin*2)); LPC_PINCON->PINMODE1 &= ~(2<<((this->pin-16)*2)); }
111 if( this->port_number == 1 && this->pin < 16 ){ LPC_PINCON->PINMODE2 |= (1<<( this->pin*2)); LPC_PINCON->PINMODE2 &= ~(2<<( this->pin *2)); }
112 if( this->port_number == 1 && this->pin >= 16 ){ LPC_PINCON->PINMODE3 |= (1<<( this->pin*2)); LPC_PINCON->PINMODE3 &= ~(2<<((this->pin-16)*2)); }
113 if( this->port_number == 2 && this->pin < 16 ){ LPC_PINCON->PINMODE4 |= (1<<( this->pin*2)); LPC_PINCON->PINMODE4 &= ~(2<<( this->pin *2)); }
114 if( this->port_number == 3 && this->pin >= 16 ){ LPC_PINCON->PINMODE7 |= (1<<( this->pin*2)); LPC_PINCON->PINMODE7 &= ~(2<<((this->pin-16)*2)); }
115 if( this->port_number == 4 && this->pin >= 16 ){ LPC_PINCON->PINMODE9 |= (1<<( this->pin*2)); LPC_PINCON->PINMODE9 &= ~(2<<((this->pin-16)*2)); }
116 return this;
117 }
118
119 // Configure this pin as no pullup or pulldown
120 Pin* Pin::pull_none(){
121 if (!this->valid) return this;
122 // Set the two bits for this pin as 10
123 if( this->port_number == 0 && this->pin < 16 ){ LPC_PINCON->PINMODE0 |= (2<<( this->pin*2)); LPC_PINCON->PINMODE0 &= ~(1<<( this->pin *2)); }
124 if( this->port_number == 0 && this->pin >= 16 ){ LPC_PINCON->PINMODE1 |= (2<<( this->pin*2)); LPC_PINCON->PINMODE1 &= ~(1<<((this->pin-16)*2)); }
125 if( this->port_number == 1 && this->pin < 16 ){ LPC_PINCON->PINMODE2 |= (2<<( this->pin*2)); LPC_PINCON->PINMODE2 &= ~(1<<( this->pin *2)); }
126 if( this->port_number == 1 && this->pin >= 16 ){ LPC_PINCON->PINMODE3 |= (2<<( this->pin*2)); LPC_PINCON->PINMODE3 &= ~(1<<((this->pin-16)*2)); }
127 if( this->port_number == 2 && this->pin < 16 ){ LPC_PINCON->PINMODE4 |= (2<<( this->pin*2)); LPC_PINCON->PINMODE4 &= ~(1<<( this->pin *2)); }
128 if( this->port_number == 3 && this->pin >= 16 ){ LPC_PINCON->PINMODE7 |= (2<<( this->pin*2)); LPC_PINCON->PINMODE7 &= ~(1<<((this->pin-16)*2)); }
129 if( this->port_number == 4 && this->pin >= 16 ){ LPC_PINCON->PINMODE9 |= (2<<( this->pin*2)); LPC_PINCON->PINMODE9 &= ~(1<<((this->pin-16)*2)); }
130 return this;
131 }
132
133 // Configure this pin as a pullup
134 Pin* Pin::pull_up(){
135 if (!this->valid) return this;
136 // Set the two bits for this pin as 00
137 if( this->port_number == 0 && this->pin < 16 ){ LPC_PINCON->PINMODE0 &= ~(3<<( this->pin *2)); }
138 if( this->port_number == 0 && this->pin >= 16 ){ LPC_PINCON->PINMODE1 &= ~(3<<((this->pin-16)*2)); }
139 if( this->port_number == 1 && this->pin < 16 ){ LPC_PINCON->PINMODE2 &= ~(3<<( this->pin *2)); }
140 if( this->port_number == 1 && this->pin >= 16 ){ LPC_PINCON->PINMODE3 &= ~(3<<((this->pin-16)*2)); }
141 if( this->port_number == 2 && this->pin < 16 ){ LPC_PINCON->PINMODE4 &= ~(3<<( this->pin *2)); }
142 if( this->port_number == 3 && this->pin >= 16 ){ LPC_PINCON->PINMODE7 &= ~(3<<((this->pin-16)*2)); }
143 if( this->port_number == 4 && this->pin >= 16 ){ LPC_PINCON->PINMODE9 &= ~(3<<((this->pin-16)*2)); }
144 return this;
145 }
146
147 // Configure this pin as a pulldown
148 Pin* Pin::pull_down(){
149 if (!this->valid) return this;
150 // Set the two bits for this pin as 11
151 if( this->port_number == 0 && this->pin < 16 ){ LPC_PINCON->PINMODE0 |= (3<<( this->pin *2)); }
152 if( this->port_number == 0 && this->pin >= 16 ){ LPC_PINCON->PINMODE1 |= (3<<((this->pin-16)*2)); }
153 if( this->port_number == 1 && this->pin < 16 ){ LPC_PINCON->PINMODE2 |= (3<<( this->pin *2)); }
154 if( this->port_number == 1 && this->pin >= 16 ){ LPC_PINCON->PINMODE3 |= (3<<((this->pin-16)*2)); }
155 if( this->port_number == 2 && this->pin < 16 ){ LPC_PINCON->PINMODE4 |= (3<<( this->pin *2)); }
156 if( this->port_number == 3 && this->pin >= 16 ){ LPC_PINCON->PINMODE7 |= (3<<((this->pin-16)*2)); }
157 if( this->port_number == 4 && this->pin >= 16 ){ LPC_PINCON->PINMODE9 |= (3<<((this->pin-16)*2)); }
158 return this;
159 }
160
161 // If available on this pin, return mbed hardware pwm class for this pin
162 mbed::PwmOut* Pin::hardware_pwm()
163 {
164 if (port_number == 1)
165 {
166 if (pin == 18) { return new mbed::PwmOut(P1_18); }
167 if (pin == 20) { return new mbed::PwmOut(P1_20); }
168 if (pin == 21) { return new mbed::PwmOut(P1_21); }
169 if (pin == 23) { return new mbed::PwmOut(P1_23); }
170 if (pin == 24) { return new mbed::PwmOut(P1_24); }
171 if (pin == 26) { return new mbed::PwmOut(P1_26); }
172 }
173 else if (port_number == 2)
174 {
175 if (pin == 0) { return new mbed::PwmOut(P2_0); }
176 if (pin == 1) { return new mbed::PwmOut(P2_1); }
177 if (pin == 2) { return new mbed::PwmOut(P2_2); }
178 if (pin == 3) { return new mbed::PwmOut(P2_3); }
179 if (pin == 4) { return new mbed::PwmOut(P2_4); }
180 if (pin == 5) { return new mbed::PwmOut(P2_5); }
181 }
182 else if (port_number == 3)
183 {
184 if (pin == 25) { return new mbed::PwmOut(P3_25); }
185 if (pin == 26) { return new mbed::PwmOut(P3_26); }
186 }
187 return nullptr;
188 }
189
190 mbed::InterruptIn* Pin::interrupt_pin()
191 {
192 if(!this->valid) return nullptr;
193
194 // set as input
195 as_input();
196
197 if (port_number == 0 || port_number == 2) {
198 PinName pinname = port_pin((PortName)port_number, pin);
199 return new mbed::InterruptIn(pinname);
200
201 }else{
202 this->valid= false;
203 return nullptr;
204 }
205 }