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