PageRenderTime 42ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/internal/Pins.cpp

https://github.com/amcjen/ncore
C++ | 389 lines | 269 code | 80 blank | 40 comment | 72 complexity | 33b9423fd41d2e1ab1eff943f150fcd7 MD5 | raw file
  1. // STL includes
  2. #include <iostream>
  3. #include <stdexcept>
  4. #include <sstream>
  5. // C includes
  6. // Library includes
  7. // Project includes
  8. #include <Dispatcher.h>
  9. #include <Parser.h>
  10. #include <Logger.h>
  11. #include <Pins.h>
  12. #include <Clock.h>
  13. using namespace std;
  14. /****************************************************************************/
  15. const int LOW = 0;
  16. const int HIGH = 1;
  17. /****************************************************************************/
  18. string Pins::pin_log_name(int pin) const
  19. {
  20. ostringstream os;
  21. if ( symbol_map.count(pin) )
  22. os << symbol_map.at(pin);
  23. else
  24. os << dec << pin;
  25. return os.str();
  26. }
  27. /****************************************************************************/
  28. Pins::Pins(Logger& _log): log(_log)
  29. {
  30. clear();
  31. }
  32. /****************************************************************************/
  33. void Pins::clear(void)
  34. {
  35. digital_states.clear();
  36. pin_modes.clear();
  37. analog_states.clear();
  38. isr_table.clear();
  39. symbol_map.clear();
  40. symbol_reverse_map.clear();
  41. digital_states.resize(num_pins);
  42. pin_modes.resize(num_pins);
  43. analog_states.resize(num_channels);
  44. isr_table.resize(num_interrupts);
  45. }
  46. /****************************************************************************/
  47. int Pins::digitalRead(int pin) const
  48. {
  49. int result = digital_states.at(pin);
  50. return result;
  51. }
  52. /****************************************************************************/
  53. void Pins::hwSetDigital(int pin,int level)
  54. {
  55. digital_states.at(pin) = level;
  56. log.internal("PINS","%s %s",pin_log_name(pin).c_str(),level?"HIGH":"LOW");
  57. }
  58. /****************************************************************************/
  59. int Pins::analogRead(int pin) const
  60. {
  61. return analog_states.at(pin);
  62. }
  63. /****************************************************************************/
  64. void Pins::hwSetAnalog(int pin,int level)
  65. {
  66. analog_states.at(pin) = level;
  67. log.internal("PINS", "A%i %i",pin,level);
  68. }
  69. /****************************************************************************/
  70. void Pins::digitalWrite(int pin,int level)
  71. {
  72. digital_states.at(pin) = level;
  73. log.sketch("PINS","%s %s",pin_log_name(pin).c_str(),level?"HIGH":"LOW");
  74. }
  75. /****************************************************************************/
  76. int Pins::hwGetDigital(int pin) const
  77. {
  78. return digital_states.at(pin);
  79. }
  80. /****************************************************************************/
  81. void Pins::pinMode(int pin, int dir)
  82. {
  83. pin_modes.at(pin) = dir;
  84. log.sketch("PINS","%s %s",pin_log_name(pin).c_str(),dir?"OUTPUT":"INPUT");
  85. }
  86. /****************************************************************************/
  87. void Pins::pinSymbol(int pin, const std::string& symbol)
  88. {
  89. symbol_map[pin] = symbol;
  90. symbol_reverse_map[symbol] = pin;
  91. }
  92. /****************************************************************************/
  93. void Pins::attachInterrupt(int irq, void (*isr)(void))
  94. {
  95. isr_table.at(irq) = isr;
  96. log.sketch("IRQ","%i attached",irq);
  97. }
  98. /****************************************************************************/
  99. void Pins::detachInterrupt(int irq)
  100. {
  101. attachInterrupt(irq,NULL);
  102. log.sketch("IRQ","%i detached",irq);
  103. }
  104. /****************************************************************************/
  105. void Pins::hwTriggerInterrupt(int irq) const
  106. {
  107. if ( ! isr_table.at(irq) )
  108. throw new runtime_error("No handler assigned for this interrupt");
  109. log.internal("IRQ","%i triggered",irq);
  110. isr_table[irq]();
  111. }
  112. /****************************************************************************/
  113. bool Pins::runCommand( const Parser& parser )
  114. {
  115. bool result = false;
  116. const string& command = parser.at(0);
  117. if ( command == "pins" )
  118. {
  119. result = command_pins(parser);
  120. }
  121. else if ( command == "pin" )
  122. {
  123. result = command_pin(parser);
  124. }
  125. else if ( command == "irq" )
  126. {
  127. result = command_irq(parser);
  128. }
  129. else if ( command == "help" )
  130. {
  131. const string& helpcommand = parser.at(1);
  132. if ( helpcommand == "pins" )
  133. {
  134. cout << "pins -- list current state of all pins" << endl;
  135. }
  136. else if ( helpcommand == "pin" )
  137. {
  138. cout << "pin <#> HIGH|LOW -- set digital pin high or low" << endl;
  139. cout << "pin A<#> <value> -- set analog pin to value" << endl;
  140. cout << "pin <#> is <symbol> -- assign a symbolic name to a digitial pin" << endl;
  141. cout << "pin <#> press -- toggle value of pin and back after 50ms" << endl;
  142. }
  143. else if ( helpcommand == "irq" )
  144. {
  145. cout << "irq <#> -- trigger irq <#>" << endl;
  146. }
  147. result = true;
  148. }
  149. // is this a pin symbol we are aware of?
  150. else if ( symbol_reverse_map.count(command) )
  151. {
  152. // translate it to "pin X press"
  153. Parser press;
  154. press.resize(3);
  155. press.at(0) = "pin";
  156. press.at(1) = command;
  157. press.at(2) = "press";
  158. result = command_pin(press);
  159. }
  160. return result;
  161. }
  162. /****************************************************************************/
  163. bool Pins::command_pin_digital(vector<string>::const_iterator current,vector<string>::const_iterator end)
  164. {
  165. bool press = false;
  166. int pin;
  167. char c = (*current)[0];
  168. if ( c >= '0' && c <= '9' )
  169. {
  170. istringstream ss(*current);
  171. ss >> pin;
  172. }
  173. else
  174. {
  175. // This is a pin symbol
  176. if ( symbol_reverse_map.count(*current) )
  177. pin = symbol_reverse_map.at(*current);
  178. else
  179. throw new runtime_error("Unknown pin value");
  180. }
  181. current++;
  182. if ( pin < 0 || pin >= num_pins )
  183. throw new runtime_error("Pin out of range");
  184. // Get the level, high or low
  185. if ( current == end )
  186. throw new runtime_error("Expecting pin level");
  187. int level = LOW;
  188. if ( *current == "high" )
  189. level = HIGH;
  190. else if ( *current == "low" )
  191. level = LOW;
  192. else if ( *current == "press" )
  193. {
  194. level = hwGetDigital(pin) ^ HIGH;
  195. press = true;
  196. }
  197. else if ( *current == "is" )
  198. {
  199. // This is setting a pin symbol.
  200. if ( ++current == end )
  201. throw new runtime_error("Expecting symbol name");
  202. pinSymbol(pin,*current);
  203. }
  204. else
  205. {
  206. throw new runtime_error("Unknown level value");
  207. }
  208. ++current;
  209. // Make sure we're at the end of input
  210. if ( current != end )
  211. throw new runtime_error("Unexpected tokens at end of input");
  212. hwSetDigital( pin, level );
  213. if ( press )
  214. {
  215. Clock().delay(50);
  216. hwSetDigital( pin, level ^ HIGH );
  217. }
  218. return true;
  219. }
  220. /****************************************************************************/
  221. bool Pins::command_pin_analog(vector<string>::const_iterator current,vector<string>::const_iterator end)
  222. {
  223. string pin_str = (*current++).substr(1);
  224. istringstream ss(pin_str);
  225. int pin;
  226. ss >> pin;
  227. if ( pin < 0 || pin >= num_channels )
  228. throw new runtime_error("Analog channel out of range");
  229. if ( current == end )
  230. throw new runtime_error("Expecting pin level");
  231. char c = (*current)[0];
  232. if ( c < '0' || c > '9' )
  233. throw new runtime_error("Unknown level value");
  234. int level;
  235. istringstream ss_level(*current++);
  236. ss_level >> level;
  237. if ( level < 0 || level >= 1024 )
  238. throw new runtime_error("Level value out of range");
  239. // Make sure we're at the end of input
  240. if ( current != end )
  241. throw new runtime_error("Unexpected tokens at end of input");
  242. hwSetAnalog( pin, level );
  243. return true;
  244. }
  245. /****************************************************************************/
  246. bool Pins::command_pin(const vector<string>& _commands)
  247. {
  248. vector<string>::const_iterator current = _commands.begin();
  249. // Skip over 'pin' command
  250. ++current;
  251. // Get the pin number
  252. if ( current == _commands.end() )
  253. throw new runtime_error("Expecting pin number");
  254. // Is this an analog channel?
  255. string pin_str = *current;
  256. bool analog = ( pin_str[0] == 'a' );
  257. if ( analog )
  258. return command_pin_analog(current,_commands.end());
  259. else
  260. return command_pin_digital(current,_commands.end());
  261. }
  262. /****************************************************************************/
  263. bool Pins::command_pins(const vector<string>&) const
  264. {
  265. int counter = 0;
  266. cout << "DIGITAL PINS: ";
  267. vector<int>::const_iterator digital = digital_states.begin();
  268. while ( digital != digital_states.end() )
  269. {
  270. cout << dec << counter++ << ":" << *digital << " ";
  271. ++digital;
  272. }
  273. cout << endl;
  274. counter = 0;
  275. cout << "ANALOG PINS: ";
  276. vector<int>::const_iterator analog = analog_states.begin();
  277. while ( analog != analog_states.end() )
  278. {
  279. cout << dec << counter++ << ":" << *analog << " ";
  280. ++analog;
  281. }
  282. cout << endl;
  283. return true;
  284. }
  285. /****************************************************************************/
  286. bool Pins::command_irq(const vector<string>& _commands) const
  287. {
  288. vector<string>::const_iterator current = _commands.begin();
  289. // Skip over 'irq' command
  290. ++current;
  291. // Get the irq number
  292. if ( current == _commands.end() )
  293. throw new runtime_error("Expecting irq number");
  294. char c = (*current)[0];
  295. if ( c < '0' || c > '9' )
  296. throw new runtime_error("Unknown irq number");
  297. istringstream ss(*current++);
  298. int irq;
  299. ss >> irq;
  300. if ( irq < 0 || irq >= num_interrupts )
  301. throw new runtime_error("Interrupt number out of range");
  302. // Make sure we're at the end of input
  303. if ( current != _commands.end() )
  304. throw new runtime_error("Unexpected tokens at end of input");
  305. hwTriggerInterrupt( irq );
  306. return true;
  307. }
  308. /****************************************************************************/
  309. // vim:cin:ai:sts=2 sw=2 ft=cpp