static void echill_send_wakeup_ind(void){
	// update state
	tx_state     = TX_W4_WAKEUP;
	ehcill_state = EHCILL_STATE_W4_ACK;
	ehcill_command_to_send = EHCILL_WAKE_UP_IND;
	hal_uart_dma_send_block(&ehcill_command_to_send, 1);
}
static int ehcill_send_packet(uint8_t packet_type, uint8_t *packet, int size){
    
    // check for ongoing write
    switch (tx_state){
        case TX_W4_WAKEUP:
        case TX_W4_PACKET_SENT:
            // we should not arrive here, log state
            log_error("h4_send_packet with tx_state = %u, ehcill_state %u, packet type %u, data %02x %02x %02x", tx_state, ehcill_state, packet_type, packet[0], packet[1], packet[2]);
            return -1;
        case TX_IDLE:
        case TX_DONE:
        case TX_W2_EHCILL_SEND:
        case TX_W4_EHCILL_SENT:
            break;
    }
    
    // store packet type before actual data and increase size
    size++;
    packet--;
    *packet = packet_type;

    // store request
    tx_data = packet;
    tx_len  = size;
    
    // if awake, just start sending 
    if (!ehcill_sleep_mode_active()){
        tx_state = TX_W4_PACKET_SENT;
        hal_uart_dma_send_block(tx_data, tx_len);
        return 0;
    }

    switch (tx_state){
        case TX_W2_EHCILL_SEND:
        case TX_W4_EHCILL_SENT:
            // wake up / sleep ack in progress, nothing to do now
            return 0;
        case TX_IDLE:
        case TX_DONE:
        default:
            // all clear, prepare for wakeup
            break;
    }
    
    // UART needed again
    hal_uart_dma_set_sleep(0);
    ehcill_reactivate_rx();

    // start wakeup
    echill_send_wakeup_ind();

    return 0;
}
static void h4_block_sent(void){
    switch (tx_state){
        case TX_W4_HEADER_SENT:
            tx_state = TX_W4_PACKET_SENT;
            // h4 packet type + actual packet
            hal_uart_dma_send_block(tx_data, tx_len);
            break;
        case TX_W4_PACKET_SENT:
            tx_state = TX_DONE;
            // trigger run loop
            embedded_trigger();
            break;
        default:
            break;
    }
}
// potentially called from ISR context
static void h4_block_sent(void){
    int command;
    switch (tx_state){
        case TX_W4_PACKET_SENT:
            // packet fully sent, reset state
            tx_len = 0;
            // now, send pending ehcill command if neccessary
            switch (ehcill_command_to_send){
                case EHCILL_GO_TO_SLEEP_ACK:
                    ehcill_sleep_ack_timer_setup();
		            tx_send_packet_sent = 1;
                    break;
                case EHCILL_WAKE_UP_IND:
                    tx_state = TX_W4_EHCILL_SENT;
                    // gpio_clear(GPIOB, GPIO_DEBUG_1);
                    hal_uart_dma_send_block(&ehcill_command_to_send, 1);
		            tx_send_packet_sent = 1;
                    break;
                default:
                    // trigger run loop
                    tx_state = TX_DONE;
		            tx_send_packet_sent = 1;
                    embedded_trigger();
                    break;
            }
            break;
        case TX_W4_EHCILL_SENT:
            tx_state = TX_DONE;
            command = ehcill_command_to_send;
            ehcill_command_to_send = 0;
            if (command == EHCILL_GO_TO_SLEEP_ACK) {
                // UART not needed after EHCILL_GO_TO_SLEEP_ACK was sent
                hal_uart_dma_set_sleep(1);
            }
            if (h4_outgoing_packet_ready()){
                // already packet ready? then start wakeup
                hal_uart_dma_set_sleep(0);
                ehcill_reactivate_rx();
                echill_send_wakeup_ind();
            }
            // trigger run loop
            embedded_trigger();
            break;
        default:
            break;
    }
}
static int h4_send_packet(uint8_t packet_type, uint8_t *packet, int size){
    
    // write in progress
    if (tx_state != TX_IDLE) {
        log_error("h4_send_packet with tx_state = %u, type %u, data %02x %02x %02x", tx_state, packet_type, packet[0], packet[1], packet[2]);
        return -1;
    }
    
    tx_packet_type = packet_type;
    tx_data = packet;
    tx_len  = size;
    
    tx_state = TX_W4_HEADER_SENT;
	hal_uart_dma_send_block(&tx_packet_type, 1);
    
    return 0;
}
static int h4_send_packet(uint8_t packet_type, uint8_t *packet, int size){
    
    // write in progress
    if (tx_state != TX_IDLE) {
        log_error("h4_send_packet with tx_state = %u, type %u, data %02x %02x %02x", tx_state, packet_type, packet[0], packet[1], packet[2]);
        return -1;
    }
    
    // store packet type before actual data and increase size
    size++;
    packet--;
    *packet = packet_type;

    tx_state = TX_W4_PACKET_SENT;
	hal_uart_dma_send_block(packet, size);
    
    return 0;
}
static void ehcill_schedule_ecill_command(uint8_t command){
    ehcill_command_to_send = command;
    switch (tx_state){
        case TX_IDLE:
        case TX_DONE:
            if (ehcill_command_to_send == EHCILL_WAKE_UP_ACK){
                // send right away
                tx_state = TX_W4_EHCILL_SENT;
                hal_uart_dma_send_block(&ehcill_command_to_send, 1);        
                break;
            }
            // change state so BTstack cannot send and setup timer
            tx_state = TX_W2_EHCILL_SEND;
            ehcill_sleep_ack_timer_setup();
            break;
        default:
            break;
    }
}
static void ehcill_handle(uint8_t action){
    // log_info("ehcill_handle: %x, state %u, defer_rx %u", action, ehcill_state, ehcill_defer_rx_size);
    switch(ehcill_state){
        case EHCILL_STATE_AWAKE:
            switch(action){
                case EHCILL_GO_TO_SLEEP_IND:
                    
                    // 1. set RTS high - already done by BT RX ISR
                    // 2. enable CTS   - CTS always enabled
                    
                    ehcill_state = EHCILL_STATE_SLEEP;
#ifdef LOG_EHCILL
                    log_info("EHCILL: GO_TO_SLEEP_IND RX");
#endif
                    // gpio_set(GPIOB, GPIO_DEBUG_1);

                    ehcill_schedule_ecill_command(EHCILL_GO_TO_SLEEP_ACK);
                    break;
                    
                default:
                    break;
            }
            break;
            
        case EHCILL_STATE_SLEEP:
            switch(action){
                case EHCILL_CTS_SIGNAL:
                    // UART needed again
                    hal_uart_dma_set_sleep(0);
                    // and continue to receive
                    ehcill_reactivate_rx();
                    break;
                    
                case EHCILL_WAKE_UP_IND:
                    ehcill_state = EHCILL_STATE_AWAKE;
#ifdef LOG_EHCILL
                    log_info("EHCILL: WAKE_UP_IND RX");
#endif
                    ehcill_schedule_ecill_command(EHCILL_WAKE_UP_ACK);
                    break;
                    
                default:
                    break;
            }
            break;
            
        case EHCILL_STATE_W4_ACK:
            switch(action){
                case EHCILL_WAKE_UP_IND:
                case EHCILL_WAKE_UP_ACK:
#ifdef LOG_EHCILL
                    log_info("EHCILL: WAKE_UP_IND or ACK");
#endif
                    tx_state = TX_W4_PACKET_SENT;
                    hal_uart_dma_send_block(tx_data, tx_len);
                    ehcill_state = EHCILL_STATE_AWAKE;
                    
                    break;
                    
                default:
                    break;
            }
            break;
    }
}
static void ehcill_sleep_ack_timer_handler(timer_source_t * timer){
    tx_state = TX_W4_EHCILL_SENT;
    hal_uart_dma_send_block(&ehcill_command_to_send, 1);    
}