You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. #include <Arduino.h>
  2. #include <HC05.h>
  3. #ifdef DEBUG_SW_PORT
  4. SoftwareSerial DEBUG_SW_PORT;
  5. #endif
  6. #ifdef HC05_SOFTWARE_SERIAL
  7. HC05::HC05(int cmdPin, int statePin, uint8_t rx, uint8_t tx):_btSerial(rx,tx,0)
  8. #else
  9. #define _btSerial HC05_HW_SERIAL_PORT
  10. HC05::HC05(int cmdPin, int statePin)
  11. #endif
  12. {
  13. pinMode(cmdPin, OUTPUT);
  14. _cmdPin = cmdPin;
  15. cmdMode = false;
  16. #ifdef HC05_STATE_PIN
  17. pinMode(statePin, INPUT);
  18. _statePin = statePin;
  19. #endif
  20. _bufsize = sizeof(_buffer)/sizeof(char);
  21. }
  22. static const unsigned long rates[] =
  23. {4800,9600,19200,38400,57600,115200};
  24. unsigned long HC05::findBaud()
  25. {
  26. const int bt_rx = 4;
  27. const int bt_tx = 5;
  28. int numRates = sizeof(rates)/sizeof(unsigned long);
  29. int response = false;
  30. int recvd = 0;
  31. //char _buffer[128];
  32. DEBUG_PRINTLN("findBaud");
  33. setCmdPin(HIGH);
  34. delay(100);
  35. for(int rn = 0; rn < numRates; rn++)
  36. {
  37. _btSerial.begin(rates[rn]);
  38. _btSerial.setTimeout(100);
  39. _btSerial.flush();
  40. DEBUG_WRITE("Trying ");
  41. DEBUG_PRINT(rates[rn]);
  42. DEBUG_WRITE("... ");
  43. _btSerial.write("AT\r\n");
  44. recvd = _btSerial.readBytes(_buffer,_bufsize);
  45. if (recvd > 0)
  46. {
  47. DEBUG_PRINTLN("Found.");
  48. // FIXME: refactor to a single return
  49. setCmdPin(LOW);
  50. return(rates[rn]);
  51. }
  52. else
  53. {
  54. DEBUG_PRINTLN("x");
  55. }
  56. }
  57. setCmdPin(LOW);
  58. DEBUG_WRITE("\r\nNo connection\r\n");
  59. return(0);
  60. }
  61. bool HC05::cmd(String cmd, unsigned long timeout)
  62. {
  63. return this->cmd(cmd.c_str(), timeout);
  64. }
  65. bool HC05::cmd(const char* cmd, unsigned long timeout)
  66. {
  67. _lastError = -1;
  68. _stringBuffer = "";
  69. _stringData = "";
  70. int recvd = 0;
  71. DEBUG_PRINTLN(cmd);
  72. setCmdPin(HIGH);
  73. // No spec for how long it takes to enter command mode, but 100ms
  74. // seems to work- assuming the output has been drained.
  75. delay(100);
  76. _btSerial.write(cmd);
  77. _btSerial.write("\r\n");
  78. _btSerial.setTimeout(timeout);
  79. do
  80. {
  81. // ATTENTION: At least through Arduino v1.0.3, it is not possible
  82. // to tell the difference between a timeout and
  83. // receiving only the termination character (NL in this
  84. // case), because the termination character is not
  85. // returned and timeout is not returned as a unique
  86. // indication.
  87. // In this case the result would be an early return
  88. // of a multiline response before the OK is received.
  89. // The return would incorrectly indicate an error (no
  90. // OK response).
  91. recvd = _btSerial.readBytesUntil('\n', _buffer, _bufsize);
  92. if (recvd > 0)
  93. {
  94. _buffer[recvd] = 0;
  95. _stringBuffer += _buffer;
  96. _stringBuffer += "\n";
  97. // DEBUG_WRITE((uint8_t *)_buffer,recvd);
  98. // DEBUG_WRITE('\n');
  99. }
  100. else
  101. {
  102. DEBUG_PRINTLN("timeout 1");
  103. }
  104. }
  105. while ((recvd > 0) && (_buffer[0] != 'O' || _buffer[1] != 'K'));
  106. setCmdPin(LOW);
  107. // Empirically determined that it takes some time to reliably exit
  108. // command mode. The appeared to be a baud rate dependency and with
  109. // >100ms required at 9600 baud.
  110. delay(150);
  111. DEBUG_WRITE(_stringBuffer.c_str());
  112. if (_buffer[0] == 'O' && _buffer[1] == 'K') {
  113. return true;
  114. }
  115. if (_stringBuffer.startsWith("ERROR:(")) {
  116. String errorCode = _stringBuffer.substring(7, _stringBuffer.length() - 3);
  117. _lastError = errorCode.toInt();
  118. DEBUG_WRITE("Error: ");
  119. DEBUG_PRINTLN(_lastError);
  120. } else {
  121. _lastError = -1;
  122. }
  123. return false;
  124. }
  125. /*
  126. * If setBaud() is called while the HC-05 is connected, then
  127. * it will be disconnected when AT+RESET command is issued, and
  128. * it may take 2 (or more?) connection attempts to reconnect. The extra
  129. * connect attempts may be a host side issue and not specific to the
  130. * HC-05 module.
  131. */
  132. void HC05::setBaud(unsigned long baud, unsigned long stopbits, unsigned long parity)
  133. {
  134. int recvd = 0;
  135. setCmdPin(HIGH);
  136. delay(200);
  137. DEBUG_WRITE("AT+UART=");
  138. _btSerial.write("AT+UART=");
  139. DEBUG_PRINT(baud);
  140. _btSerial.print(baud);
  141. DEBUG_PRINT(",");
  142. _btSerial.print(",");
  143. DEBUG_PRINT(stopbits);
  144. _btSerial.print(stopbits);
  145. DEBUG_PRINT(",");
  146. _btSerial.print(",");
  147. DEBUG_PRINT(parity);
  148. _btSerial.print(parity);
  149. DEBUG_WRITE("\r\n");
  150. _btSerial.write("\r\n");
  151. recvd = _btSerial.readBytes(_buffer,_bufsize);
  152. if (recvd > 0)
  153. {
  154. DEBUG_WRITE((uint8_t *)_buffer,recvd);
  155. }
  156. else
  157. {
  158. DEBUG_PRINTLN("timeout 2");
  159. }
  160. cmd("AT+RESET");
  161. setCmdPin(LOW);
  162. _btSerial.begin(baud);
  163. delay(1000);
  164. }
  165. // Usually parity is none, and there is only one stop bit, so this
  166. // simpler call will do the job.
  167. void HC05::setBaud(unsigned long baud)
  168. {
  169. setBaud(baud, 0, 0);
  170. }
  171. int HC05::available()
  172. {
  173. _btSerial.available();
  174. }
  175. int HC05::peek()
  176. {
  177. _btSerial.peek();
  178. }
  179. void HC05::flush()
  180. {
  181. _btSerial.flush();
  182. }
  183. int HC05::read()
  184. {
  185. _btSerial.read();
  186. }
  187. void HC05::begin(unsigned long baud)
  188. {
  189. _btSerial.begin(baud);
  190. }
  191. #ifndef HC05_SOFTWARE_SERIAL
  192. // only hardware serial ports support parity/stop bit configuration
  193. void HC05::begin(unsigned long baud, uint8_t config)
  194. {
  195. _btSerial.begin(baud, config);
  196. }
  197. #endif
  198. #ifdef HC05_STATE_PIN
  199. bool HC05::connected()
  200. {
  201. return(digitalRead(_statePin)?true:false);
  202. }
  203. #endif
  204. size_t HC05::write(uint8_t byte)
  205. {
  206. #ifdef HC05_STATE_PIN
  207. // The down side of this check is that the status gets checked for
  208. // every byte written out. That doesn't seem efficient.
  209. if (digitalRead(_statePin) != HIGH)
  210. {
  211. DEBUG_PRINT("No Connection, waiting...");
  212. while (digitalRead(_statePin) == LOW)
  213. {
  214. delay(100);
  215. }
  216. DEBUG_PRINTLN("OK");
  217. }
  218. #endif
  219. _btSerial.write(byte);
  220. }
  221. void HC05::cmdMode2Start(int pwrPin)
  222. {
  223. pinMode(pwrPin, OUTPUT);
  224. digitalWrite(pwrPin, LOW);
  225. delay(250); // off or reset time
  226. digitalWrite(_cmdPin, HIGH);
  227. digitalWrite(pwrPin, HIGH);
  228. cmdMode = true;
  229. _btSerial.begin(38400);
  230. delay(1500); // time for the HC05 to initialize
  231. }
  232. void HC05::cmdMode2End(void)
  233. {
  234. digitalWrite(_cmdPin, LOW);
  235. cmdMode = false;
  236. delay(1000);
  237. }
  238. void HC05::setCmdPin(bool state)
  239. {
  240. if (cmdMode == false)
  241. {
  242. digitalWrite(_cmdPin, state);
  243. }
  244. }
  245. bool HC05::atGetCommand(String command, unsigned long timeout)
  246. {
  247. return this->atGetCommand1(command, "", timeout);
  248. }
  249. bool HC05::atGetCommand1(String command, String arg1, unsigned long timeout)
  250. {
  251. if (this->cmd("AT+" + command + "?" + arg1, timeout)) {
  252. if (_stringBuffer.startsWith("+" + command + ":")) {
  253. _stringData = _stringBuffer.substring(command.length() + 2, _stringBuffer.length() - 6);
  254. DEBUG_PRINTLN(_stringData);
  255. }
  256. return true;
  257. }
  258. return false;
  259. }
  260. bool HC05::atTest(unsigned long timeout)
  261. {
  262. return this->cmd("AT", timeout);
  263. }
  264. bool HC05::atReset(unsigned long timeout)
  265. {
  266. return this->cmd("AT+RESET", timeout);
  267. }
  268. bool HC05::atVersion(unsigned long timeout)
  269. {
  270. return this->atGetCommand("VERSION", timeout);
  271. }
  272. bool HC05::atRestore(unsigned long timeout)
  273. {
  274. return this->cmd("AT+ORGL", timeout);
  275. }
  276. bool HC05::atGetAddress(unsigned long timeout)
  277. {
  278. return this->atGetCommand("ADDR", timeout);
  279. }
  280. bool HC05::atGetName(unsigned long timeout)
  281. {
  282. return this->atGetCommand("NAME", timeout);
  283. }
  284. bool HC05::atSetName(String name, unsigned long timeout)
  285. {
  286. return this->cmd("AT+NAME=" + name, timeout);
  287. }
  288. bool HC05::atGetRemoteName(String address, unsigned long timeout)
  289. {
  290. return this->atGetCommand1("RNAME", address, timeout);
  291. }
  292. bool HC05::atGetRole(unsigned long timeout)
  293. {
  294. return this->atGetCommand("ROLE", timeout);
  295. }
  296. bool HC05::atSetRole(Roles role, unsigned long timeout)
  297. {
  298. return this->cmd("AT+ROLE=" + role, timeout);
  299. }
  300. bool HC05::atGetPassKey(unsigned long timeout)
  301. {
  302. return this->atGetCommand("PSWD", timeout);
  303. }
  304. bool HC05::atSetPassKey(String passKey, unsigned long timeout)
  305. {
  306. return this->cmd("AT+PSWD=" + passKey, timeout);
  307. }