S&B Volcano vaporizer remote control with Pi Pico W
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

volcano.c 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /*
  2. * volcano.c
  3. *
  4. * Copyright (c) 2023 Thomas Buck (thomas@xythobuz.de)
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  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. * See <http://www.gnu.org/licenses/>.
  17. */
  18. #include "config.h"
  19. #include "log.h"
  20. #include "ble.h"
  21. #include "volcano.h"
  22. #define UUID_SRVC_1 0x10
  23. #define UUID_PRJSTAT1 0x0C
  24. #define UUID_PRJSTAT2 0x0D
  25. #define UUID_PRJSTAT3 0x0E
  26. #define UUID_SRVC_2 0x11
  27. #define UUID_WRITE_SRVC 0x00
  28. #define UUID_CURRENT_TEMP 0x01
  29. #define UUID_TARGET_TEMP 0x03
  30. #define UUID_HEATER_ON 0x0F
  31. #define UUID_HEATER_OFF 0x10
  32. #define UUID_PUMP_ON 0x13
  33. #define UUID_PUMP_OFF 0x14
  34. #define MASK_PRJSTAT1_HEIZUNG_ENA 0x0020
  35. #define MASK_PRJSTAT1_AUTOBLESHUTDOWN 0x0200
  36. #define MASK_PRJSTAT1_PUMPE_FET_ENABLE 0x2000
  37. #define MASK_PRJSTAT2_FAHRENHEIT_ENA 0x0200
  38. #define MASK_PRJSTAT2_DISPLAY_ON_COOLING 0x1000
  39. #define MASK_PRJSTAT3_VIBRATION 0x0400
  40. // "10xx00xx-5354-4f52-5a26-4249434b454c"
  41. static uint8_t uuid_base[16] = {
  42. 0x10, 0xFF, 0x00, 0xFF, 0x53, 0x54, 0x4f, 0x52,
  43. 0x5a, 0x26, 0x42, 0x49, 0x43, 0x4b, 0x45, 0x4c,
  44. };
  45. static uint8_t uuid_base2[16] = {
  46. 0x10, 0xFF, 0x00, 0xFF, 0x53, 0x54, 0x4f, 0x52,
  47. 0x5a, 0x26, 0x42, 0x49, 0x43, 0x4b, 0x45, 0x4c,
  48. };
  49. int8_t volcano_discover_characteristics(void) {
  50. uuid_base[1] = UUID_SRVC_2;
  51. uuid_base2[1] = UUID_SRVC_2;
  52. uuid_base[3] = UUID_WRITE_SRVC;
  53. int8_t r;
  54. uuid_base2[3] = UUID_TARGET_TEMP;
  55. r = ble_discover(uuid_base, uuid_base2);
  56. if (r < 0) {
  57. return r;
  58. }
  59. uuid_base2[3] = UUID_HEATER_ON;
  60. r = ble_discover(uuid_base, uuid_base2);
  61. if (r < 0) {
  62. return r;
  63. }
  64. uuid_base2[3] = UUID_HEATER_OFF;
  65. r = ble_discover(uuid_base, uuid_base2);
  66. if (r < 0) {
  67. return r;
  68. }
  69. uuid_base2[3] = UUID_PUMP_ON;
  70. r = ble_discover(uuid_base, uuid_base2);
  71. if (r < 0) {
  72. return r;
  73. }
  74. uuid_base2[3] = UUID_PUMP_OFF;
  75. r = ble_discover(uuid_base, uuid_base2);
  76. if (r < 0) {
  77. return r;
  78. }
  79. return 0;
  80. }
  81. int16_t volcano_get_current_temp(void) {
  82. uuid_base[1] = UUID_SRVC_2;
  83. uuid_base[3] = UUID_CURRENT_TEMP;
  84. uint8_t buff[4];
  85. int32_t r = ble_read(uuid_base, buff, sizeof(buff));
  86. if (r != sizeof(buff)) {
  87. debug("ble_read unexpected value %ld", r);
  88. return -1;
  89. }
  90. uint32_t *v = (uint32_t *)buff;
  91. return *v;
  92. }
  93. int16_t volcano_get_target_temp(void) {
  94. uuid_base[3] = UUID_TARGET_TEMP;
  95. uint8_t buff[4];
  96. int32_t r = ble_read(uuid_base, buff, sizeof(buff));
  97. if (r != sizeof(buff)) {
  98. debug("ble_read unexpected value %ld", r);
  99. return -1;
  100. }
  101. uint32_t *v = (uint32_t *)buff;
  102. return *v;
  103. }
  104. int8_t volcano_set_target_temp(uint16_t value) {
  105. uuid_base[1] = UUID_SRVC_2;
  106. uuid_base2[1] = UUID_SRVC_2;
  107. uuid_base[3] = UUID_WRITE_SRVC;
  108. uuid_base2[3] = UUID_TARGET_TEMP;
  109. uint8_t buff[4];
  110. uint32_t *v = (uint32_t *)buff;
  111. *v = value;
  112. int8_t r = ble_write(uuid_base, uuid_base2, buff, sizeof(buff));
  113. if (r != 0) {
  114. debug("ble_write unexpected value %d", r);
  115. }
  116. return r;
  117. }
  118. int8_t volcano_set_heater_state(bool value) {
  119. uuid_base[1] = UUID_SRVC_2;
  120. uuid_base2[1] = UUID_SRVC_2;
  121. uuid_base[3] = UUID_WRITE_SRVC;
  122. if (value) {
  123. uuid_base2[3] = UUID_HEATER_ON;
  124. } else {
  125. uuid_base2[3] = UUID_HEATER_OFF;
  126. }
  127. uint8_t d = 0;
  128. int8_t r = ble_write(uuid_base, uuid_base2, &d, sizeof(d));
  129. if (r != 0) {
  130. debug("ble_write unexpected value %d", r);
  131. }
  132. return r;
  133. }
  134. int8_t volcano_set_pump_state(bool value) {
  135. uuid_base[1] = UUID_SRVC_2;
  136. uuid_base2[1] = UUID_SRVC_2;
  137. uuid_base[3] = UUID_WRITE_SRVC;
  138. if (value) {
  139. uuid_base2[3] = UUID_PUMP_ON;
  140. } else {
  141. uuid_base2[3] = UUID_PUMP_OFF;
  142. }
  143. uint8_t d = 0;
  144. int8_t r = ble_write(uuid_base, uuid_base2, &d, sizeof(d));
  145. if (r != 0) {
  146. debug("ble_write unexpected value %d", r);
  147. }
  148. return r;
  149. }
  150. enum unit volcano_get_unit(void) {
  151. uuid_base[1] = UUID_SRVC_1;
  152. uuid_base[3] = UUID_PRJSTAT2;
  153. uint8_t buff[4];
  154. int32_t r = ble_read(uuid_base, buff, sizeof(buff));
  155. if (r != sizeof(buff)) {
  156. debug("ble_read unexpected value %ld", r);
  157. return UNIT_INVALID;
  158. }
  159. uint32_t *v = (uint32_t *)buff;
  160. return (*v & MASK_PRJSTAT2_FAHRENHEIT_ENA) ? UNIT_F : UNIT_C;
  161. }
  162. enum volcano_state volcano_get_state(void) {
  163. uuid_base[1] = UUID_SRVC_1;
  164. uuid_base[3] = UUID_PRJSTAT1;
  165. uint8_t buff[4];
  166. int32_t r = ble_read(uuid_base, buff, sizeof(buff));
  167. if (r != sizeof(buff)) {
  168. debug("ble_read unexpected value %ld", r);
  169. return VOLCANO_STATE_INVALID;
  170. }
  171. uint32_t *v = (uint32_t *)buff;
  172. uint32_t heater = (*v & MASK_PRJSTAT1_HEIZUNG_ENA);
  173. uint32_t pump = (*v & MASK_PRJSTAT1_PUMPE_FET_ENABLE);
  174. return (heater ? VOLCANO_STATE_HEATER : 0) | (pump ? VOLCANO_STATE_PUMP : 0);
  175. }
  176. int8_t volcano_set_unit(enum unit unit) {
  177. uuid_base[1] = UUID_SRVC_1;
  178. uuid_base2[1] = UUID_SRVC_1;
  179. uuid_base[3] = UUID_WRITE_SRVC;
  180. uuid_base2[3] = UUID_PRJSTAT2;
  181. uint32_t v = MASK_PRJSTAT2_FAHRENHEIT_ENA;
  182. if (unit == UNIT_F) {
  183. v |= 0x10000;
  184. }
  185. int8_t r = ble_write(uuid_base, uuid_base2, (uint8_t *)&v, sizeof(v));
  186. if (r != 0) {
  187. debug("ble_write unexpected value %d", r);
  188. }
  189. return r;
  190. }
  191. int8_t volcano_set_vibration(bool value) {
  192. uuid_base[1] = UUID_SRVC_1;
  193. uuid_base2[1] = UUID_SRVC_1;
  194. uuid_base[3] = UUID_WRITE_SRVC;
  195. uuid_base2[3] = UUID_PRJSTAT3;
  196. uint32_t v = MASK_PRJSTAT3_VIBRATION;
  197. if (!value) {
  198. v |= 0x10000;
  199. }
  200. int8_t r = ble_write(uuid_base, uuid_base2, (uint8_t *)&v, sizeof(v));
  201. if (r != 0) {
  202. debug("ble_write unexpected value %d", r);
  203. }
  204. return r;
  205. }
  206. int8_t volcano_get_vibration(void) {
  207. uuid_base[1] = UUID_SRVC_1;
  208. uuid_base[3] = UUID_PRJSTAT3;
  209. uint8_t buff[4];
  210. int32_t r = ble_read(uuid_base, buff, sizeof(buff));
  211. if (r != sizeof(buff)) {
  212. debug("ble_read unexpected value %ld", r);
  213. return -1;
  214. }
  215. uint32_t *v = (uint32_t *)buff;
  216. return (*v & MASK_PRJSTAT3_VIBRATION) ? 0 : 1;
  217. }
  218. int8_t volcano_set_display_cooling(bool value) {
  219. uuid_base[1] = UUID_SRVC_1;
  220. uuid_base2[1] = UUID_SRVC_1;
  221. uuid_base[3] = UUID_WRITE_SRVC;
  222. uuid_base2[3] = UUID_PRJSTAT2;
  223. uint32_t v = MASK_PRJSTAT2_DISPLAY_ON_COOLING;
  224. if (!value) {
  225. v |= 0x10000;
  226. }
  227. int8_t r = ble_write(uuid_base, uuid_base2, (uint8_t *)&v, sizeof(v));
  228. if (r != 0) {
  229. debug("ble_write unexpected value %d", r);
  230. }
  231. return r;
  232. }
  233. int8_t volcano_get_display_cooling(void) {
  234. uuid_base[1] = UUID_SRVC_1;
  235. uuid_base[3] = UUID_PRJSTAT2;
  236. uint8_t buff[4];
  237. int32_t r = ble_read(uuid_base, buff, sizeof(buff));
  238. if (r != sizeof(buff)) {
  239. debug("ble_read unexpected value %ld", r);
  240. return -1;
  241. }
  242. uint32_t *v = (uint32_t *)buff;
  243. return (*v & MASK_PRJSTAT2_DISPLAY_ON_COOLING) ? 0 : 1;
  244. }