Lite kort hur detta bibliotek fungerar.
Steg 1:
Först anropas denna funktion
Koden som körs är denna. Vad denna gör är att den ska läsa ett meddelande för att kunna ta ett beslut.
Kod: Markera allt
bool modbus_polling(){
	if(nmbs_server){
		nmbs_error err = nmbs_server_poll(nmbs_server);
		if (err != NMBS_ERROR_NONE) {
			return false;
		}
		return true;
	}
	return false;
}
 
Steg 2:
Denna kod är själva polling-funktionen. Den läser och sedan skriver den
Kod: Markera allt
nmbs_error nmbs_server_poll(nmbs_t* nmbs) {
    msg_state_reset(nmbs);
    bool first_byte_received = false;
    nmbs_error err = recv_req_header(nmbs, &first_byte_received);
    if (err != NMBS_ERROR_NONE) {
        if (!first_byte_received && err == NMBS_ERROR_TIMEOUT)
            return NMBS_ERROR_NONE;
        return err;
    }
#ifdef NMBS_DEBUG
    printf("%d ", nmbs->address_rtu);
    printf("NMBS req <- ");
    if (nmbs->platform.transport == NMBS_TRANSPORT_RTU) {
        if (nmbs->msg.broadcast)
            printf("broadcast\t");
        else
            printf("address_rtu %d\t", nmbs->msg.unit_id);
    }
#endif
    err = handle_req_fc(nmbs);
    if (err != NMBS_ERROR_NONE) {
        if (err != NMBS_ERROR_TIMEOUT)
            flush(nmbs);
        return err;
    }
    return NMBS_ERROR_NONE;
}
 
Steg 3:
Låt oss börja först med läsningen. Den ska alltså läsa en header. Troligtvis är det en "data-frame".  Vi går vidare in till funktionen 
recv_msg_header.
Kod: Markera allt
static nmbs_error recv_req_header(nmbs_t* nmbs, bool* first_byte_received) {
    nmbs_error err = recv_msg_header(nmbs, first_byte_received);
    if (err != NMBS_ERROR_NONE)
        return err;
    if (nmbs->platform.transport == NMBS_TRANSPORT_RTU) {
        // Check if request is for us
        if (nmbs->msg.unit_id == NMBS_BROADCAST_ADDRESS)
            nmbs->msg.broadcast = true;
        else if (nmbs->msg.unit_id != nmbs->address_rtu)
            nmbs->msg.ignored = true;
        else
            nmbs->msg.ignored = false;
    }
    return NMBS_ERROR_NONE;
}
 
Steg 4:
Här är koden för att läsa. Det denna kod gör är att den läser ID och FUNKTION i dataramen. Alltså två byte. Den är något försiktig dock när den läser då den läser via 
get_1 som betyder "get one byte". För varje "byte" den har läst, så "hoppar" den ett steg.  Funktionen 
 recv(nmbs, 1); anropar alltså den där UART funktionen som du har ovan med storleken 
size = 1.
Kod: Markera allt
static nmbs_error recv_msg_header(nmbs_t* nmbs, bool* first_byte_received) {
    // We wait for the read timeout here, just for the first message byte
    int32_t old_byte_timeout = nmbs->byte_timeout_ms;
    nmbs->byte_timeout_ms = nmbs->read_timeout_ms;
    msg_state_reset(nmbs);
    *first_byte_received = false;
    if (nmbs->platform.transport == NMBS_TRANSPORT_RTU) {
        nmbs_error err = recv(nmbs, 1);
        nmbs->byte_timeout_ms = old_byte_timeout;
        if (err != NMBS_ERROR_NONE)
            return err;
        *first_byte_received = true;
        nmbs->msg.unit_id = get_1(nmbs);
        err = recv(nmbs, 1);
        if (err != NMBS_ERROR_NONE)
            return err;
        nmbs->msg.fc = get_1(nmbs);
    }
    else if (nmbs->platform.transport == NMBS_TRANSPORT_TCP) {
       Denna kod är bortklippt för den visar bara TCP-IP.
    }
    return NMBS_ERROR_NONE;
}
 
Steg 5:
Efter vi har fått våra ID byte och FUNKTION byte. En sak förstår jag inte varför 
nmbs->msg.unit_id har alltid en fixerad broadcast adress på 0 så fort vi läser ett meddelande. 
Då är vill tillbaka till denna kod igen
Kod: Markera allt
static nmbs_error recv_req_header(nmbs_t* nmbs, bool* first_byte_received) {
    nmbs_error err = recv_msg_header(nmbs, first_byte_received);
    if (err != NMBS_ERROR_NONE)
        return err;
    if (nmbs->platform.transport == NMBS_TRANSPORT_RTU) {
        // Check if request is for us
        if (nmbs->msg.unit_id == NMBS_BROADCAST_ADDRESS)
            nmbs->msg.broadcast = true;
        else if (nmbs->msg.unit_id != nmbs->address_rtu)
            nmbs->msg.ignored = true;
        else
            nmbs->msg.ignored = false;
    }
    return NMBS_ERROR_NONE;
}
 
Steg 6:
Vi är tillbaka till denna kod igen och nu ska vi läsa våran funktionskod. Detta gör via via 
handle_req_fc(nmbs);
Kod: Markera allt
nmbs_error nmbs_server_poll(nmbs_t* nmbs) {
    msg_state_reset(nmbs);
    bool first_byte_received = false;
    nmbs_error err = recv_req_header(nmbs, &first_byte_received);
    if (err != NMBS_ERROR_NONE) {
        if (!first_byte_received && err == NMBS_ERROR_TIMEOUT)
            return NMBS_ERROR_NONE;
        return err;
    }
#ifdef NMBS_DEBUG
    printf("%d ", nmbs->address_rtu);
    printf("NMBS req <- ");
    if (nmbs->platform.transport == NMBS_TRANSPORT_RTU) {
        if (nmbs->msg.broadcast)
            printf("broadcast\t");
        else
            printf("address_rtu %d\t", nmbs->msg.unit_id);
    }
#endif
    err = handle_req_fc(nmbs);
    if (err != NMBS_ERROR_NONE) {
        if (err != NMBS_ERROR_TIMEOUT)
            flush(nmbs);
        return err;
    }
    return NMBS_ERROR_NONE;
}
 
Steg 7:
Nu ska vi avgöra vad vi ska ta för beslut. Om vi har FUNKTION = 4 så betyder det att vi ska skicka ett register. Då anropar vi 
err = handle_read_input_registers(nmbs);
Kod: Markera allt
static nmbs_error handle_req_fc(nmbs_t* nmbs) {
    NMBS_DEBUG_PRINT("fc %d\t", nmbs->msg.fc);
    nmbs_error err = NMBS_ERROR_NONE;
    switch (nmbs->msg.fc) {
#ifndef NMBS_SERVER_READ_COILS_DISABLED
        case 1:
            err = handle_read_coils(nmbs);
            break;
#endif
#ifndef NMBS_SERVER_READ_DISCRETE_INPUTS_DISABLED
        case 2:
            err = handle_read_discrete_inputs(nmbs);
            break;
#endif
#ifndef NMBS_SERVER_READ_HOLDING_REGISTERS_DISABLED
        case 3:
            err = handle_read_holding_registers(nmbs);
            break;
#endif
#ifndef NMBS_SERVER_READ_INPUT_REGISTERS_DISABLED
        case 4:
            err = handle_read_input_registers(nmbs);
            break;
#endif
#ifndef NMBS_SERVER_WRITE_SINGLE_COIL_DISABLED
        case 5:
            err = handle_write_single_coil(nmbs);
            break;
#endif
#ifndef NMBS_SERVER_WRITE_SINGLE_REGISTER_DISABLED
        case 6:
            err = handle_write_single_register(nmbs);
            break;
#endif
#ifndef NMBS_SERVER_WRITE_MULTIPLE_COILS_DISABLED
        case 15:
            err = handle_write_multiple_coils(nmbs);
            break;
#endif
#ifndef NMBS_SERVER_WRITE_MULTIPLE_REGISTERS_DISABLED
        case 16:
            err = handle_write_multiple_registers(nmbs);
            break;
#endif
#ifndef NMBS_SERVER_READ_FILE_RECORD_DISABLED
        case 20:
            err = handle_read_file_record(nmbs);
            break;
#endif
#ifndef NMBS_SERVER_WRITE_FILE_RECORD_DISABLED
        case 21:
            err = handle_write_file_record(nmbs);
            break;
#endif
#ifndef NMBS_SERVER_READ_WRITE_REGISTERS_DISABLED
        case 23:
            err = handle_read_write_registers(nmbs);
            break;
#endif
#ifndef NMBS_SERVER_READ_DEVICE_IDENTIFICATION_DISABLED
        case 43:
            err = handle_read_device_identification(nmbs);
            break;
#endif
        default:
            flush(nmbs);
            if (!nmbs->msg.ignored && !nmbs->msg.broadcast)
                err = send_exception_msg(nmbs, NMBS_EXCEPTION_ILLEGAL_FUNCTION);
    }
    return err;
}
 
Steg 8:
Här är liksom slutpunkten för meddelandet. Om inte 
 if (!nmbs->msg.broadcast)  kör så blir det en timeout.
Kod: Markera allt
#if !defined(NMBS_SERVER_READ_HOLDING_REGISTERS_DISABLED) || !defined(NMBS_SERVER_READ_INPUT_REGISTERS_DISABLED)
static nmbs_error handle_read_registers(nmbs_t* nmbs,
                                        nmbs_error (*callback)(uint16_t, uint16_t, uint16_t*, uint8_t, void*)) {
    nmbs_error err = recv(nmbs, 4);
    if (err != NMBS_ERROR_NONE)
        return err;
    uint16_t address = get_2(nmbs);
    uint16_t quantity = get_2(nmbs);
    NMBS_DEBUG_PRINT("a %d\tq %d", address, quantity);
    err = recv_msg_footer(nmbs);
    if (err != NMBS_ERROR_NONE)
        return err;
    if (!nmbs->msg.ignored) {
        if (quantity < 1 || quantity > 125)
            return send_exception_msg(nmbs, NMBS_EXCEPTION_ILLEGAL_DATA_VALUE);
        if ((uint32_t) address + (uint32_t) quantity > ((uint32_t) 0xFFFF) + 1)
            return send_exception_msg(nmbs, NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS);
        if (callback) {
            uint16_t regs[125] = {0};
            err = callback(address, quantity, regs, nmbs->msg.unit_id, nmbs->callbacks.arg);
            if (err != NMBS_ERROR_NONE) {
                if (nmbs_error_is_exception(err))
                    return send_exception_msg(nmbs, err);
                return send_exception_msg(nmbs, NMBS_EXCEPTION_SERVER_DEVICE_FAILURE);
            }
            // TODO check all these read request broadcast use cases
            if (!nmbs->msg.broadcast) {
                uint8_t regs_bytes = quantity * 2;
                put_res_header(nmbs, 1 + regs_bytes);
                put_1(nmbs, regs_bytes);
                NMBS_DEBUG_PRINT("b %d\t", regs_bytes);
                NMBS_DEBUG_PRINT("regs ");
                for (int i = 0; i < quantity; i++) {
                    put_2(nmbs, regs[i]);
                    NMBS_DEBUG_PRINT("%d ", regs[i]);
                }
                err = send_msg(nmbs);
                if (err != NMBS_ERROR_NONE)
                    return err;
            }else{
            	int a = 0; /* Broroad cast! */
            }
        }
        else {
            return send_exception_msg(nmbs, NMBS_EXCEPTION_ILLEGAL_FUNCTION);
        }
    }
    else {
        return recv_read_registers_res(nmbs, quantity, NULL);
    }
    return NMBS_ERROR_NONE;
}