復制代碼- /*-
- * Copyright (c) 2017 moecmks
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
- #include <assert.h>
- #include <string.h>
- #include "codecb.h"
- /* Convert characters to specific number - noexport */
- static
- char ascii_to_num (char ch) {
- /* e.g.
- * source '9' -> target 9
- * source 'A' -> target 10
- * source '1' -> target 1
- * source 'a' -> (nondone, Don't use lowercase letters in fx1s-14mr-001).
- */
- if (ch >= '0' && ch <= '9')
- return (ch - '0');
- if (ch >= 'A' && ch <= 'F')
- return (ch - ('A' - 10));
- else
- assert (0);
- return ch;
- }
- /* Convert number to specific characters - noexport */
- static
- char num_to_ascii (char ch) {
- /* e.g.
- * source 9 -> target '9'
- * source A -> target '0'
- * source 1 -> target '1'
- * source a -> (nondone, Don't use lowercase letters in fx1s-14mr-001).
- */
- if (ch >= 0x00 && ch <= 0x09)
- return (ch + '0');
- if (ch >= 0x0A && ch <= 0x0F)
- return (ch + ('A' - 10));
- else
- assert (0);
- return ch;
- }
- /* XXX:L-endian.
- */
- static
- uint16_t vailed8 (uint16_t nums) {
-
- /* e.g.
- * 1234 vailed.
- * 9000 invailed.
- * 1007 vailed.
- * 1811 invailed.
- * 0 ~ 65535
- */
- uint16_t d0 = nums % 10 >> 0;
- uint16_t d1 = nums % 100 / 10;
- uint16_t d2 = nums % 1000 / 100;
- uint16_t d3 = nums % 10000 / 1000;
-
- if ( d0 > 7 || d1 > 7)
- return -1;
- if ( d2 > 7)
- return -1;
- return d0 + d1 * 8 + d2 * 8 * 8 + d3 * 8 * 8 * 8;
- }
- static
- uint8_t fxcrc_adjust (unsigned char *crcbuf, uint32_t num) {
-
- uint32_t s= 0;
- uint32_t st = 0;
-
- for (; s != num; s++)
- st += crcbuf[s];
- /* we only save lowest bit's byte **/
- return st & 0xFF;
- }
- static /* we not check numb cross register **.**/
- uint32_t fxcalc_addru (enum FXREGS_FIELD reg, uint16_t addr,
- enum FX1S_VERSION ver,
- uint16_t *opbsize,
- uint16_t *raddr, unsigned char *dboff) {
-
- static const /* XXX:enum constant dependence **/
- uint16_t xmax_tab[4] = { 6, 8, 12, 16 };
- static const /* XXX:enum constant dependence **/
- uint16_t ymax_tab[4] = { 4, 6, 8, 14 };
- uint16_t addr0 = 0x00A0;
- uint16_t eig = vailed8 (addr);
- uint8_t off = -1;
- uint32_t opbsize0 = 2;
- switch (reg) {
-
- case FX1S_REGISTER_FIELD_D:
-
- if (addr <= 127 && addr == addr) /* numbers: 128, normal use */
- addr0 = 0x1000 + addr * 2;
- else if (addr <= 255) /* numbers: 128, save use */
- addr0 = 0x1000 + addr * 2;
- else if (addr >= 1000 && addr <= 2499) /* numbers: 1500, file register */
- addr0 = 0x1000 + addr * 2;
- else if (addr >= 8000 && addr <= 8255) /* numbers: 256, special IO port */
- addr0 = 0x0E00 + (addr - 8000) * 2;
- else /* Illegal access */
- return FX1S_RANGE;
- break;
- case FX1S_REGISTER_FIELD_X:
- /*
- * Check the number of available X-coils according to the PLC version
- */
- if ((eig = vailed8 (addr)) == -1
- || (eig >= xmax_tab[ver]) )
- return FX1S_PARA;
-
- addr0 = 0x0080 + eig / 8;
- off = eig & 7;
-
- opbsize0 = 1;
- break;
-
- case FX1S_REGISTER_FIELD_Y_PLS:
- addr0 += 0x0200;
- case FX1S_REGISTER_FIELD_Y_OUT:
-
- /*
- * Check the number of available Y-coils according to the PLC version
- */
- if ((eig = vailed8 (addr)) == -1)
- return FX1S_PARA;
-
- addr0 += eig / 8;
- off = eig & 7;
-
- opbsize0 = 1;
- break;
- case FX1S_REGISTER_FIELD_S:
-
- if ((addr >= 128)) /* numbers:128, status register **/
- return FX1S_RANGE;
- addr0 = addr / 8;
- off = addr & 7;
-
- opbsize0 = 1;
- break;
-
- case FX1S_REGISTER_FIELD_T:
-
- if ( (addr <= 63)) /* numbers:64, 100ms or 10ms M8028/D8030/D8031 **/
- addr0 = 0x0800 + addr * 2;
- else
- return FX1S_RANGE;
- break;
-
- case FX1S_REGISTER_FIELD_M:
-
- if (addr < 384) /* numbers: 384, normal use */
- addr0 = 0x0100 + addr / 8;
- else if (addr < 512) /* numbers: 512, save use */
- addr0 = 0x0100 + addr / 8;
- else if (addr >= 8000 && addr < 8256) /* numbers: 256, special IO port */
- addr0 = 0x01E0 + (addr - 8000) / 8;
- else /* Illegal access */
- return FX1S_RANGE;
-
- off = addr & 7;
- opbsize0 = 1;
- break;
-
- case FX1S_REGISTER_FIELD_C16:
-
- if (addr < 16) /* numbers: 16, normal use */
- addr0 = 0x0A00 + addr * 2;
- else if (addr < 32) /* numbers: 16, save use */
- addr0 = 0x0A00 + addr * 2;
- else /* Illegal access */
- return FX1S_RANGE;
- break;
-
- case FX1S_REGISTER_FIELD_C32:
-
- /* for C32 high speed registers,
- * we only perform some basic checks, please note
- **/
- if (addr > 200 && addr <= 255)
- addr0 = 0x0C00 + (addr - 200) * 4;
- else /* Illegal access */
- return FX1S_RANGE;
-
- opbsize0 = 4;
- break;
-
- case FX1S_REGISTER_FIELD_CRESET:
-
- if (addr <= 255)
- addr0 = 0x03C0 + addr / 8;
- else /* Illegal access */
- return FX1S_RANGE;
-
- opbsize0 = 1;
- break;
-
- default:
- return FX1S_PARA;
- }
-
- *raddr = addr0;
- *dboff = off;
- *opbsize = opbsize0;
- return FX1S_OK;
- }
- int fx1s_makersecb (struct read_section2 *rsec, /* write to the serial port, use the size of the read_section */
- enum FX1S_REGISTER_FIELD rf, uint16_t *rvap_size,
- enum FX1S_VERSION ver, uint16_t address)
- {
- struct read_section2 sec;
- uint32_t e;
-
- /** phase 1:fill stdhead/stdend flags and cmd, rread count,s */
- sec.stx = SECTION_LINK_STX;
- sec.etx = SECTION_LINK_ETX;
- sec.cmd = SECTION_CMD_READ;
- /** phase 2:calc address for register and current PLC version */
- e = fxcalc_addru (rf, address, ver, & sec.opbsize, & sec.opbaddr, & sec.opboff);
- if (e != FX1S_OK)
- return e;
- else
- *rvap_size = sizeof (sec.stx) +
- sizeof (sec.crc)+ sizeof (sec.etx) + sec.opbsize * 2;
- /** phase 3:fill numb ascii, * */
- sec.numb[0] = num_to_ascii ( (sec.opbsize & 0xF0) >>4);
- sec.numb[1] = num_to_ascii ( (sec.opbsize & 0x0F) >>0);
-
- /** phase 4:fill address ascii, * */
- sec.unit_address[0] = num_to_ascii ( (sec.opbaddr & 0xF000) >>12);
- sec.unit_address[1] = num_to_ascii ( (sec.opbaddr & 0x0F00) >> 8);
- sec.unit_address[2] = num_to_ascii ( (sec.opbaddr & 0x00F0) >> 4);
- sec.unit_address[3] = num_to_ascii ( (sec.opbaddr & 0x000F) >> 0);
-
- /** phase 5:crc adjust, fill ascii buf * */
- sec.crce = fxcrc_adjust (& sec.cmd, sizeof (sec.cmd) + sizeof (sec.unit_address)
- + sizeof (sec.numb)
- + sizeof (sec.etx));
- sec.crc[0] = num_to_ascii ( (sec.crce & 0xF0) >> 4);
- sec.crc[1] = num_to_ascii ( (sec.crce & 0x0F) >> 0);
-
- memcpy (rsec, & sec, sizeof (sec));
- return FX1S_OK;
- }
- int fx1s_makewsecb (void *wsec, /* Variable size structure, so use void *, please understand **/
- void *buf, /* wsec size == sizeof(wc) * 2 **/
- enum FX1S_REGISTER_FIELD rf, uint16_t *wsec_size,
- enum FX1S_VERSION ver, uint16_t address)
- {
- uint16_t opbsize, opbaddr;
- char obpoff;
- char varsbuf[256];
- char *as = buf, cs;
- uint32_t e;
- uint32_t s = 0;
- struct write_section *secp = wsec;
- struct write_section *secdp = (void *)varsbuf;
- /** phase 1:fill stdhead flags and cmd */
- secdp->stx = SECTION_LINK_STX;
- secdp->cmd = SECTION_CMD_WRITE;
- /** phase 2:calc address for register and current PLC version */
- e = fxcalc_addru (rf, address, ver, & opbsize, & opbaddr, & obpoff);
- if (e != FX1S_OK)
- return e;
- else
- *wsec_size = sizeof (struct write_section) + opbsize * 2;
- /** phase 3:fill numb ascii, * */
- secdp->numb[0] = num_to_ascii ( (opbsize & 0xF0) >>4);
- secdp->numb[1] = num_to_ascii ( (opbsize & 0x0F) >>0);
-
- /** phase 4:fill address ascii, * */
- secdp->unit_address[0] = num_to_ascii ( (opbaddr & 0xF000) >>12);
- secdp->unit_address[1] = num_to_ascii ( (opbaddr & 0x0F00) >> 8);
- secdp->unit_address[2] = num_to_ascii ( (opbaddr & 0x00F0) >> 4);
- secdp->unit_address[3] = num_to_ascii ( (opbaddr & 0x000F) >> 0);
-
- /** phase 5:fill variable buffer, * */
- for ( ; s != opbsize; s++) {
- unsigned char temp = as[s];
- char tmphi = num_to_ascii (temp >> 4);
- char tmplo = num_to_ascii (temp & 15);
-
- secdp->numb[2+s*2+0] = tmphi;
- secdp->numb[2+s*2+1] = tmplo;
- }
- /** phase 6:crc adjust, fill ascii buf * */
- secdp->numb[2+opbsize*2] = SECTION_LINK_ETX;
-
- cs = fxcrc_adjust (& secdp->cmd, opbsize * 2 + sizeof (secp->cmd) + sizeof (secp->unit_address)
- + sizeof (secp->numb)
- + sizeof (secp->etx));
- secdp->numb[2+opbsize*2+1] = num_to_ascii ( (cs & 0xF0) >> 4);
- secdp->numb[2+opbsize*2+2] = num_to_ascii ( (cs & 0x0F) >> 0);
-
- memcpy (wsec, & varsbuf, *wsec_size);
- return FX1S_OK;
- }
- uint32_t fx1s_cmprvpack (void *raccbuf, /* Variable size structure, so use void *, please understand **/
- uint16_t rc, void **ascii_buf, uint16_t *opbsize
- , uint16_t *stdpos)
- {
- char *varsbuf = raccbuf;
- uint16_t c = 0;
- char stx_find = 0;
- uint16_t stdpos0 = -1;
-
- /* we find SECTION_LINK_NAK or SECTION_LINK_STX at first **/
- for (; c != rc; c++)
- {
- if (varsbuf[c] == SECTION_LINK_NAK)
- return FX1S_NAK;
- if (varsbuf[c] == SECTION_LINK_STX)
- {
- /* second, we check SECTION_LINK_ETX in buffer **/
- stx_find = 1;
- stdpos0 = c + 1;
- }
- if (varsbuf[c] == SECTION_LINK_ETX && stx_find == 1)
- {
- /* exist CRC byte ??**/
- if ((c + 2) >= rc)
- return FX1S_INCOP;
- /* calculate, compare the CRC code **/
- {
- # if 0
- # else
- *ascii_buf = & varsbuf[stdpos0];
- *opbsize = c - stdpos0;
- *stdpos = stdpos0;
- return FX1S_OK;
- # endif
- }
- }
- }
-
- return FX1S_INCOP;
- }
- uint32_t fx1s_decrvsec (void *raccbuf, void *sbuf, uint16_t opbasize) {
-
- char *varsbuf = raccbuf;
- char *ssbuf = sbuf;
- uint16_t c = 0;
-
- if (opbasize % 2 == 1)
- return FX1S_INCOP;
- if (opbasize == 0)
- return FX1S_PARA;
-
- for ( ; c != opbasize; c += 2)
- {
- char tmphi = ascii_to_num (varsbuf[c]) << 4;
- char tmplo = ascii_to_num (varsbuf[c+1]);
- char temp = (tmphi & 0xF0) | (tmplo & 0x0F);
-
- ssbuf[c>>1] = temp;
- }
-
- return FX1S_OK;
- }
|