xsns_36_mgc3130.ino 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. /*
  2. xsns_36_MGC3130.ino - Support for I2C MGC3130 Electric Field Sensor for Sonoff-Tasmota
  3. Copyright (C) 2018 Christian Baars & Theo Arends
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. //#define USE_MGC3130
  16. #ifdef USE_I2C
  17. #ifdef USE_MGC3130
  18. /*********************************************************************************************\
  19. * MGC3130 - Electric Field Sensor
  20. *
  21. * Adaption for TASMOTA: Christian Baars
  22. * based on various implementations from Pimoroni, jspark311, hoverlabs and scjurgen
  23. *
  24. * I2C Address: 0x42
  25. *
  26. * Wiring: SDA/SCL as usual plus RESET and TRANSFER -> 4 Wires
  27. \*********************************************************************************************/
  28. #define XSNS_36 36
  29. #warning **** MGC3130: It is recommended to disable all unneeded I2C-drivers ****
  30. #define MGC3130_I2C_ADDR 0x42
  31. #define MGC3130_xfer pin[GPIO_MGC3130_XFER]
  32. #define MGC3130_reset pin[GPIO_MGC3130_RESET]
  33. bool MGC3130_type = false;
  34. char MGC3130stype[8];
  35. #define MGC3130_SYSTEM_STATUS 0x15
  36. #define MGC3130_REQUEST_MSG 0x06
  37. #define MGC3130_FW_VERSION 0x83
  38. #define MGC3130_SET_RUNTIME 0xA2
  39. #define MGC3130_SENSOR_DATA 0x91
  40. #define MGC3130_GESTURE_GARBAGE 1
  41. #define MGC3130_FLICK_WEST_EAST 2
  42. #define MGC3130_FLICK_EAST_WEST 3
  43. #define MGC3130_FLICK_SOUTH_NORTH 4
  44. #define MGC3130_FLICK_NORTH_SOUTH 5
  45. #define MGC3130_CIRCLE_CLOCKWISE 6 //not active in airwheel mode
  46. #define MGC3130_CIRCLE_CCLOCKWISE 7 //not active in airwheel mode
  47. #define MGC3130_MIN_ROTVALUE 0
  48. #define MGC3130_MAX_ROTVALUE 1023
  49. #define MGC3130_MIN_ZVALUE 32768 // if we fly under the radar, we do not report anything
  50. #ifdef USE_WEBSERVER
  51. const char HTTP_MGC_3130_SNS[] PROGMEM = "%s"
  52. "{s}" "%s" "{m}%s{e}"
  53. "{s}" "HwRev" "{m}%u.%u{e}"
  54. "{s}" "loaderVer" "{m}%u.%u{e}"
  55. "{s}" "platVer" "{m}%u{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
  56. #endif // USE_WEBSERVER
  57. /*********************************************************************************************\
  58. * MGC3130
  59. *
  60. * Programmer : MGC3130 Datasheet
  61. \*********************************************************************************************/
  62. #pragma pack(1)
  63. union MGC3130_Union{
  64. uint8_t buffer[132];
  65. struct
  66. {
  67. // header
  68. uint8_t msgSize; // in Bytes
  69. uint8_t flag; //not used
  70. uint8_t counter; // cyclic counter of transmitted messages
  71. uint8_t id; // 0x91 for data output
  72. // payload
  73. struct {
  74. uint8_t DSPStatus:1;
  75. uint8_t gestureInfo:1;
  76. uint8_t touchInfo:1;
  77. uint8_t airWheelInfo:1;
  78. uint8_t xyzPosition:1;
  79. uint8_t noisePower:1;
  80. uint8_t reserved:2;
  81. uint8_t electrodeConfiguration:3;
  82. uint8_t CICData:1;
  83. uint8_t SDData:1;
  84. uint16_t reserved2:3;
  85. } outputConfigMask;
  86. uint8_t timestamp;
  87. struct {
  88. uint8_t positionValid:1;
  89. uint8_t airWheelValid:1;
  90. uint8_t rawDataValid:1;
  91. uint8_t noisePowerValid:1;
  92. uint8_t environmentalNoise:1;
  93. uint8_t clipping:1;
  94. uint8_t reserved:1;
  95. uint8_t DSPRunning:1;
  96. } systemInfo;
  97. uint16_t dspInfo;
  98. struct {
  99. uint8_t gestureCode:8; // 0 -> No Gesture
  100. uint8_t reserved:4;
  101. uint8_t gestureType:4; //garbage, flick or circular
  102. uint8_t edgeFlick:1;
  103. uint16_t reserved2:14;
  104. uint8_t gestureInProgress:1; // If "1" Gesture recognition in progress
  105. } gestureInfo;
  106. struct {
  107. uint8_t touchSouth:1;
  108. uint8_t touchWest:1; //:Bit 01
  109. uint8_t touchNorth:1; //:Bit 02
  110. uint8_t touchEast:1; //:Bit 03
  111. uint8_t touchCentre:1; //:Bit 04
  112. uint8_t tapSouth:1; //:Bit 05
  113. uint8_t tapWest:1; //:Bit 06
  114. uint8_t tapNorth:1; //:Bit 07
  115. uint8_t tapEast :1; //:Bit 08
  116. uint8_t tapCentre:1; //:Bit 09
  117. uint8_t doubleTapSouth:1; //:Bit 10
  118. uint8_t doubleTapWest:1; //:Bit 11
  119. uint8_t doubleTapNorth:1; //:Bit 12
  120. uint8_t doubleTapEast:1; //:Bit 13
  121. uint8_t doubleTapCentre:1; //:Bit 14
  122. uint8_t reserved:1; //:Bit 15
  123. uint8_t touchCounter; //period between the time when the hand starts moving to touch until it is detected
  124. uint8_t reserved2;
  125. } touchInfo;
  126. int8_t airWheel;
  127. uint8_t reserved;
  128. uint16_t x;
  129. uint16_t y;
  130. uint16_t z;
  131. float noisePower;
  132. float CICData[4]; // uncalibrated sensor data
  133. float SDData[4]; // signal deviation
  134. } out;
  135. struct {
  136. uint8_t header[3];
  137. // payload
  138. uint8_t valid;
  139. uint8_t hwRev[2];
  140. uint8_t parameterStartAddr;
  141. uint8_t loaderVersion[2];
  142. uint8_t loaderPlatform;
  143. uint8_t fwStartAddr;
  144. char fwVersion[120];
  145. } fw;
  146. struct{
  147. uint8_t id;
  148. uint8_t size;
  149. uint16_t error;
  150. uint32_t reserved;
  151. uint32_t reserved1;
  152. } status;
  153. } MGC_data;
  154. #pragma pack()
  155. char MGC3130_currentGesture[12];
  156. int8_t MGC3130_delta, MGC3130_lastrotation = 0;
  157. int16_t MGC3130_rotValue, MGC3130_lastSentRotValue = 0;
  158. uint16_t MGC3130_lastSentX, MGC3130_lastSentY, MGC3130_lastSentZ = 0;
  159. uint8_t hwRev[2], loaderVersion[2], loaderPlatform = 0;
  160. char MGC3130_firmwareInfo[20];
  161. uint8_t MGC3130_touchTimeout = 0;
  162. uint16_t MGC3130_touchCounter = 1; // measure how long you touch the surface in loop cycles
  163. uint32_t MGC3130_touchTimeStamp = millis();
  164. bool MGC3130_triggeredByTouch = false;
  165. uint8_t MGC3130_mode = 1; // 1-gesture; 2-airwheel; 3-position
  166. // predefined messages
  167. uint8_t MGC3130autoCal[] = {0x10, 0x00, 0x00, 0xA2, 0x80, 0x00 , 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
  168. uint8_t MGC3130disableAirwheel[] = {0x10, 0x00, 0x00, 0xA2, 0x90, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00};
  169. uint8_t MGC3130enableAirwheel[] = {0x10, 0x00, 0x00, 0xA2, 0x90, 0x00 , 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00};
  170. void MGC3130_triggerTele(){
  171. mqtt_data[0] = '\0';
  172. if (MqttShowSensor()) {
  173. MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
  174. #ifdef USE_RULES
  175. RulesTeleperiod(); // Allow rule based HA messages
  176. #endif // USE_RULES
  177. }
  178. }
  179. void MGC3130_handleSensorData(){
  180. if ( MGC_data.out.outputConfigMask.touchInfo && MGC3130_touchTimeout == 0){
  181. if (MGC3130_handleTouch()){
  182. MGC3130_triggeredByTouch = true;
  183. MGC3130_triggerTele();
  184. }
  185. }
  186. if(MGC3130_mode == 1){
  187. if( MGC_data.out.outputConfigMask.gestureInfo && MGC_data.out.gestureInfo.gestureCode > 0){
  188. MGC3130_handleGesture();
  189. MGC3130_triggerTele();
  190. }
  191. }
  192. if(MGC3130_mode == 2){
  193. if(MGC_data.out.outputConfigMask.airWheelInfo && MGC_data.out.systemInfo.airWheelValid){
  194. MGC3130_handleAirWheel();
  195. MGC3130_triggerTele();
  196. }
  197. }
  198. if(MGC3130_mode == 3){
  199. if(MGC_data.out.systemInfo.positionValid && (MGC_data.out.z > MGC3130_MIN_ZVALUE)){
  200. MGC3130_triggerTele();
  201. }
  202. }
  203. }
  204. void MGC3130_sendMessage(uint8_t data[], uint8_t length){
  205. Wire.beginTransmission(MGC3130_I2C_ADDR);
  206. Wire.write(data,length);
  207. Wire.endTransmission();
  208. delay(2);
  209. MGC3130_receiveMessage();
  210. }
  211. void MGC3130_handleGesture(){
  212. //char log[LOGSZ];
  213. char edge[5];
  214. if (MGC_data.out.gestureInfo.edgeFlick){
  215. snprintf_P(edge, sizeof(edge), PSTR("ED_"));
  216. }
  217. else{
  218. snprintf_P(edge, sizeof(edge), PSTR(""));
  219. }
  220. switch(MGC_data.out.gestureInfo.gestureCode){
  221. case MGC3130_GESTURE_GARBAGE:
  222. //snprintf_P(log, sizeof(log), PSTR("NONE"));
  223. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("NONE"));
  224. break;
  225. case MGC3130_FLICK_WEST_EAST:
  226. //snprintf_P(log, sizeof(log), PSTR("%sFL_WE"), edge);
  227. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("%sFL_WE"), edge);
  228. break;
  229. case MGC3130_FLICK_EAST_WEST:
  230. //snprintf_P(log, sizeof(log), PSTR("%sFL_EW"), edge);
  231. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("%sFL_EW"), edge);
  232. break;
  233. case MGC3130_FLICK_SOUTH_NORTH:
  234. //snprintf_P(log, sizeof(log), PSTR("%sFL_SN"), edge);
  235. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("%sFL_SN"), edge);
  236. break;
  237. case MGC3130_FLICK_NORTH_SOUTH:
  238. //snprintf_P(log, sizeof(log), PSTR("%sFL_NS"), edge);
  239. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("%sFL_NS"), edge);
  240. break;
  241. case MGC3130_CIRCLE_CLOCKWISE:
  242. //snprintf_P(log, sizeof(log), PSTR("CW"));
  243. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("CW"));
  244. break;
  245. case MGC3130_CIRCLE_CCLOCKWISE:
  246. //snprintf_P(log, sizeof(log), PSTR("CCW"));
  247. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("CCW"));
  248. break;
  249. }
  250. //AddLog_P(LOG_LEVEL_DEBUG, log);
  251. }
  252. bool MGC3130_handleTouch(){
  253. //char log[LOGSZ];
  254. bool success = false; // if we find a touch of higher order, we are done
  255. if (MGC_data.out.touchInfo.doubleTapCentre && !success){
  256. //snprintf_P(log, sizeof(log), PSTR("DTAP_CENTRE"));
  257. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("DT_C"));
  258. MGC3130_touchTimeout = 5;
  259. success = true;
  260. MGC3130_touchCounter = 1;
  261. }
  262. else if (MGC_data.out.touchInfo.doubleTapEast && !success){
  263. //snprintf_P(log, sizeof(log), PSTR("DTAP_EAST"));
  264. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("DT_E"));
  265. MGC3130_touchTimeout = 5;
  266. success = true;
  267. MGC3130_touchCounter = 1;
  268. }
  269. else if (MGC_data.out.touchInfo.doubleTapNorth && !success){
  270. //snprintf_P(log, sizeof(log), PSTR("DTAP_NORTH"));
  271. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("DT_N"));
  272. MGC3130_touchTimeout = 5;
  273. success = true;
  274. MGC3130_touchCounter = 1;
  275. }
  276. else if (MGC_data.out.touchInfo.doubleTapWest && !success){
  277. //snprintf_P(log, sizeof(log), PSTR("DTAP_WEST"));
  278. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("DT_W"));
  279. MGC3130_touchTimeout = 5;
  280. success = true;
  281. MGC3130_touchCounter = 1;
  282. }
  283. else if (MGC_data.out.touchInfo.doubleTapSouth && !success){
  284. //snprintf_P(log, sizeof(log), PSTR("DTAP_SOUTH"));
  285. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("DT_S"));
  286. MGC3130_touchTimeout = 5;
  287. success = true;
  288. MGC3130_touchCounter = 1;
  289. }
  290. if (MGC_data.out.touchInfo.tapCentre && !success){
  291. //snprintf_P(log, sizeof(log), PSTR("TAP_CENTRE"));
  292. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TP_C"));
  293. MGC3130_touchTimeout = 2;
  294. success = true;
  295. MGC3130_touchCounter = 1;
  296. }
  297. else if (MGC_data.out.touchInfo.tapEast && !success){
  298. //snprintf_P(log, sizeof(log), PSTR("TAP_EAST"));
  299. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TP_E"));
  300. MGC3130_touchTimeout = 2;
  301. success = true;
  302. MGC3130_touchCounter = 1;
  303. }
  304. else if (MGC_data.out.touchInfo.tapNorth && !success){
  305. //snprintf_P(log, sizeof(log), PSTR("TAP_NORTH"));
  306. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TP_N"));
  307. MGC3130_touchTimeout = 2;
  308. success = true;
  309. MGC3130_touchCounter = 1;
  310. }
  311. else if (MGC_data.out.touchInfo.tapWest && !success){
  312. //snprintf_P(log, sizeof(log), PSTR("TAP_WEST"));
  313. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TP_W"));
  314. MGC3130_touchTimeout = 2;
  315. success = true;
  316. MGC3130_touchCounter = 1;
  317. }
  318. else if (MGC_data.out.touchInfo.tapSouth && !success){
  319. //snprintf_P(log, sizeof(log), PSTR("TAP_SOUTH"));
  320. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TP_S"));
  321. MGC3130_touchTimeout = 2;
  322. success = true;
  323. MGC3130_touchCounter = 1;
  324. }
  325. else if (MGC_data.out.touchInfo.touchCentre && !success){
  326. //snprintf_P(log, sizeof(log), PSTR("TOUCH_CENTRE"));
  327. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TH_C"));
  328. success = true;
  329. MGC3130_touchCounter++; // This will reset to 0 after touching for approx. 1h and 50 minutes ;)
  330. }
  331. else if (MGC_data.out.touchInfo.touchEast && !success){
  332. //snprintf_P(log, sizeof(log), PSTR("TOUCH_EAST"));
  333. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TH_E"));
  334. success = true;
  335. MGC3130_touchCounter++;
  336. }
  337. else if (MGC_data.out.touchInfo.touchNorth && !success){
  338. //snprintf_P(log, sizeof(log), PSTR("TOUCH_NORTH"));
  339. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TH_N"));
  340. success = true;
  341. MGC3130_touchCounter++;
  342. }
  343. else if (MGC_data.out.touchInfo.touchWest && !success){
  344. //snprintf_P(log, sizeof(log), PSTR("TOUCH_WEST"));
  345. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TH_W"));
  346. success = true;
  347. MGC3130_touchCounter++;
  348. }
  349. else if (MGC_data.out.touchInfo.touchSouth && !success){
  350. //snprintf_P(log, sizeof(log), PSTR("TOUCH_SOUTH"));
  351. snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TH_S"));
  352. success = true;
  353. MGC3130_touchCounter++;
  354. }
  355. //AddLog_P(LOG_LEVEL_DEBUG, log);
  356. return success;
  357. }
  358. void MGC3130_handleAirWheel(){
  359. MGC3130_delta = MGC_data.out.airWheel - MGC3130_lastrotation;
  360. MGC3130_lastrotation = MGC_data.out.airWheel;
  361. MGC3130_rotValue = MGC3130_rotValue + MGC3130_delta;
  362. if(MGC3130_rotValue < MGC3130_MIN_ROTVALUE){
  363. MGC3130_rotValue = MGC3130_MIN_ROTVALUE;
  364. }
  365. if(MGC3130_rotValue > MGC3130_MAX_ROTVALUE){
  366. MGC3130_rotValue = MGC3130_MAX_ROTVALUE;
  367. }
  368. }
  369. void MGC3130_handleSystemStatus(){
  370. //Serial.println("Got System status");
  371. }
  372. bool MGC3130_receiveMessage(){
  373. if(MGC3130_readData()){
  374. switch(MGC_data.out.id){
  375. case MGC3130_SENSOR_DATA:
  376. MGC3130_handleSensorData();
  377. break;
  378. case MGC3130_SYSTEM_STATUS:
  379. MGC3130_handleSystemStatus();
  380. break;
  381. case MGC3130_FW_VERSION:
  382. hwRev[0] = MGC_data.fw.hwRev[1];
  383. hwRev[1] = MGC_data.fw.hwRev[0];
  384. loaderVersion[0] = MGC_data.fw.loaderVersion[0];
  385. loaderVersion[1] = MGC_data.fw.loaderVersion[1];
  386. loaderPlatform = MGC_data.fw.loaderPlatform;
  387. snprintf_P(MGC3130_firmwareInfo, sizeof(MGC3130_firmwareInfo), PSTR("FW: %s"), MGC_data.fw.fwVersion);
  388. MGC3130_firmwareInfo[20] = '\0';
  389. // Serial.print(MGC3130_firmwareInfo);
  390. break;
  391. }
  392. return true;
  393. }
  394. return false;
  395. }
  396. bool MGC3130_readData()
  397. {
  398. bool success = false;
  399. if (!digitalRead(MGC3130_xfer)){
  400. pinMode(MGC3130_xfer, OUTPUT);
  401. digitalWrite(MGC3130_xfer, LOW);
  402. Wire.requestFrom(MGC3130_I2C_ADDR, (uint16_t)32); // request usual data output
  403. MGC_data.buffer[0] = 4; // read at least header, but update after first read anyway
  404. unsigned char i = 0;
  405. while(Wire.available() && (i < MGC_data.buffer[0])){
  406. MGC_data.buffer[i] = Wire.read();
  407. i++;
  408. }
  409. digitalWrite(MGC3130_xfer, HIGH);
  410. pinMode(MGC3130_xfer, INPUT);
  411. success = true;
  412. }
  413. return success;
  414. }
  415. void MGC3130_nextMode(){
  416. if (MGC3130_mode < 3){
  417. MGC3130_mode++;
  418. }
  419. else{
  420. MGC3130_mode = 1;
  421. }
  422. switch(MGC3130_mode){ // there is more to be done in the future
  423. case 1:
  424. MGC3130_sendMessage(MGC3130disableAirwheel,16);
  425. break;
  426. case 2:
  427. MGC3130_sendMessage(MGC3130enableAirwheel,16);
  428. break;
  429. case 3:
  430. MGC3130_sendMessage(MGC3130disableAirwheel,16);
  431. break;
  432. }
  433. }
  434. void MGC3130_loop()
  435. {
  436. if(MGC3130_touchTimeout > 0){
  437. MGC3130_touchTimeout--;
  438. }
  439. MGC3130_receiveMessage();
  440. }
  441. bool MGC3130_detect(void)
  442. {
  443. if (MGC3130_type){
  444. return true;
  445. }
  446. pinMode(MGC3130_xfer, INPUT_PULLUP);
  447. pinMode(MGC3130_reset, OUTPUT);
  448. digitalWrite(MGC3130_reset, LOW);
  449. delay(10);
  450. digitalWrite(MGC3130_reset, HIGH);
  451. delay(50);
  452. boolean success = false;
  453. success = MGC3130_receiveMessage(); // This should read the firmware info
  454. if (success) {
  455. strcpy_P(MGC3130stype, PSTR("MGC3130"));
  456. snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, MGC3130stype, MGC3130_I2C_ADDR);
  457. AddLog(LOG_LEVEL_DEBUG);
  458. MGC3130_currentGesture[0] = '\0';
  459. MGC3130_type = true;
  460. } else {
  461. snprintf_P(log_data, sizeof(log_data), PSTR("MGC3130 did not respond at address 0x%x"), MGC3130_I2C_ADDR);
  462. AddLog(LOG_LEVEL_DEBUG);
  463. }
  464. return success;
  465. }
  466. /*********************************************************************************************\
  467. * Presentation
  468. \*********************************************************************************************/
  469. void MGC3130_show(boolean json)
  470. {
  471. if (!MGC3130_type) { return; }
  472. char status_chr[2];
  473. if (MGC_data.out.systemInfo.DSPRunning) {
  474. sprintf (status_chr, "1");
  475. }
  476. else{
  477. sprintf (status_chr, "0");
  478. }
  479. if (json) {
  480. if (MGC3130_mode == 3 && !MGC3130_triggeredByTouch) {
  481. if (MGC_data.out.systemInfo.positionValid && !(MGC_data.out.x == MGC3130_lastSentX && MGC_data.out.y == MGC3130_lastSentY && MGC_data.out.z == MGC3130_lastSentZ)) {
  482. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"X\":%u,\"Y\":%u,\"Z\":%u}"),
  483. mqtt_data, MGC3130stype, MGC_data.out.x/64, MGC_data.out.y/64, (MGC_data.out.z-(uint16_t)MGC3130_MIN_ZVALUE)/64);
  484. MGC3130_lastSentX = MGC_data.out.x;
  485. MGC3130_lastSentY = MGC_data.out.y;
  486. MGC3130_lastSentZ = MGC_data.out.z;
  487. }
  488. }
  489. MGC3130_triggeredByTouch = false;
  490. if (MGC3130_mode == 2) {
  491. if (MGC_data.out.systemInfo.airWheelValid && (MGC3130_rotValue != MGC3130_lastSentRotValue)) {
  492. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"AW\":%i}"), mqtt_data, MGC3130stype, MGC3130_rotValue);
  493. MGC3130_lastSentRotValue = MGC3130_rotValue;
  494. }
  495. }
  496. if (MGC3130_currentGesture[0] != '\0') {
  497. if (millis() - MGC3130_touchTimeStamp > 220 ) {
  498. MGC3130_touchCounter = 1;
  499. }
  500. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"%s\":%u}"), mqtt_data, MGC3130stype, MGC3130_currentGesture, MGC3130_touchCounter);
  501. MGC3130_currentGesture[0] = '\0';
  502. MGC3130_touchTimeStamp = millis();
  503. }
  504. #ifdef USE_WEBSERVER
  505. } else {
  506. snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MGC_3130_SNS, mqtt_data, MGC3130stype, status_chr, hwRev[0], hwRev[1], loaderVersion[0], loaderVersion[1], loaderPlatform );
  507. #endif // USE_WEBSERVER
  508. }
  509. }
  510. /*********************************************************************************************\
  511. * Command Sensor36
  512. *
  513. * Command | Payload | Description
  514. * ---------|---------|--------------------------
  515. * Sensor36 | | ...
  516. * Sensor36 | 0 | Next Mode - cycle through the modes
  517. * Sensor36 | 1 | Gesture Mode
  518. * Sensor36 | 2 | Airwheel Mode
  519. * Sensor36 | 3 | Position Mode with x,y,z - z must be higher than half of the max. sensing height
  520. \*********************************************************************************************/
  521. bool MGC3130CommandSensor()
  522. {
  523. boolean serviced = true;
  524. switch (XdrvMailbox.payload) {
  525. case 0: // cycle through the modes
  526. MGC3130_nextMode();
  527. break;
  528. case 1: // gesture & touch
  529. MGC3130_mode = 1;
  530. MGC3130_sendMessage(MGC3130disableAirwheel,16);
  531. break;
  532. case 2: // airwheel & touch
  533. MGC3130_mode = 2;
  534. MGC3130_sendMessage(MGC3130enableAirwheel,16);
  535. break;
  536. case 3: // position & touch
  537. MGC3130_mode = 3;
  538. MGC3130_sendMessage(MGC3130disableAirwheel,16);
  539. break;
  540. }
  541. return serviced;
  542. }
  543. /*********************************************************************************************\
  544. * Interface
  545. \*********************************************************************************************/
  546. boolean Xsns36(byte function)
  547. {
  548. boolean result = false;
  549. if (i2c_flg) {
  550. if ((FUNC_INIT == function) && (pin[GPIO_MGC3130_XFER] < 99) && (pin[GPIO_MGC3130_RESET] < 99)) {
  551. MGC3130_detect();
  552. }
  553. else if (MGC3130_type) {
  554. switch (function) {
  555. case FUNC_EVERY_50_MSECOND:
  556. MGC3130_loop();
  557. break;
  558. case FUNC_COMMAND:
  559. if (XSNS_36 == XdrvMailbox.index) {
  560. result = MGC3130CommandSensor();
  561. }
  562. break;
  563. case FUNC_JSON_APPEND:
  564. MGC3130_show(1);
  565. break;
  566. #ifdef USE_WEBSERVER
  567. case FUNC_WEB_APPEND:
  568. MGC3130_show(0);
  569. break;
  570. #endif // USE_WEBSERVER
  571. }
  572. }
  573. }
  574. return result;
  575. }
  576. #endif // USE_MGC3130
  577. #endif // USE_I2C