+static int parse_culfw(uint8_t *buf, int buf_len, void *data)
+{
+       struct recv_data *rdata = data;
+       int pos = 0;
+       int rpos = 0; // read index
+
+       memset(rdata->message, 0, sizeof(rdata->message));
+       rdata->message_type = 0;
+
+       if (buf_len <= 3)
+               return 0;
+
+       switch(buf[0]) {
+               case 'A':
+                       if (buf[1] == 's')
+                               return 0;
+
+                       if ((buf[1] == 'p') || (buf[1] == 't')) // tsculfw: ping or set timestamp command echoed?
+                               return 0;
+
+                       if (buf[1] == '?') {// tsculfw: unknown command
+                               fprintf(stderr, "unknown ASKSIN command sent\n");
+                               return 0;
+                       }
+
+                       if (buf[1] == 'F') { // tsculfw: timestamp message?
+                               rdata->is_TSCUL = 1;
+                               if (buf_len <= (3+14)) // tsculfw: reasonable len?
+                                       return 0;
+                               if (!validate_nibble(buf[3]) || !validate_nibble(buf[4])) // tsculfw: hex?
+                                       return 0;
+
+                               rdata->credits = ascii_to_nibble(buf[3]); // tsculfw: coarse credits info, 0 = full credits (1800 x10ms) available
+
+                               //AFF1B000053A1010F0520CB1122334BD57110
+                               switch(ascii_to_nibble(buf[4]) & 0x7) { // tsculfw: message type?
+                                       case 0: // tsculfw: send fail message repeat fail or AES Auth error
+                                               fprintf(stderr, "send didn't complete, repeat fail or AES Auth error\n");
+                                               return 0;
+                                       case 1: // tsculfw: received message
+                                               rpos += 7; // tsculfw: ignore timestamp data for now
+                                               break;
+                                       case 2: // tsculfw: ping answer
+                                               return 0;
+                                       case 3: // tsculfw: send success
+                                               rdata->message_type = MESSAGE_TYPE_B;
+                                               return 0;
+                                       case 4: // tsculfw: send fail channel busy message
+                                               fprintf(stderr, "CCA didn't complete, too much traffic\n");
+                                               return 0;
+                                       case 5: // tsculfw: send fail credits message
+                                               fprintf(stderr, "send didn't complete, not enough credits left\n");
+                                               return 0;
+                                       case 6: // tsculfw: send timestamp fail message no buffer or send message length error
+                                               fprintf(stderr, "send didn't complete, not enough credits left -> wait 30 minutes with TSCUL powered and not reset\n");
+                                               return 0;
+                                       case 7: // tsculfw: send fail due to cc1101 TX-FIFO underflow error message
+                                               fprintf(stderr, "send didn't complete, cc1101 TX-FIFO underflow\n");
+                                               return 0;
+                                       default:
+                                               break;
+                               }
+                       }
+
+                       while(validate_nibble(buf[(rpos * 2) + 1]) &&
+                             validate_nibble(buf[(rpos * 2) + 2]) &&
+                             (rpos + 1 < buf_len)) {
+                               rdata->message[pos] = ascii_to_nibble(buf[(rpos * 2) + 1]) << 4;
+                               rdata->message[pos] |= ascii_to_nibble(buf[(rpos * 2) + 2]);
+                               pos++;
+                               rpos++;
+                       }
+
+                       if (hmid && (SRC(rdata->message) != hmid))
+                               return 0;
+
+                       rdata->message_type = MESSAGE_TYPE_E;
+                       break;
+               case 'V':
+                       {
+                               uint8_t v;
+                               char *s;
+                               char *e;
+
+                               if (!strncmp((char*)buf, "VTS", 3)) { // tsculfw: "VTS x.xx NNNNNN"
+                                       rdata->is_TSCUL = 1;
+                                       rdata->version = 0xffff;
+                                       break;
+                               }
+
+                               s = ((char*)buf) + 2;
+                               e = strchr(s, '.');
+                               if (!e) {
+                                       fprintf(stderr, "Unknown response from CUL: %s", buf);
+                                       return 0;
+                               }
+                               *e = '\0';
+                               v = atoi(s);
+                               rdata->version = v << 8;
+
+                               s = e + 1;
+                               e = strchr(s, ' ');
+                               if (!e) {
+                                       fprintf(stderr, "Unknown response from CUL: %s", buf);
+                                       return 0;
+                               }
+                               *e = '\0';
+                               v = atoi(s);
+                               rdata->version |= v;
+
+                               s = e + 1;
+                               e = strchr(s, ' ');
+                               if (!e) {
+                                       break;
+                               }
+                               *e = '\0';
+                               if (!strcmp(s, "a-culfw")) {
+                                       rdata->version = 0xffff;
+                               }
+                       }
+                       break;
+               case 'E':
+                       {
+                               if (!strncmp((char*)buf, "ERR:CCA", 7)) {
+                                       fprintf(stderr, "CCA didn't complete, too much traffic\n");
+                               }
+                               break;
+                       }
+               default:
+                       fprintf(stderr, "Unknown response from CUL: %s", buf);
+                       return 0;
+                       break;
+       }
+
+       return 1;
+}
+
+static int parse_hmuartlgw(enum hmuartlgw_dst dst, uint8_t *buf, int buf_len, void *data)
+{
+       struct recv_data *rdata = data;
+
+       if (dst == HMUARTLGW_OS) {
+               switch (rdata->uartlgw_state) {
+                       case HMUARTLGW_STATE_GET_FIRMWARE:
+                               if (buf[0] == HMUARTLGW_OS_ACK) {
+                                       rdata->uartlgw_version[0] = buf[5];
+                                       rdata->uartlgw_version[1] = buf[6];
+                                       rdata->uartlgw_version[2] = buf[7];
+                                       rdata->uartlgw_state = HMUARTLGW_STATE_DONE;
+                               }
+                               break;
+                       case HMUARTLGW_STATE_GET_CREDITS:
+                               if (buf[0] == HMUARTLGW_OS_ACK) {
+                                       rdata->credits = buf[2] / 2;
+                                       rdata->uartlgw_state = HMUARTLGW_STATE_DONE;
+                               }
+                               break;
+                       default:
+                               break;
+               }
+               return 0;
+       }
+
+       switch(buf[0]) {
+               case HMUARTLGW_APP_ACK:
+                       if (rdata->uartlgw_state == HMUARTLGW_STATE_GET_HMID) {
+                               my_hmid = (buf[4] << 16) | (buf[5] << 8) | buf[6];
+                       }
+
+                       rdata->status = buf[1];
+                       rdata->message_type = MESSAGE_TYPE_R;
+                       rdata->uartlgw_state = HMUARTLGW_STATE_ACK_APP;
+#if 0
+                       hexdump(buf, buf_len, "ACK Status: ");
+#endif
+
+                       break;
+               case HMUARTLGW_APP_RECV:
+                       if ((!hmid) ||
+                           ((buf[7] == ((hmid >> 16) & 0xff)) &&
+                           (buf[8] == ((hmid >> 8) & 0xff)) &&
+                           (buf[9] == (hmid & 0xff)))) {
+                               memset(rdata->message, 0, sizeof(rdata->message));
+                               memcpy(rdata->message + 1, buf + 4, buf_len - 4);
+                               rdata->message[LEN] = buf_len - 4;
+                               rdata->message_type = MESSAGE_TYPE_E;
+                       }
+                       break;
+               default:
+                       break;
+       }
+
+       return 1;
+}
+
+int send_wait_hmuartlgw(struct hm_dev *dev, struct recv_data *rdata, uint8_t *data, int data_len,
+                        enum hmuartlgw_dst dst, enum hmuartlgw_state srcstate,
+                       enum hmuartlgw_state dststate)
+{
+       int cnt = 5;
+
+       do {
+               rdata->uartlgw_state = srcstate;
+               hmuartlgw_send(dev->hmuartlgw, data, data_len, dst);
+               do { hmuartlgw_poll(dev->hmuartlgw, 500); } while (rdata->uartlgw_state != dststate);
+               if (rdata->status != HMUARTLGW_ACK_EINPROGRESS)
+                       break;
+               usleep(200*1000);
+       } while (cnt--);
+       if (rdata->status == HMUARTLGW_ACK_EINPROGRESS) {
+               fprintf(stderr, "IO thinks it is busy, you might have to reset it!\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+int send_hm_message(struct hm_dev *dev, struct recv_data *rdata, uint8_t *msg)