Commit 52ab1bbea760ed8eaca184f7d875a2f52a116d0f
Committed by
Stéphane Raimbault
1 parent
1776a350
Introduce offsets in modbus mappings
This allows to place the coils/registers at any virtual start address, not only at address 0. This can be useful e.g. when the server has to fulfill a specification in which registers are expected at predefined locations. Signed-off-by: Michael Heimpold <mhei@heimpold.de>
Showing
5 changed files
with
152 additions
and
37 deletions
doc/Makefile.am
| @@ -12,6 +12,7 @@ TXT3 = \ | @@ -12,6 +12,7 @@ TXT3 = \ | ||
| 12 | modbus_get_socket.txt \ | 12 | modbus_get_socket.txt \ |
| 13 | modbus_mapping_free.txt \ | 13 | modbus_mapping_free.txt \ |
| 14 | modbus_mapping_new.txt \ | 14 | modbus_mapping_new.txt \ |
| 15 | + modbus_mapping_offset_new.txt \ | ||
| 15 | modbus_mask_write_register.txt \ | 16 | modbus_mask_write_register.txt \ |
| 16 | modbus_new_rtu.txt \ | 17 | modbus_new_rtu.txt \ |
| 17 | modbus_new_tcp_pi.txt \ | 18 | modbus_new_tcp_pi.txt \ |
doc/modbus_mapping_new.txt
| @@ -18,6 +18,9 @@ The *modbus_mapping_new()* function shall allocate four arrays to store bits, | @@ -18,6 +18,9 @@ The *modbus_mapping_new()* function shall allocate four arrays to store bits, | ||
| 18 | input bits, registers and inputs registers. The pointers are stored in | 18 | input bits, registers and inputs registers. The pointers are stored in |
| 19 | modbus_mapping_t structure. All values of the arrays are initialized to zero. | 19 | modbus_mapping_t structure. All values of the arrays are initialized to zero. |
| 20 | 20 | ||
| 21 | +This function is equivalent to a call of the _modbus_mapping_offset_new()_ function | ||
| 22 | +with all offsets set to zero. | ||
| 23 | + | ||
| 21 | If it isn't necessary to allocate an array for a specific type of data, you can | 24 | If it isn't necessary to allocate an array for a specific type of data, you can |
| 22 | pass the zero value in argument, the associated pointer will be NULL. | 25 | pass the zero value in argument, the associated pointer will be NULL. |
| 23 | 26 | ||
| @@ -40,7 +43,7 @@ EXAMPLE | @@ -40,7 +43,7 @@ EXAMPLE | ||
| 40 | ------- | 43 | ------- |
| 41 | [source,c] | 44 | [source,c] |
| 42 | ------------------- | 45 | ------------------- |
| 43 | -/* The fist value of each array is accessible from the 0 address. */ | 46 | +/* The first value of each array is accessible from the 0 address. */ |
| 44 | mb_mapping = modbus_mapping_new(BITS_ADDRESS + BITS_NB, | 47 | mb_mapping = modbus_mapping_new(BITS_ADDRESS + BITS_NB, |
| 45 | INPUT_BITS_ADDRESS + INPUT_BITS_NB, | 48 | INPUT_BITS_ADDRESS + INPUT_BITS_NB, |
| 46 | REGISTERS_ADDRESS + REGISTERS_NB, | 49 | REGISTERS_ADDRESS + REGISTERS_NB, |
doc/modbus_mapping_offset_new.txt
0 → 100644
| 1 | +modbus_mapping_offset_new(3) | ||
| 2 | +============================ | ||
| 3 | + | ||
| 4 | + | ||
| 5 | +NAME | ||
| 6 | +---- | ||
| 7 | +modbus_mapping_offset_new - allocate four arrays of bits and registers | ||
| 8 | + | ||
| 9 | + | ||
| 10 | +SYNOPSIS | ||
| 11 | +-------- | ||
| 12 | +*modbus_mapping_t* modbus_mapping_new(int 'nb_bits', int 'offset_bits', | ||
| 13 | + int 'nb_input_bits', int 'offset_input_bits', | ||
| 14 | + int 'nb_registers', int 'offset_registers', | ||
| 15 | + int 'nb_input_registers', int 'offset_input_registers');* | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +DESCRIPTION | ||
| 19 | +----------- | ||
| 20 | +The _modbus_mapping_offset_new()_ function shall allocate four arrays to store bits, | ||
| 21 | +input bits, registers and inputs registers. The pointers are stored in | ||
| 22 | +modbus_mapping_t structure. All values of the arrays are initialized to zero. | ||
| 23 | + | ||
| 24 | +The different offsets make it possible to place the mapping at any address in | ||
| 25 | +each address space. | ||
| 26 | + | ||
| 27 | +If it isn't necessary to allocate an array for a specific type of data, you can | ||
| 28 | +pass the zero value in argument, the associated pointer will be NULL. | ||
| 29 | + | ||
| 30 | +This function is convenient to handle requests in a Modbus server/slave. | ||
| 31 | + | ||
| 32 | + | ||
| 33 | +RETURN VALUE | ||
| 34 | +------------ | ||
| 35 | +The _modbus_mapping_offset_new()_ function shall return the new allocated structure if | ||
| 36 | +successful. Otherwise it shall return NULL and set errno. | ||
| 37 | + | ||
| 38 | + | ||
| 39 | +ERRORS | ||
| 40 | +------ | ||
| 41 | +ENOMEM:: | ||
| 42 | +Not enough memory | ||
| 43 | + | ||
| 44 | + | ||
| 45 | +EXAMPLE | ||
| 46 | +------- | ||
| 47 | +[source,c] | ||
| 48 | +------------------- | ||
| 49 | +/* The first value of each array is accessible at address 4. */ | ||
| 50 | +mb_mapping = modbus_mapping_offset_new(BITS_ADDRESS + BITS_NB, 4, | ||
| 51 | + INPUT_BITS_ADDRESS + INPUT_BITS_NB, 4, | ||
| 52 | + REGISTERS_ADDRESS + REGISTERS_NB, 4, | ||
| 53 | + INPUT_REGISTERS_ADDRESS + INPUT_REGISTERS_NB, 4); | ||
| 54 | +if (mb_mapping == NULL) { | ||
| 55 | + fprintf(stderr, "Failed to allocate the mapping: %s\n", | ||
| 56 | + modbus_strerror(errno)); | ||
| 57 | + modbus_free(ctx); | ||
| 58 | + return -1; | ||
| 59 | +} | ||
| 60 | +------------------- | ||
| 61 | + | ||
| 62 | +SEE ALSO | ||
| 63 | +-------- | ||
| 64 | +linkmb:modbus_mapping_free[3] | ||
| 65 | + | ||
| 66 | + | ||
| 67 | +AUTHORS | ||
| 68 | +------- | ||
| 69 | +The libmodbus documentation was written by Stéphane Raimbault | ||
| 70 | +<stephane.raimbault@gmail.com> |
src/modbus.c
| @@ -706,6 +706,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -706,6 +706,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 706 | switch (function) { | 706 | switch (function) { |
| 707 | case MODBUS_FC_READ_COILS: { | 707 | case MODBUS_FC_READ_COILS: { |
| 708 | int nb = (req[offset + 3] << 8) + req[offset + 4]; | 708 | int nb = (req[offset + 3] << 8) + req[offset + 4]; |
| 709 | + int addr = address - mb_mapping->offset_bits; | ||
| 709 | 710 | ||
| 710 | if (nb < 1 || MODBUS_MAX_READ_BITS < nb) { | 711 | if (nb < 1 || MODBUS_MAX_READ_BITS < nb) { |
| 711 | if (ctx->debug) { | 712 | if (ctx->debug) { |
| @@ -718,10 +719,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -718,10 +719,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 718 | rsp_length = response_exception( | 719 | rsp_length = response_exception( |
| 719 | ctx, &sft, | 720 | ctx, &sft, |
| 720 | MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); | 721 | MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); |
| 721 | - } else if ((address + nb) > mb_mapping->nb_bits) { | 722 | + } else if (address < mb_mapping->offset_bits || (addr + nb) > mb_mapping->nb_bits) { |
| 722 | if (ctx->debug) { | 723 | if (ctx->debug) { |
| 723 | fprintf(stderr, "Illegal data address 0x%0X in read_bits\n", | 724 | fprintf(stderr, "Illegal data address 0x%0X in read_bits\n", |
| 724 | - address + nb); | 725 | + address < mb_mapping->offset_bits ? address : address + nb); |
| 725 | } | 726 | } |
| 726 | rsp_length = response_exception( | 727 | rsp_length = response_exception( |
| 727 | ctx, &sft, | 728 | ctx, &sft, |
| @@ -729,7 +730,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -729,7 +730,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 729 | } else { | 730 | } else { |
| 730 | rsp_length = ctx->backend->build_response_basis(&sft, rsp); | 731 | rsp_length = ctx->backend->build_response_basis(&sft, rsp); |
| 731 | rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0); | 732 | rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0); |
| 732 | - rsp_length = response_io_status(address, nb, | 733 | + rsp_length = response_io_status(addr, nb, |
| 733 | mb_mapping->tab_bits, | 734 | mb_mapping->tab_bits, |
| 734 | rsp, rsp_length); | 735 | rsp, rsp_length); |
| 735 | } | 736 | } |
| @@ -739,6 +740,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -739,6 +740,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 739 | /* Similar to coil status (but too many arguments to use a | 740 | /* Similar to coil status (but too many arguments to use a |
| 740 | * function) */ | 741 | * function) */ |
| 741 | int nb = (req[offset + 3] << 8) + req[offset + 4]; | 742 | int nb = (req[offset + 3] << 8) + req[offset + 4]; |
| 743 | + int addr = address - mb_mapping->offset_input_bits; | ||
| 742 | 744 | ||
| 743 | if (nb < 1 || MODBUS_MAX_READ_BITS < nb) { | 745 | if (nb < 1 || MODBUS_MAX_READ_BITS < nb) { |
| 744 | if (ctx->debug) { | 746 | if (ctx->debug) { |
| @@ -751,10 +753,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -751,10 +753,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 751 | rsp_length = response_exception( | 753 | rsp_length = response_exception( |
| 752 | ctx, &sft, | 754 | ctx, &sft, |
| 753 | MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); | 755 | MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); |
| 754 | - } else if ((address + nb) > mb_mapping->nb_input_bits) { | 756 | + } else if (address < mb_mapping->offset_input_bits || (addr + nb) > mb_mapping->nb_input_bits) { |
| 755 | if (ctx->debug) { | 757 | if (ctx->debug) { |
| 756 | fprintf(stderr, "Illegal data address 0x%0X in read_input_bits\n", | 758 | fprintf(stderr, "Illegal data address 0x%0X in read_input_bits\n", |
| 757 | - address + nb); | 759 | + address < mb_mapping->offset_input_bits ? address : address + nb); |
| 758 | } | 760 | } |
| 759 | rsp_length = response_exception( | 761 | rsp_length = response_exception( |
| 760 | ctx, &sft, | 762 | ctx, &sft, |
| @@ -762,7 +764,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -762,7 +764,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 762 | } else { | 764 | } else { |
| 763 | rsp_length = ctx->backend->build_response_basis(&sft, rsp); | 765 | rsp_length = ctx->backend->build_response_basis(&sft, rsp); |
| 764 | rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0); | 766 | rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0); |
| 765 | - rsp_length = response_io_status(address, nb, | 767 | + rsp_length = response_io_status(addr, nb, |
| 766 | mb_mapping->tab_input_bits, | 768 | mb_mapping->tab_input_bits, |
| 767 | rsp, rsp_length); | 769 | rsp, rsp_length); |
| 768 | } | 770 | } |
| @@ -770,6 +772,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -770,6 +772,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 770 | break; | 772 | break; |
| 771 | case MODBUS_FC_READ_HOLDING_REGISTERS: { | 773 | case MODBUS_FC_READ_HOLDING_REGISTERS: { |
| 772 | int nb = (req[offset + 3] << 8) + req[offset + 4]; | 774 | int nb = (req[offset + 3] << 8) + req[offset + 4]; |
| 775 | + int addr = address - mb_mapping->offset_registers; | ||
| 773 | 776 | ||
| 774 | if (nb < 1 || MODBUS_MAX_READ_REGISTERS < nb) { | 777 | if (nb < 1 || MODBUS_MAX_READ_REGISTERS < nb) { |
| 775 | if (ctx->debug) { | 778 | if (ctx->debug) { |
| @@ -782,10 +785,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -782,10 +785,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 782 | rsp_length = response_exception( | 785 | rsp_length = response_exception( |
| 783 | ctx, &sft, | 786 | ctx, &sft, |
| 784 | MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); | 787 | MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); |
| 785 | - } else if ((address + nb) > mb_mapping->nb_registers) { | 788 | + } else if (address < mb_mapping->offset_registers || (addr + nb) > mb_mapping->nb_registers) { |
| 786 | if (ctx->debug) { | 789 | if (ctx->debug) { |
| 787 | fprintf(stderr, "Illegal data address 0x%0X in read_registers\n", | 790 | fprintf(stderr, "Illegal data address 0x%0X in read_registers\n", |
| 788 | - address + nb); | 791 | + address < mb_mapping->offset_registers ? address : address + nb); |
| 789 | } | 792 | } |
| 790 | rsp_length = response_exception( | 793 | rsp_length = response_exception( |
| 791 | ctx, &sft, | 794 | ctx, &sft, |
| @@ -795,7 +798,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -795,7 +798,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 795 | 798 | ||
| 796 | rsp_length = ctx->backend->build_response_basis(&sft, rsp); | 799 | rsp_length = ctx->backend->build_response_basis(&sft, rsp); |
| 797 | rsp[rsp_length++] = nb << 1; | 800 | rsp[rsp_length++] = nb << 1; |
| 798 | - for (i = address; i < address + nb; i++) { | 801 | + for (i = addr; i < addr + nb; i++) { |
| 799 | rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8; | 802 | rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8; |
| 800 | rsp[rsp_length++] = mb_mapping->tab_registers[i] & 0xFF; | 803 | rsp[rsp_length++] = mb_mapping->tab_registers[i] & 0xFF; |
| 801 | } | 804 | } |
| @@ -806,6 +809,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -806,6 +809,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 806 | /* Similar to holding registers (but too many arguments to use a | 809 | /* Similar to holding registers (but too many arguments to use a |
| 807 | * function) */ | 810 | * function) */ |
| 808 | int nb = (req[offset + 3] << 8) + req[offset + 4]; | 811 | int nb = (req[offset + 3] << 8) + req[offset + 4]; |
| 812 | + int addr = address - mb_mapping->offset_input_registers; | ||
| 809 | 813 | ||
| 810 | if (nb < 1 || MODBUS_MAX_READ_REGISTERS < nb) { | 814 | if (nb < 1 || MODBUS_MAX_READ_REGISTERS < nb) { |
| 811 | if (ctx->debug) { | 815 | if (ctx->debug) { |
| @@ -818,10 +822,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -818,10 +822,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 818 | rsp_length = response_exception( | 822 | rsp_length = response_exception( |
| 819 | ctx, &sft, | 823 | ctx, &sft, |
| 820 | MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); | 824 | MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); |
| 821 | - } else if ((address + nb) > mb_mapping->nb_input_registers) { | 825 | + } else if (address < mb_mapping->offset_input_registers || (addr + nb) > mb_mapping->nb_input_registers) { |
| 822 | if (ctx->debug) { | 826 | if (ctx->debug) { |
| 823 | fprintf(stderr, "Illegal data address 0x%0X in read_input_registers\n", | 827 | fprintf(stderr, "Illegal data address 0x%0X in read_input_registers\n", |
| 824 | - address + nb); | 828 | + address < mb_mapping->offset_input_registers ? address : address + nb); |
| 825 | } | 829 | } |
| 826 | rsp_length = response_exception( | 830 | rsp_length = response_exception( |
| 827 | ctx, &sft, | 831 | ctx, &sft, |
| @@ -831,15 +835,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -831,15 +835,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 831 | 835 | ||
| 832 | rsp_length = ctx->backend->build_response_basis(&sft, rsp); | 836 | rsp_length = ctx->backend->build_response_basis(&sft, rsp); |
| 833 | rsp[rsp_length++] = nb << 1; | 837 | rsp[rsp_length++] = nb << 1; |
| 834 | - for (i = address; i < address + nb; i++) { | 838 | + for (i = addr; i < addr + nb; i++) { |
| 835 | rsp[rsp_length++] = mb_mapping->tab_input_registers[i] >> 8; | 839 | rsp[rsp_length++] = mb_mapping->tab_input_registers[i] >> 8; |
| 836 | rsp[rsp_length++] = mb_mapping->tab_input_registers[i] & 0xFF; | 840 | rsp[rsp_length++] = mb_mapping->tab_input_registers[i] & 0xFF; |
| 837 | } | 841 | } |
| 838 | } | 842 | } |
| 839 | } | 843 | } |
| 840 | break; | 844 | break; |
| 841 | - case MODBUS_FC_WRITE_SINGLE_COIL: | ||
| 842 | - if (address >= mb_mapping->nb_bits) { | 845 | + case MODBUS_FC_WRITE_SINGLE_COIL: { |
| 846 | + int addr = address - mb_mapping->offset_bits; | ||
| 847 | + | ||
| 848 | + if (address < mb_mapping->offset_bits || addr >= mb_mapping->nb_bits) { | ||
| 843 | if (ctx->debug) { | 849 | if (ctx->debug) { |
| 844 | fprintf(stderr, | 850 | fprintf(stderr, |
| 845 | "Illegal data address 0x%0X in write_bit\n", | 851 | "Illegal data address 0x%0X in write_bit\n", |
| @@ -852,7 +858,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -852,7 +858,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 852 | int data = (req[offset + 3] << 8) + req[offset + 4]; | 858 | int data = (req[offset + 3] << 8) + req[offset + 4]; |
| 853 | 859 | ||
| 854 | if (data == 0xFF00 || data == 0x0) { | 860 | if (data == 0xFF00 || data == 0x0) { |
| 855 | - mb_mapping->tab_bits[address] = (data) ? ON : OFF; | 861 | + mb_mapping->tab_bits[addr] = (data) ? ON : OFF; |
| 856 | memcpy(rsp, req, req_length); | 862 | memcpy(rsp, req, req_length); |
| 857 | rsp_length = req_length; | 863 | rsp_length = req_length; |
| 858 | } else { | 864 | } else { |
| @@ -866,9 +872,12 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -866,9 +872,12 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 866 | MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); | 872 | MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); |
| 867 | } | 873 | } |
| 868 | } | 874 | } |
| 875 | + } | ||
| 869 | break; | 876 | break; |
| 870 | - case MODBUS_FC_WRITE_SINGLE_REGISTER: | ||
| 871 | - if (address >= mb_mapping->nb_registers) { | 877 | + case MODBUS_FC_WRITE_SINGLE_REGISTER: { |
| 878 | + int addr = address - mb_mapping->offset_registers; | ||
| 879 | + | ||
| 880 | + if (address < mb_mapping->offset_registers || addr >= mb_mapping->nb_registers) { | ||
| 872 | if (ctx->debug) { | 881 | if (ctx->debug) { |
| 873 | fprintf(stderr, "Illegal data address 0x%0X in write_register\n", | 882 | fprintf(stderr, "Illegal data address 0x%0X in write_register\n", |
| 874 | address); | 883 | address); |
| @@ -879,13 +888,15 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -879,13 +888,15 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 879 | } else { | 888 | } else { |
| 880 | int data = (req[offset + 3] << 8) + req[offset + 4]; | 889 | int data = (req[offset + 3] << 8) + req[offset + 4]; |
| 881 | 890 | ||
| 882 | - mb_mapping->tab_registers[address] = data; | 891 | + mb_mapping->tab_registers[addr] = data; |
| 883 | memcpy(rsp, req, req_length); | 892 | memcpy(rsp, req, req_length); |
| 884 | rsp_length = req_length; | 893 | rsp_length = req_length; |
| 885 | } | 894 | } |
| 895 | + } | ||
| 886 | break; | 896 | break; |
| 887 | case MODBUS_FC_WRITE_MULTIPLE_COILS: { | 897 | case MODBUS_FC_WRITE_MULTIPLE_COILS: { |
| 888 | int nb = (req[offset + 3] << 8) + req[offset + 4]; | 898 | int nb = (req[offset + 3] << 8) + req[offset + 4]; |
| 899 | + int addr = address - mb_mapping->offset_bits; | ||
| 889 | 900 | ||
| 890 | if (nb < 1 || MODBUS_MAX_WRITE_BITS < nb) { | 901 | if (nb < 1 || MODBUS_MAX_WRITE_BITS < nb) { |
| 891 | if (ctx->debug) { | 902 | if (ctx->debug) { |
| @@ -901,17 +912,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -901,17 +912,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 901 | rsp_length = response_exception( | 912 | rsp_length = response_exception( |
| 902 | ctx, &sft, | 913 | ctx, &sft, |
| 903 | MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); | 914 | MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); |
| 904 | - } else if ((address + nb) > mb_mapping->nb_bits) { | 915 | + } else if (address < mb_mapping->offset_bits || (addr + nb) > mb_mapping->nb_bits) { |
| 905 | if (ctx->debug) { | 916 | if (ctx->debug) { |
| 906 | fprintf(stderr, "Illegal data address 0x%0X in write_bits\n", | 917 | fprintf(stderr, "Illegal data address 0x%0X in write_bits\n", |
| 907 | - address + nb); | 918 | + address < mb_mapping->offset_bits ? address : address + nb); |
| 908 | } | 919 | } |
| 909 | rsp_length = response_exception( | 920 | rsp_length = response_exception( |
| 910 | ctx, &sft, | 921 | ctx, &sft, |
| 911 | MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp); | 922 | MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp); |
| 912 | } else { | 923 | } else { |
| 913 | /* 6 = byte count */ | 924 | /* 6 = byte count */ |
| 914 | - modbus_set_bits_from_bytes(mb_mapping->tab_bits, address, nb, &req[offset + 6]); | 925 | + modbus_set_bits_from_bytes(mb_mapping->tab_bits, addr, nb, &req[offset + 6]); |
| 915 | 926 | ||
| 916 | rsp_length = ctx->backend->build_response_basis(&sft, rsp); | 927 | rsp_length = ctx->backend->build_response_basis(&sft, rsp); |
| 917 | /* 4 to copy the bit address (2) and the quantity of bits */ | 928 | /* 4 to copy the bit address (2) and the quantity of bits */ |
| @@ -922,6 +933,8 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -922,6 +933,8 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 922 | break; | 933 | break; |
| 923 | case MODBUS_FC_WRITE_MULTIPLE_REGISTERS: { | 934 | case MODBUS_FC_WRITE_MULTIPLE_REGISTERS: { |
| 924 | int nb = (req[offset + 3] << 8) + req[offset + 4]; | 935 | int nb = (req[offset + 3] << 8) + req[offset + 4]; |
| 936 | + int addr = address - mb_mapping->offset_registers; | ||
| 937 | + | ||
| 925 | if (nb < 1 || MODBUS_MAX_WRITE_REGISTERS < nb) { | 938 | if (nb < 1 || MODBUS_MAX_WRITE_REGISTERS < nb) { |
| 926 | if (ctx->debug) { | 939 | if (ctx->debug) { |
| 927 | fprintf(stderr, | 940 | fprintf(stderr, |
| @@ -936,17 +949,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -936,17 +949,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 936 | rsp_length = response_exception( | 949 | rsp_length = response_exception( |
| 937 | ctx, &sft, | 950 | ctx, &sft, |
| 938 | MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); | 951 | MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); |
| 939 | - } else if ((address + nb) > mb_mapping->nb_registers) { | 952 | + } else if (address < mb_mapping->offset_registers || (addr + nb) > mb_mapping->nb_registers) { |
| 940 | if (ctx->debug) { | 953 | if (ctx->debug) { |
| 941 | fprintf(stderr, "Illegal data address 0x%0X in write_registers\n", | 954 | fprintf(stderr, "Illegal data address 0x%0X in write_registers\n", |
| 942 | - address + nb); | 955 | + address < mb_mapping->offset_registers ? address : address + nb); |
| 943 | } | 956 | } |
| 944 | rsp_length = response_exception( | 957 | rsp_length = response_exception( |
| 945 | ctx, &sft, | 958 | ctx, &sft, |
| 946 | MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp); | 959 | MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp); |
| 947 | } else { | 960 | } else { |
| 948 | int i, j; | 961 | int i, j; |
| 949 | - for (i = address, j = 6; i < address + nb; i++, j += 2) { | 962 | + for (i = addr, j = 6; i < addr + nb; i++, j += 2) { |
| 950 | /* 6 and 7 = first value */ | 963 | /* 6 and 7 = first value */ |
| 951 | mb_mapping->tab_registers[i] = | 964 | mb_mapping->tab_registers[i] = |
| 952 | (req[offset + j] << 8) + req[offset + j + 1]; | 965 | (req[offset + j] << 8) + req[offset + j + 1]; |
| @@ -983,8 +996,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -983,8 +996,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 983 | errno = ENOPROTOOPT; | 996 | errno = ENOPROTOOPT; |
| 984 | return -1; | 997 | return -1; |
| 985 | break; | 998 | break; |
| 986 | - case MODBUS_FC_MASK_WRITE_REGISTER: | ||
| 987 | - if (address >= mb_mapping->nb_registers) { | 999 | + case MODBUS_FC_MASK_WRITE_REGISTER: { |
| 1000 | + int addr = address - mb_mapping->offset_registers; | ||
| 1001 | + | ||
| 1002 | + if (address < mb_mapping->offset_registers || addr >= mb_mapping->nb_registers) { | ||
| 988 | if (ctx->debug) { | 1003 | if (ctx->debug) { |
| 989 | fprintf(stderr, "Illegal data address 0x%0X in write_register\n", | 1004 | fprintf(stderr, "Illegal data address 0x%0X in write_register\n", |
| 990 | address); | 1005 | address); |
| @@ -993,21 +1008,24 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -993,21 +1008,24 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 993 | ctx, &sft, | 1008 | ctx, &sft, |
| 994 | MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp); | 1009 | MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp); |
| 995 | } else { | 1010 | } else { |
| 996 | - uint16_t data = mb_mapping->tab_registers[address]; | 1011 | + uint16_t data = mb_mapping->tab_registers[addr]; |
| 997 | uint16_t and = (req[offset + 3] << 8) + req[offset + 4]; | 1012 | uint16_t and = (req[offset + 3] << 8) + req[offset + 4]; |
| 998 | uint16_t or = (req[offset + 5] << 8) + req[offset + 6]; | 1013 | uint16_t or = (req[offset + 5] << 8) + req[offset + 6]; |
| 999 | 1014 | ||
| 1000 | data = (data & and) | (or & (~and)); | 1015 | data = (data & and) | (or & (~and)); |
| 1001 | - mb_mapping->tab_registers[address] = data; | 1016 | + mb_mapping->tab_registers[addr] = data; |
| 1002 | memcpy(rsp, req, req_length); | 1017 | memcpy(rsp, req, req_length); |
| 1003 | rsp_length = req_length; | 1018 | rsp_length = req_length; |
| 1004 | } | 1019 | } |
| 1020 | + } | ||
| 1005 | break; | 1021 | break; |
| 1006 | case MODBUS_FC_WRITE_AND_READ_REGISTERS: { | 1022 | case MODBUS_FC_WRITE_AND_READ_REGISTERS: { |
| 1007 | int nb = (req[offset + 3] << 8) + req[offset + 4]; | 1023 | int nb = (req[offset + 3] << 8) + req[offset + 4]; |
| 1008 | uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6]; | 1024 | uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6]; |
| 1009 | int nb_write = (req[offset + 7] << 8) + req[offset + 8]; | 1025 | int nb_write = (req[offset + 7] << 8) + req[offset + 8]; |
| 1010 | int nb_write_bytes = req[offset + 9]; | 1026 | int nb_write_bytes = req[offset + 9]; |
| 1027 | + int addr = address - mb_mapping->offset_registers; | ||
| 1028 | + int addr_write = address_write - mb_mapping->offset_registers; | ||
| 1011 | 1029 | ||
| 1012 | if (nb_write < 1 || MODBUS_MAX_WR_WRITE_REGISTERS < nb_write || | 1030 | if (nb_write < 1 || MODBUS_MAX_WR_WRITE_REGISTERS < nb_write || |
| 1013 | nb < 1 || MODBUS_MAX_WR_READ_REGISTERS < nb || | 1031 | nb < 1 || MODBUS_MAX_WR_READ_REGISTERS < nb || |
| @@ -1023,12 +1041,15 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -1023,12 +1041,15 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 1023 | rsp_length = response_exception( | 1041 | rsp_length = response_exception( |
| 1024 | ctx, &sft, | 1042 | ctx, &sft, |
| 1025 | MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); | 1043 | MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); |
| 1026 | - } else if ((address + nb) > mb_mapping->nb_registers || | ||
| 1027 | - (address_write + nb_write) > mb_mapping->nb_registers) { | 1044 | + } else if (address < mb_mapping->offset_registers || |
| 1045 | + (addr + nb) > mb_mapping->nb_registers || | ||
| 1046 | + address_write < mb_mapping->offset_registers || | ||
| 1047 | + (addr_write + nb_write) > mb_mapping->nb_registers) { | ||
| 1028 | if (ctx->debug) { | 1048 | if (ctx->debug) { |
| 1029 | fprintf(stderr, | 1049 | fprintf(stderr, |
| 1030 | "Illegal data read address 0x%0X or write address 0x%0X write_and_read_registers\n", | 1050 | "Illegal data read address 0x%0X or write address 0x%0X write_and_read_registers\n", |
| 1031 | - address + nb, address_write + nb_write); | 1051 | + address < mb_mapping->offset_registers ? address : address + nb, |
| 1052 | + address_write < mb_mapping->offset_registers ? address_write : address_write + nb_write); | ||
| 1032 | } | 1053 | } |
| 1033 | rsp_length = response_exception(ctx, &sft, | 1054 | rsp_length = response_exception(ctx, &sft, |
| 1034 | MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp); | 1055 | MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp); |
| @@ -1039,13 +1060,13 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -1039,13 +1060,13 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 1039 | 1060 | ||
| 1040 | /* Write first. | 1061 | /* Write first. |
| 1041 | 10 and 11 are the offset of the first values to write */ | 1062 | 10 and 11 are the offset of the first values to write */ |
| 1042 | - for (i = address_write, j = 10; i < address_write + nb_write; i++, j += 2) { | 1063 | + for (i = addr_write, j = 10; i < addr_write + nb_write; i++, j += 2) { |
| 1043 | mb_mapping->tab_registers[i] = | 1064 | mb_mapping->tab_registers[i] = |
| 1044 | (req[offset + j] << 8) + req[offset + j + 1]; | 1065 | (req[offset + j] << 8) + req[offset + j + 1]; |
| 1045 | } | 1066 | } |
| 1046 | 1067 | ||
| 1047 | /* and read the data for the response */ | 1068 | /* and read the data for the response */ |
| 1048 | - for (i = address; i < address + nb; i++) { | 1069 | + for (i = addr; i < addr + nb; i++) { |
| 1049 | rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8; | 1070 | rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8; |
| 1050 | rsp[rsp_length++] = mb_mapping->tab_registers[i] & 0xFF; | 1071 | rsp[rsp_length++] = mb_mapping->tab_registers[i] & 0xFF; |
| 1051 | } | 1072 | } |
| @@ -1786,10 +1807,12 @@ int modbus_set_debug(modbus_t *ctx, int flag) | @@ -1786,10 +1807,12 @@ int modbus_set_debug(modbus_t *ctx, int flag) | ||
| 1786 | /* Allocates 4 arrays to store bits, input bits, registers and inputs | 1807 | /* Allocates 4 arrays to store bits, input bits, registers and inputs |
| 1787 | registers. The pointers are stored in modbus_mapping structure. | 1808 | registers. The pointers are stored in modbus_mapping structure. |
| 1788 | 1809 | ||
| 1789 | - The modbus_mapping_new() function shall return the new allocated structure if | 1810 | + The modbus_mapping_offset_new() function shall return the new allocated structure if |
| 1790 | successful. Otherwise it shall return NULL and set errno to ENOMEM. */ | 1811 | successful. Otherwise it shall return NULL and set errno to ENOMEM. */ |
| 1791 | -modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, | ||
| 1792 | - int nb_registers, int nb_input_registers) | 1812 | +modbus_mapping_t* modbus_mapping_offset_new(int nb_bits, int offset_bits, |
| 1813 | + int nb_input_bits, int offset_input_bits, | ||
| 1814 | + int nb_registers, int offset_registers, | ||
| 1815 | + int nb_input_registers, int offset_input_registers) | ||
| 1793 | { | 1816 | { |
| 1794 | modbus_mapping_t *mb_mapping; | 1817 | modbus_mapping_t *mb_mapping; |
| 1795 | 1818 | ||
| @@ -1800,6 +1823,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, | @@ -1800,6 +1823,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, | ||
| 1800 | 1823 | ||
| 1801 | /* 0X */ | 1824 | /* 0X */ |
| 1802 | mb_mapping->nb_bits = nb_bits; | 1825 | mb_mapping->nb_bits = nb_bits; |
| 1826 | + mb_mapping->offset_bits = offset_bits; | ||
| 1803 | if (nb_bits == 0) { | 1827 | if (nb_bits == 0) { |
| 1804 | mb_mapping->tab_bits = NULL; | 1828 | mb_mapping->tab_bits = NULL; |
| 1805 | } else { | 1829 | } else { |
| @@ -1815,6 +1839,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, | @@ -1815,6 +1839,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, | ||
| 1815 | 1839 | ||
| 1816 | /* 1X */ | 1840 | /* 1X */ |
| 1817 | mb_mapping->nb_input_bits = nb_input_bits; | 1841 | mb_mapping->nb_input_bits = nb_input_bits; |
| 1842 | + mb_mapping->offset_input_bits = offset_input_bits; | ||
| 1818 | if (nb_input_bits == 0) { | 1843 | if (nb_input_bits == 0) { |
| 1819 | mb_mapping->tab_input_bits = NULL; | 1844 | mb_mapping->tab_input_bits = NULL; |
| 1820 | } else { | 1845 | } else { |
| @@ -1830,6 +1855,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, | @@ -1830,6 +1855,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, | ||
| 1830 | 1855 | ||
| 1831 | /* 4X */ | 1856 | /* 4X */ |
| 1832 | mb_mapping->nb_registers = nb_registers; | 1857 | mb_mapping->nb_registers = nb_registers; |
| 1858 | + mb_mapping->offset_registers = offset_registers; | ||
| 1833 | if (nb_registers == 0) { | 1859 | if (nb_registers == 0) { |
| 1834 | mb_mapping->tab_registers = NULL; | 1860 | mb_mapping->tab_registers = NULL; |
| 1835 | } else { | 1861 | } else { |
| @@ -1846,6 +1872,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, | @@ -1846,6 +1872,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, | ||
| 1846 | 1872 | ||
| 1847 | /* 3X */ | 1873 | /* 3X */ |
| 1848 | mb_mapping->nb_input_registers = nb_input_registers; | 1874 | mb_mapping->nb_input_registers = nb_input_registers; |
| 1875 | + mb_mapping->offset_input_registers = offset_input_registers; | ||
| 1849 | if (nb_input_registers == 0) { | 1876 | if (nb_input_registers == 0) { |
| 1850 | mb_mapping->tab_input_registers = NULL; | 1877 | mb_mapping->tab_input_registers = NULL; |
| 1851 | } else { | 1878 | } else { |
| @@ -1865,6 +1892,12 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, | @@ -1865,6 +1892,12 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, | ||
| 1865 | return mb_mapping; | 1892 | return mb_mapping; |
| 1866 | } | 1893 | } |
| 1867 | 1894 | ||
| 1895 | +modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, | ||
| 1896 | + int nb_registers, int nb_input_registers) | ||
| 1897 | +{ | ||
| 1898 | + return modbus_mapping_offset_new(nb_bits, 0, nb_input_bits, 0, nb_registers, 0, nb_input_registers, 0); | ||
| 1899 | +} | ||
| 1900 | + | ||
| 1868 | /* Frees the 4 arrays */ | 1901 | /* Frees the 4 arrays */ |
| 1869 | void modbus_mapping_free(modbus_mapping_t *mb_mapping) | 1902 | void modbus_mapping_free(modbus_mapping_t *mb_mapping) |
| 1870 | { | 1903 | { |
src/modbus.h
| @@ -156,9 +156,13 @@ typedef struct _modbus modbus_t; | @@ -156,9 +156,13 @@ typedef struct _modbus modbus_t; | ||
| 156 | 156 | ||
| 157 | typedef struct { | 157 | typedef struct { |
| 158 | int nb_bits; | 158 | int nb_bits; |
| 159 | + int offset_bits; | ||
| 159 | int nb_input_bits; | 160 | int nb_input_bits; |
| 161 | + int offset_input_bits; | ||
| 160 | int nb_input_registers; | 162 | int nb_input_registers; |
| 163 | + int offset_input_registers; | ||
| 161 | int nb_registers; | 164 | int nb_registers; |
| 165 | + int offset_registers; | ||
| 162 | uint8_t *tab_bits; | 166 | uint8_t *tab_bits; |
| 163 | uint8_t *tab_input_bits; | 167 | uint8_t *tab_input_bits; |
| 164 | uint16_t *tab_input_registers; | 168 | uint16_t *tab_input_registers; |
| @@ -209,6 +213,10 @@ MODBUS_API int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, in | @@ -209,6 +213,10 @@ MODBUS_API int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, in | ||
| 209 | uint16_t *dest); | 213 | uint16_t *dest); |
| 210 | MODBUS_API int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest); | 214 | MODBUS_API int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest); |
| 211 | 215 | ||
| 216 | +MODBUS_API modbus_mapping_t* modbus_mapping_offset_new(int nb_bits, int offset_bits, | ||
| 217 | + int nb_input_bits, int offset_input_bits, | ||
| 218 | + int nb_registers, int offset_registers, | ||
| 219 | + int nb_input_registers, int offset_input_registers); | ||
| 212 | MODBUS_API modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, | 220 | MODBUS_API modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, |
| 213 | int nb_registers, int nb_input_registers); | 221 | int nb_registers, int nb_input_registers); |
| 214 | MODBUS_API void modbus_mapping_free(modbus_mapping_t *mb_mapping); | 222 | MODBUS_API void modbus_mapping_free(modbus_mapping_t *mb_mapping); |