PageRenderTime 25ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/hardware/onewire/ecmd.c

https://github.com/jochen/ethersex
C | 507 lines | 370 code | 72 blank | 65 comment | 74 complexity | 4fe45b7ac6191ea505df6c9359812503 MD5 | raw file
Possible License(s): GPL-3.0
  1. /*
  2. *
  3. * Copyright (c) by Alexander Neumann <alexander@bumpern.de>
  4. * Copyright (c) 2007 by Stefan Siegl <stesie@brokenpipe.de>
  5. * Copyright (c) 2007 by Christian Dietrich <stettberger@dokucode.de>
  6. *
  7. * This program is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License (either version 2 or
  9. * version 3) as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. *
  20. * For more information on the GPL, please go to:
  21. * http://www.gnu.org/copyleft/gpl.html
  22. */
  23. #include <string.h>
  24. #include <avr/pgmspace.h>
  25. #include <avr/eeprom.h>
  26. #include <avr/interrupt.h>
  27. #include "config.h"
  28. #include "core/debug.h"
  29. #include "core/eeprom.h"
  30. #include "core/bit-macros.h"
  31. #include "hardware/onewire/onewire.h"
  32. #include "protocols/ecmd/ecmd-base.h"
  33. /* parse an onewire rom address at cmd, write result to ptr */
  34. int8_t parse_ow_rom(char *cmd, ow_rom_code_t *rom)
  35. {
  36. uint8_t *addr = rom->bytewise;
  37. uint8_t end;
  38. #ifdef DEBUG_ECMD_OW_ROM
  39. debug_printf("called parse_ow_rom with string '%s'\n", cmd);
  40. #endif
  41. /* read 8 times 2 hex chars into a byte */
  42. int ret = sscanf_P(cmd, PSTR("%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%c"),
  43. addr+0, addr+1, addr+2, addr+3,
  44. addr+4, addr+5, addr+6, addr+7,
  45. &end);
  46. #ifdef DEBUG_ECMD_OW_ROM
  47. debug_printf("scanf returned %d\n", ret);
  48. #endif
  49. if ((ret == 8) || ((ret == 9) && (end == ' '))) {
  50. #ifdef DEBUG_ECMD_OW_ROM
  51. debug_printf("read rom %02x %02x %02x %02x %02x %02x %02x %02x\n",
  52. addr[0], addr[1], addr[2], addr[3],
  53. addr[4], addr[5], addr[6], addr[7]);
  54. #endif
  55. return 0;
  56. }
  57. return -1;
  58. }
  59. #ifdef ONEWIRE_DETECT_SUPPORT
  60. #ifdef ONEWIRE_POLLING_SUPPORT
  61. int16_t parse_cmd_onewire_list(char *cmd, char *output, uint16_t len)
  62. {
  63. #ifdef ONEWIRE_DS2502_SUPPORT
  64. int8_t list_type;
  65. while (*cmd == ' ')
  66. cmd++;
  67. switch (*cmd) {
  68. case 't':
  69. list_type = OW_LIST_TYPE_TEMP_SENSOR;
  70. break;
  71. case 'e':
  72. list_type = OW_LIST_TYPE_EEPROM;
  73. break;
  74. case '\0':
  75. list_type = OW_LIST_TYPE_ALL;
  76. break;
  77. default:
  78. return ECMD_ERR_PARSE_ERROR;
  79. }
  80. cmd++; /* for static bytes */
  81. #endif
  82. /* trick: use bytes on cmd as "connection specific static variables" */
  83. if (cmd[0] != 23) /* indicator flag: real invocation: 0 */
  84. {
  85. cmd[0] = 23; /* continuing call: 23 */
  86. cmd[1] = 0; /* counter for sensors in list*/
  87. }
  88. uint8_t i = cmd[1];
  89. /* This is a special case: the while loop below printed a sensor which was last in the list,
  90. so we still need to send an 'OK' after the sensor id */
  91. if(i>=OW_SENSORS_COUNT)
  92. {
  93. return ECMD_FINAL_OK;
  94. }
  95. int16_t ret = 0;
  96. do
  97. {
  98. if(ow_sensors[i].ow_rom_code.raw != 0)
  99. {
  100. #ifdef ONEWIRE_DS2502_SUPPORT
  101. if ((list_type == OW_LIST_TYPE_ALL) || (list_type == OW_LIST_TYPE_TEMP_SENSOR && ow_temp_sensor(&ow_sensors[i].ow_rom_code)) || (list_type == OW_LIST_TYPE_EEPROM && ow_eeprom(&ow_sensors[i].ow_rom_code))) {
  102. #endif
  103. ret = snprintf_P(output, len,
  104. PSTR("%02x%02x%02x%02x%02x%02x%02x%02x"),
  105. ow_sensors[i].ow_rom_code.bytewise[0],
  106. ow_sensors[i].ow_rom_code.bytewise[1],
  107. ow_sensors[i].ow_rom_code.bytewise[2],
  108. ow_sensors[i].ow_rom_code.bytewise[3],
  109. ow_sensors[i].ow_rom_code.bytewise[4],
  110. ow_sensors[i].ow_rom_code.bytewise[5],
  111. ow_sensors[i].ow_rom_code.bytewise[6],
  112. ow_sensors[i].ow_rom_code.bytewise[7]
  113. );
  114. #ifdef ONEWIRE_DS2502_SUPPORT
  115. }
  116. #endif
  117. }
  118. i++;
  119. } while(ret == 0 && i<OW_SENSORS_COUNT);
  120. /* The while loop exited either because a sensor has been found or because there is no sensor left, let's check for that */
  121. if(ret == 0)
  122. {
  123. /* => i has reached OW_SENSORS_COUNT */
  124. return ECMD_FINAL_OK;
  125. }
  126. /* else, ret is != 0 which means a sensor has been found and this functions has to be called again
  127. to prevent a buffer overflow
  128. */
  129. /* Save i to cmd[1] */
  130. cmd[1] = i;
  131. return ECMD_AGAIN(ret);
  132. }
  133. #else
  134. int16_t parse_cmd_onewire_list(char *cmd, char *output, uint16_t len)
  135. {
  136. uint8_t firstonbus = 0;
  137. int16_t ret;
  138. if (ow_global.lock == 0) {
  139. firstonbus = 1;
  140. #if ONEWIRE_BUSCOUNT > 1
  141. ow_global.bus = 0;
  142. #endif
  143. #ifdef DEBUG_ECMD_OW_LIST
  144. debug_printf("called onewire list for the first time\n");
  145. #endif
  146. #ifdef ONEWIRE_DS2502_SUPPORT
  147. /* parse optional parameters */
  148. while (*cmd == ' ')
  149. cmd++;
  150. switch (*cmd) {
  151. case 't':
  152. ow_global.list_type = OW_LIST_TYPE_TEMP_SENSOR;
  153. break;
  154. case 'e':
  155. ow_global.list_type = OW_LIST_TYPE_EEPROM;
  156. break;
  157. case '\0':
  158. ow_global.list_type = OW_LIST_TYPE_ALL;
  159. break;
  160. default:
  161. return ECMD_ERR_PARSE_ERROR;
  162. }
  163. #endif
  164. } else {
  165. #ifdef DEBUG_ECMD_OW_LIST
  166. debug_printf("called onewire list again\n");
  167. #endif
  168. firstonbus = 0;
  169. }
  170. #if defined ONEWIRE_DS2502_SUPPORT || ONEWIRE_BUSCOUNT > 1
  171. list_next: ;
  172. #endif
  173. /* disable interrupts */
  174. uint8_t sreg = SREG;
  175. cli();
  176. #if ONEWIRE_BUSCOUNT > 1
  177. ret = ow_search_rom((uint8_t)(1 << (ow_global.bus + ONEWIRE_STARTPIN)), firstonbus);
  178. #else
  179. ret = ow_search_rom(ONEWIRE_BUSMASK, firstonbus);
  180. #endif
  181. /* re-enable interrupts */
  182. SREG = sreg;
  183. /* make sure only one conversion happens at a time */
  184. ow_global.lock = 1;
  185. if (ret == 1) {
  186. #ifdef ONEWIRE_DS2502_SUPPORT
  187. if ((ow_global.list_type == OW_LIST_TYPE_ALL) ||
  188. ((ow_global.list_type == OW_LIST_TYPE_TEMP_SENSOR) &&
  189. (ow_temp_sensor(&ow_global.current_rom))) ||
  190. ((ow_global.list_type == OW_LIST_TYPE_EEPROM) &&
  191. (ow_eeprom(&ow_global.current_rom)))) {
  192. /* only print device rom address if it matches the selected list type */
  193. #endif
  194. #ifdef DEBUG_ECMD_OW_LIST
  195. debug_printf("discovered device "
  196. #if ONEWIRE_BUSCOUNT > 1
  197. "%02x %02x %02x %02x %02x %02x %02x %02x on bus %d\n",
  198. #else
  199. "%02x %02x %02x %02x %02x %02x %02x %02x\n",
  200. #endif
  201. ow_global.current_rom.bytewise[0],
  202. ow_global.current_rom.bytewise[1],
  203. ow_global.current_rom.bytewise[2],
  204. ow_global.current_rom.bytewise[3],
  205. ow_global.current_rom.bytewise[4],
  206. ow_global.current_rom.bytewise[5],
  207. ow_global.current_rom.bytewise[6],
  208. ow_global.current_rom.bytewise[7]
  209. #if ONEWIRE_BUSCOUNT > 1
  210. ,ow_global.bus);
  211. #else
  212. );
  213. #endif
  214. #endif
  215. ret = snprintf_P(output, len,
  216. PSTR("%02x%02x%02x%02x%02x%02x%02x%02x"),
  217. ow_global.current_rom.bytewise[0],
  218. ow_global.current_rom.bytewise[1],
  219. ow_global.current_rom.bytewise[2],
  220. ow_global.current_rom.bytewise[3],
  221. ow_global.current_rom.bytewise[4],
  222. ow_global.current_rom.bytewise[5],
  223. ow_global.current_rom.bytewise[6],
  224. ow_global.current_rom.bytewise[7]);
  225. #ifdef DEBUG_ECMD_OW_LIST
  226. debug_printf("generated %d bytes\n", ret);
  227. #endif
  228. /* set return value that the parser has to be called again */
  229. if (ret > 0)
  230. ret = ECMD_AGAIN(ret);
  231. #ifdef DEBUG_ECMD_OW_LIST
  232. debug_printf("returning %d\n", ret);
  233. #endif
  234. return ECMD_FINAL(ret);
  235. #ifdef ONEWIRE_DS2502_SUPPORT
  236. } else {
  237. /* device did not match list type: try again */
  238. firstonbus = 0;
  239. goto list_next;
  240. }
  241. #endif
  242. }
  243. #if ONEWIRE_BUSCOUNT > 1
  244. #ifdef DEBUG_ECMD_OW_LIST
  245. if (ret != 0) {
  246. debug_printf("no devices on bus %d\n", ow_global.bus);
  247. }
  248. #endif
  249. if (ow_global.bus < ONEWIRE_BUSCOUNT - 1) {
  250. ow_global.bus++;
  251. firstonbus = 1;
  252. goto list_next;
  253. }
  254. #endif
  255. ow_global.lock = 0;
  256. return ECMD_FINAL_OK;
  257. }
  258. #endif /* ONEWIRE_POLLING_SUPPORT*/
  259. #endif /* ONEWIRE_DETECT_SUPPORT */
  260. #ifdef ONEWIRE_POLLING_SUPPORT
  261. int16_t parse_cmd_onewire_get(char *cmd, char *output, uint16_t len)
  262. {
  263. ow_rom_code_t rom;
  264. int16_t ret;
  265. ret = parse_ow_rom(cmd, &rom);
  266. if (ret < 0)
  267. return ECMD_ERR_PARSE_ERROR;
  268. if (ow_temp_sensor(&rom)) {
  269. /*Search the sensor...*/
  270. for(uint8_t i=0;i<OW_SENSORS_COUNT;i++)
  271. {
  272. if(ow_sensors[i].ow_rom_code.raw == rom.raw)
  273. {
  274. /*Found it*/
  275. int16_t temp=ow_sensors[i].temp;
  276. div_t res = div(temp,10);
  277. ret = snprintf_P(output, len, PSTR("%d.%1d"), res.quot,res.rem);
  278. return ECMD_FINAL(ret);
  279. }
  280. }
  281. /*Sensor is not in list*/
  282. ret = snprintf_P(output, len, PSTR("Sensor not in list!"));
  283. return ECMD_FINAL(ret);
  284. #ifdef ONEWIRE_DS2502_SUPPORT
  285. } else if (ow_eeprom(&rom)) {
  286. debug_printf("reading mac\n");
  287. /* disable interrupts */
  288. uint8_t sreg = SREG;
  289. cli();
  290. uint8_t mac[6];
  291. ret = ow_eeprom_read(&rom, mac);
  292. /* re-enable interrupts */
  293. SREG = sreg;
  294. if (ret != 0) {
  295. debug_printf("mac read failed: %d\n", ret);
  296. return ECMD_ERR_READ_ERROR;
  297. }
  298. debug_printf("successfully read mac\n");
  299. debug_printf("mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
  300. mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  301. ret = snprintf_P(output, len,
  302. PSTR("mac: %02x:%02x:%02x:%02x:%02x:%02x"),
  303. mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  304. #endif /* ONEWIRE_DS2502_SUPPORT */
  305. } else {
  306. debug_printf("unknown sensor type\n");
  307. #ifdef TEENSY_SUPPORT
  308. strcpy_P (output, PSTR("unknown sensor type"));
  309. return ECMD_FINAL(strlen(output));
  310. #else
  311. ret = snprintf_P(output, len, PSTR("unknown sensor type"));
  312. #endif
  313. }
  314. return ECMD_FINAL(ret);
  315. }
  316. #else
  317. int16_t parse_cmd_onewire_get(char *cmd, char *output, uint16_t len)
  318. {
  319. ow_rom_code_t rom;
  320. int16_t ret;
  321. while (*cmd == ' ')
  322. cmd++;
  323. debug_printf("called onewire_get with: \"%s\"\n", cmd);
  324. ret = parse_ow_rom(cmd, &rom);
  325. /* check for parse error */
  326. if (ret < 0)
  327. return ECMD_ERR_PARSE_ERROR;
  328. if (ow_temp_sensor(&rom)) {
  329. debug_printf("reading temperature\n");
  330. /* disable interrupts */
  331. uint8_t sreg = SREG;
  332. cli();
  333. ow_temp_scratchpad_t sp;
  334. ret = ow_temp_read_scratchpad(&rom, &sp);
  335. /* re-enable interrupts */
  336. SREG = sreg;
  337. if (ret != 1) {
  338. debug_printf("scratchpad read failed: %d\n", ret);
  339. return ECMD_ERR_READ_ERROR;
  340. }
  341. debug_printf("successfully read scratchpad\n");
  342. int16_t temp = ow_temp_normalize(&rom, &sp);
  343. debug_printf("temperature: %d.%d\n", HI8(temp), LO8(temp) > 0 ? 5 : 0);
  344. int8_t sign = (int8_t)(temp < 0);
  345. #ifdef TEENSY_SUPPORT
  346. if (sign) {
  347. temp = -temp;
  348. output[0] = '-';
  349. }
  350. /* Here sign is 0 or 1 */
  351. itoa (HI8(temp), output + sign, 10);
  352. char *ptr = output + strlen (output);
  353. *(ptr ++) = '.';
  354. itoa (HI8(((temp & 0x00ff) * 10) + 0x80), ptr, 10);
  355. return ECMD_FINAL(strlen(output));
  356. #else
  357. if (sign) temp = -temp;
  358. ret = snprintf_P(output, len, PSTR("%s%d.%1d"),
  359. sign?"-":"", (int8_t) HI8(temp), HI8(((temp & 0x00ff) * 10) + 0x80));
  360. #endif
  361. #ifdef ONEWIRE_DS2502_SUPPORT
  362. } else if (ow_eeprom(&rom)) {
  363. debug_printf("reading mac\n");
  364. /* disable interrupts */
  365. uint8_t sreg = SREG;
  366. cli();
  367. uint8_t mac[6];
  368. ret = ow_eeprom_read(&rom, mac);
  369. /* re-enable interrupts */
  370. SREG = sreg;
  371. if (ret != 0) {
  372. debug_printf("mac read failed: %d\n", ret);
  373. return ECMD_ERR_READ_ERROR;
  374. }
  375. debug_printf("successfully read mac\n");
  376. debug_printf("mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
  377. mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  378. ret = snprintf_P(output, len,
  379. PSTR("mac: %02x:%02x:%02x:%02x:%02x:%02x"),
  380. mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  381. #endif /* ONEWIRE_DS2502_SUPPORT */
  382. } else {
  383. debug_printf("unknown sensor type\n");
  384. #ifdef TEENSY_SUPPORT
  385. strcpy_P (output, PSTR("unknown sensor type"));
  386. return ECMD_FINAL(strlen(output));
  387. #else
  388. ret = snprintf_P(output, len, PSTR("unknown sensor type"));
  389. #endif
  390. }
  391. return ECMD_FINAL(ret);
  392. }
  393. #endif
  394. #ifdef ONEWIRE_POLLING_SUPPORT
  395. int16_t parse_cmd_onewire_convert(char *cmd, char *output, uint16_t len)
  396. {
  397. return ECMD_FINAL_OK;
  398. }
  399. #else
  400. int16_t parse_cmd_onewire_convert(char *cmd, char *output, uint16_t len)
  401. {
  402. int16_t ret;
  403. while (*cmd == ' ')
  404. cmd++;
  405. debug_printf("called onewire_convert with: \"%s\"\n", cmd);
  406. ow_rom_code_t rom, *romptr;
  407. ret = parse_ow_rom(cmd, &rom);
  408. /* check for romcode */
  409. romptr = (ret < 0) ? NULL : &rom;
  410. debug_printf("converting temperature...\n");
  411. /* disable interrupts */
  412. uint8_t sreg = SREG;
  413. cli();
  414. ret = ow_temp_start_convert_wait(romptr);
  415. SREG = sreg;
  416. if (ret == 1)
  417. /* done */
  418. return ECMD_FINAL_OK;
  419. else if (ret == -1)
  420. /* no device attached */
  421. return ECMD_ERR_READ_ERROR;
  422. else
  423. /* wrong rom family code */
  424. return ECMD_ERR_PARSE_ERROR;
  425. }
  426. #endif
  427. /*
  428. -- Ethersex META --
  429. block([[Dallas_1-wire_Bus]])
  430. ecmd_ifdef(ONEWIRE_DETECT_SUPPORT)
  431. ecmd_feature(onewire_list, "1w list",,Return a list of the connected onewire devices)
  432. ecmd_endif()
  433. ecmd_feature(onewire_get, "1w get", DEVICE, Return temperature value of onewire DEVICE (provide 64-bit ID as 16-hex-digits))
  434. ecmd_feature(onewire_convert, "1w convert", [DEVICE], Trigger temperature conversion of either DEVICE or all connected devices)
  435. */