hlp:桂林国际齿轮泵代码
This commit is contained in:
@@ -0,0 +1,486 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||
* 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
|
||||
*
|
||||
* File: $Id: mbascii.c,v 1.17 2010/06/06 13:47:07 wolti Exp $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mbconfig.h"
|
||||
#include "mbascii.h"
|
||||
#include "mbframe.h"
|
||||
|
||||
#include "mbcrc.h"
|
||||
#include "mbport.h"
|
||||
|
||||
#if MB_ASCII_ENABLED > 0
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define MB_ASCII_DEFAULT_CR '\r' /*!< Default CR character for Modbus ASCII. */
|
||||
#define MB_ASCII_DEFAULT_LF '\n' /*!< Default LF character for Modbus ASCII. */
|
||||
#define MB_SER_PDU_SIZE_MIN 3 /*!< Minimum size of a Modbus ASCII frame. */
|
||||
#define MB_SER_PDU_SIZE_MAX 256 /*!< Maximum size of a Modbus ASCII frame. */
|
||||
#define MB_SER_PDU_SIZE_LRC 1 /*!< Size of LRC field in PDU. */
|
||||
#define MB_SER_PDU_ADDR_OFF 0 /*!< Offset of slave address in Ser-PDU. */
|
||||
#define MB_SER_PDU_PDU_OFF 1 /*!< Offset of Modbus-PDU in Ser-PDU. */
|
||||
|
||||
/* ----------------------- Type definitions ---------------------------------*/
|
||||
typedef enum
|
||||
{
|
||||
STATE_RX_IDLE, /*!< Receiver is in idle state. */
|
||||
STATE_RX_RCV, /*!< Frame is beeing received. */
|
||||
STATE_RX_WAIT_EOF /*!< Wait for End of Frame. */
|
||||
} eMBRcvState;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STATE_TX_IDLE, /*!< Transmitter is in idle state. */
|
||||
STATE_TX_START, /*!< Starting transmission (':' sent). */
|
||||
STATE_TX_DATA, /*!< Sending of data (Address, Data, LRC). */
|
||||
STATE_TX_END, /*!< End of transmission. */
|
||||
STATE_TX_NOTIFY /*!< Notify sender that the frame has been sent. */
|
||||
} eMBSndState;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BYTE_HIGH_NIBBLE, /*!< Character for high nibble of byte. */
|
||||
BYTE_LOW_NIBBLE /*!< Character for low nibble of byte. */
|
||||
} eMBBytePos;
|
||||
|
||||
/* ----------------------- Static functions ---------------------------------*/
|
||||
static UCHAR prvucMBCHAR2BIN( UCHAR ucCharacter );
|
||||
|
||||
static UCHAR prvucMBBIN2CHAR( UCHAR ucByte );
|
||||
|
||||
static UCHAR prvucMBLRC( UCHAR * pucFrame, USHORT usLen );
|
||||
|
||||
/* ----------------------- Static variables ---------------------------------*/
|
||||
static volatile eMBSndState eSndState;
|
||||
static volatile eMBRcvState eRcvState;
|
||||
|
||||
/* We reuse the Modbus RTU buffer because only one buffer is needed and the
|
||||
* RTU buffer is bigger. */
|
||||
extern volatile UCHAR ucRTUBuf[];
|
||||
static volatile UCHAR *ucASCIIBuf = ucRTUBuf;
|
||||
|
||||
static volatile USHORT usRcvBufferPos;
|
||||
static volatile eMBBytePos eBytePos;
|
||||
|
||||
static volatile UCHAR *pucSndBufferCur;
|
||||
static volatile USHORT usSndBufferCount;
|
||||
|
||||
static volatile UCHAR ucLRC;
|
||||
static volatile UCHAR ucMBLFCharacter;
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
eMBErrorCode
|
||||
eMBASCIIInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
( void )ucSlaveAddress;
|
||||
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
ucMBLFCharacter = MB_ASCII_DEFAULT_LF;
|
||||
|
||||
if( xMBPortSerialInit( ucPort, ulBaudRate, 7, eParity ) != TRUE )
|
||||
{
|
||||
eStatus = MB_EPORTERR;
|
||||
}
|
||||
else if( xMBPortTimersInit( MB_ASCII_TIMEOUT_SEC * 20000UL ) != TRUE )
|
||||
{
|
||||
eStatus = MB_EPORTERR;
|
||||
}
|
||||
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
void
|
||||
eMBASCIIStart( void )
|
||||
{
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
vMBPortSerialEnable( TRUE, FALSE );
|
||||
eRcvState = STATE_RX_IDLE;
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
|
||||
/* No special startup required for ASCII. */
|
||||
( void )xMBPortEventPost( EV_READY );
|
||||
}
|
||||
|
||||
void
|
||||
eMBASCIIStop( void )
|
||||
{
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
vMBPortSerialEnable( FALSE, FALSE );
|
||||
vMBPortTimersDisable( );
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
assert( usRcvBufferPos < MB_SER_PDU_SIZE_MAX );
|
||||
|
||||
/* Length and CRC check */
|
||||
if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
|
||||
&& ( prvucMBLRC( ( UCHAR * ) ucASCIIBuf, usRcvBufferPos ) == 0 ) )
|
||||
{
|
||||
/* Save the address field. All frames are passed to the upper layed
|
||||
* and the decision if a frame is used is done there.
|
||||
*/
|
||||
*pucRcvAddress = ucASCIIBuf[MB_SER_PDU_ADDR_OFF];
|
||||
|
||||
/* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
|
||||
* size of address field and CRC checksum.
|
||||
*/
|
||||
*pusLength = ( USHORT )( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_LRC );
|
||||
|
||||
/* Return the start of the Modbus PDU to the caller. */
|
||||
*pucFrame = ( UCHAR * ) & ucASCIIBuf[MB_SER_PDU_PDU_OFF];
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EIO;
|
||||
}
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBASCIISend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
UCHAR usLRC;
|
||||
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
/* Check if the receiver is still in idle state. If not we where too
|
||||
* slow with processing the received frame and the master sent another
|
||||
* frame on the network. We have to abort sending the frame.
|
||||
*/
|
||||
if( eRcvState == STATE_RX_IDLE )
|
||||
{
|
||||
/* First byte before the Modbus-PDU is the slave address. */
|
||||
pucSndBufferCur = ( UCHAR * ) pucFrame - 1;
|
||||
usSndBufferCount = 1;
|
||||
|
||||
/* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
|
||||
pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress;
|
||||
usSndBufferCount += usLength;
|
||||
|
||||
/* Calculate LRC checksum for Modbus-Serial-Line-PDU. */
|
||||
usLRC = prvucMBLRC( ( UCHAR * ) pucSndBufferCur, usSndBufferCount );
|
||||
ucASCIIBuf[usSndBufferCount++] = usLRC;
|
||||
|
||||
/* Activate the transmitter. */
|
||||
eSndState = STATE_TX_START;
|
||||
vMBPortSerialEnable( FALSE, TRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EIO;
|
||||
}
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBASCIIReceiveFSM( void )
|
||||
{
|
||||
BOOL xNeedPoll = FALSE;
|
||||
UCHAR ucByte;
|
||||
UCHAR ucResult;
|
||||
|
||||
assert( eSndState == STATE_TX_IDLE );
|
||||
|
||||
( void )xMBPortSerialGetByte( ( CHAR * ) & ucByte );
|
||||
switch ( eRcvState )
|
||||
{
|
||||
/* A new character is received. If the character is a ':' the input
|
||||
* buffer is cleared. A CR-character signals the end of the data
|
||||
* block. Other characters are part of the data block and their
|
||||
* ASCII value is converted back to a binary representation.
|
||||
*/
|
||||
case STATE_RX_RCV:
|
||||
/* Enable timer for character timeout. */
|
||||
vMBPortTimersEnable( );
|
||||
if( ucByte == ':' )
|
||||
{
|
||||
/* Empty receive buffer. */
|
||||
eBytePos = BYTE_HIGH_NIBBLE;
|
||||
usRcvBufferPos = 0;
|
||||
}
|
||||
else if( ucByte == MB_ASCII_DEFAULT_CR )
|
||||
{
|
||||
eRcvState = STATE_RX_WAIT_EOF;
|
||||
}
|
||||
else
|
||||
{
|
||||
ucResult = prvucMBCHAR2BIN( ucByte );
|
||||
switch ( eBytePos )
|
||||
{
|
||||
/* High nibble of the byte comes first. We check for
|
||||
* a buffer overflow here. */
|
||||
case BYTE_HIGH_NIBBLE:
|
||||
if( usRcvBufferPos < MB_SER_PDU_SIZE_MAX )
|
||||
{
|
||||
ucASCIIBuf[usRcvBufferPos] = ( UCHAR )( ucResult << 4 );
|
||||
eBytePos = BYTE_LOW_NIBBLE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not handled in Modbus specification but seems
|
||||
* a resonable implementation. */
|
||||
eRcvState = STATE_RX_IDLE;
|
||||
/* Disable previously activated timer because of error state. */
|
||||
vMBPortTimersDisable( );
|
||||
}
|
||||
break;
|
||||
|
||||
case BYTE_LOW_NIBBLE:
|
||||
ucASCIIBuf[usRcvBufferPos] |= ucResult;
|
||||
usRcvBufferPos++;
|
||||
eBytePos = BYTE_HIGH_NIBBLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_RX_WAIT_EOF:
|
||||
if( ucByte == ucMBLFCharacter )
|
||||
{
|
||||
/* Disable character timeout timer because all characters are
|
||||
* received. */
|
||||
vMBPortTimersDisable( );
|
||||
/* Receiver is again in idle state. */
|
||||
eRcvState = STATE_RX_IDLE;
|
||||
|
||||
/* Notify the caller of eMBASCIIReceive that a new frame
|
||||
* was received. */
|
||||
xNeedPoll = xMBPortEventPost( EV_FRAME_RECEIVED );
|
||||
}
|
||||
else if( ucByte == ':' )
|
||||
{
|
||||
/* Empty receive buffer and back to receive state. */
|
||||
eBytePos = BYTE_HIGH_NIBBLE;
|
||||
usRcvBufferPos = 0;
|
||||
eRcvState = STATE_RX_RCV;
|
||||
|
||||
/* Enable timer for character timeout. */
|
||||
vMBPortTimersEnable( );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Frame is not okay. Delete entire frame. */
|
||||
eRcvState = STATE_RX_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_RX_IDLE:
|
||||
if( ucByte == ':' )
|
||||
{
|
||||
/* Enable timer for character timeout. */
|
||||
vMBPortTimersEnable( );
|
||||
/* Reset the input buffers to store the frame. */
|
||||
usRcvBufferPos = 0;;
|
||||
eBytePos = BYTE_HIGH_NIBBLE;
|
||||
eRcvState = STATE_RX_RCV;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return xNeedPoll;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBASCIITransmitFSM( void )
|
||||
{
|
||||
BOOL xNeedPoll = FALSE;
|
||||
UCHAR ucByte;
|
||||
|
||||
assert( eRcvState == STATE_RX_IDLE );
|
||||
switch ( eSndState )
|
||||
{
|
||||
/* Start of transmission. The start of a frame is defined by sending
|
||||
* the character ':'. */
|
||||
case STATE_TX_START:
|
||||
ucByte = ':';
|
||||
xMBPortSerialPutByte( ( CHAR )ucByte );
|
||||
eSndState = STATE_TX_DATA;
|
||||
eBytePos = BYTE_HIGH_NIBBLE;
|
||||
break;
|
||||
|
||||
/* Send the data block. Each data byte is encoded as a character hex
|
||||
* stream with the high nibble sent first and the low nibble sent
|
||||
* last. If all data bytes are exhausted we send a '\r' character
|
||||
* to end the transmission. */
|
||||
case STATE_TX_DATA:
|
||||
if( usSndBufferCount > 0 )
|
||||
{
|
||||
switch ( eBytePos )
|
||||
{
|
||||
case BYTE_HIGH_NIBBLE:
|
||||
ucByte = prvucMBBIN2CHAR( ( UCHAR )( *pucSndBufferCur >> 4 ) );
|
||||
xMBPortSerialPutByte( ( CHAR ) ucByte );
|
||||
eBytePos = BYTE_LOW_NIBBLE;
|
||||
break;
|
||||
|
||||
case BYTE_LOW_NIBBLE:
|
||||
ucByte = prvucMBBIN2CHAR( ( UCHAR )( *pucSndBufferCur & 0x0F ) );
|
||||
xMBPortSerialPutByte( ( CHAR )ucByte );
|
||||
pucSndBufferCur++;
|
||||
eBytePos = BYTE_HIGH_NIBBLE;
|
||||
usSndBufferCount--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xMBPortSerialPutByte( MB_ASCII_DEFAULT_CR );
|
||||
eSndState = STATE_TX_END;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Finish the frame by sending a LF character. */
|
||||
case STATE_TX_END:
|
||||
xMBPortSerialPutByte( ( CHAR )ucMBLFCharacter );
|
||||
/* We need another state to make sure that the CR character has
|
||||
* been sent. */
|
||||
eSndState = STATE_TX_NOTIFY;
|
||||
break;
|
||||
|
||||
/* Notify the task which called eMBASCIISend that the frame has
|
||||
* been sent. */
|
||||
case STATE_TX_NOTIFY:
|
||||
eSndState = STATE_TX_IDLE;
|
||||
xNeedPoll = xMBPortEventPost( EV_FRAME_SENT );
|
||||
|
||||
/* Disable transmitter. This prevents another transmit buffer
|
||||
* empty interrupt. */
|
||||
vMBPortSerialEnable( TRUE, FALSE );
|
||||
eSndState = STATE_TX_IDLE;
|
||||
break;
|
||||
|
||||
/* We should not get a transmitter event if the transmitter is in
|
||||
* idle state. */
|
||||
case STATE_TX_IDLE:
|
||||
/* enable receiver/disable transmitter. */
|
||||
vMBPortSerialEnable( TRUE, FALSE );
|
||||
break;
|
||||
}
|
||||
|
||||
return xNeedPoll;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBASCIITimerT1SExpired( void )
|
||||
{
|
||||
switch ( eRcvState )
|
||||
{
|
||||
/* If we have a timeout we go back to the idle state and wait for
|
||||
* the next frame.
|
||||
*/
|
||||
case STATE_RX_RCV:
|
||||
case STATE_RX_WAIT_EOF:
|
||||
eRcvState = STATE_RX_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( ( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_WAIT_EOF ) );
|
||||
break;
|
||||
}
|
||||
vMBPortTimersDisable( );
|
||||
|
||||
/* no context switch required. */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static UCHAR
|
||||
prvucMBCHAR2BIN( UCHAR ucCharacter )
|
||||
{
|
||||
if( ( ucCharacter >= '0' ) && ( ucCharacter <= '9' ) )
|
||||
{
|
||||
return ( UCHAR )( ucCharacter - '0' );
|
||||
}
|
||||
else if( ( ucCharacter >= 'A' ) && ( ucCharacter <= 'F' ) )
|
||||
{
|
||||
return ( UCHAR )( ucCharacter - 'A' + 0x0A );
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
static UCHAR
|
||||
prvucMBBIN2CHAR( UCHAR ucByte )
|
||||
{
|
||||
if( ucByte <= 0x09 )
|
||||
{
|
||||
return ( UCHAR )( '0' + ucByte );
|
||||
}
|
||||
else if( ( ucByte >= 0x0A ) && ( ucByte <= 0x0F ) )
|
||||
{
|
||||
return ( UCHAR )( ucByte - 0x0A + 'A' );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Programming error. */
|
||||
assert( 0 );
|
||||
}
|
||||
return '0';
|
||||
}
|
||||
|
||||
|
||||
static UCHAR
|
||||
prvucMBLRC( UCHAR * pucFrame, USHORT usLen )
|
||||
{
|
||||
UCHAR ucLRC = 0; /* LRC char initialized */
|
||||
|
||||
while( usLen-- )
|
||||
{
|
||||
ucLRC += *pucFrame++; /* Add buffer byte without carry */
|
||||
}
|
||||
|
||||
/* Return twos complement */
|
||||
ucLRC = ( UCHAR ) ( -( ( CHAR ) ucLRC ) );
|
||||
return ucLRC;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,147 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QBarCode</class>
|
||||
<widget class="QWidget" name="QBarCode">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>680</width>
|
||||
<height>316</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" colspan="7">
|
||||
<widget class="QGraphicsView" name="BarCodeView"/>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>条形码类型</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>字体</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>条形码高度</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>放大等级</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QComboBox" name="BarCodeType"/>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QComboBox" name="BarCodeFont">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QComboBox" name="BarCodeHeigh"/>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<widget class="QSpinBox" name="BarCodeScale">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="6">
|
||||
<widget class="QPushButton" name="BarCodeInsert">
|
||||
<property name="text">
|
||||
<string>插入文档</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>文本信息</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="4">
|
||||
<widget class="QLineEdit" name="lineEdit"/>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="7">
|
||||
<widget class="QTextEdit" name="textEdit">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>60</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="5" colspan="2">
|
||||
<widget class="QLabel" name="labFileName">
|
||||
<property name="text">
|
||||
<string>FileName</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="5">
|
||||
<widget class="QPushButton" name="pushBtnOpenFile">
|
||||
<property name="text">
|
||||
<string>打开文件</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="5">
|
||||
<widget class="QPushButton" name="BarCodeGenerate">
|
||||
<property name="text">
|
||||
<string>生成条形码</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="6">
|
||||
<widget class="QPushButton" name="pushBtnColse">
|
||||
<property name="text">
|
||||
<string>关闭</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labStatus">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,774 @@
|
||||
/*
|
||||
* ean.c -- encoding for ean, upc and isbn
|
||||
*
|
||||
* Copyright (c) 1999 Alessandro Rubini <rubini@gnu.org>
|
||||
* Copyright (c) 1999 Prosa Srl. <prosa@prosa.it>
|
||||
* Copyright (c) 2001 Boszormenyi Zoltan <zboszor@mail.externet.hu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "barcode.h"
|
||||
|
||||
/*
|
||||
* IMPORTANT NOTE: if you are reading this file to learn how to add a
|
||||
* new encoding type, this is the wrong place as there are too many
|
||||
* special cases. Please refer to code39.c instead. If you want to
|
||||
* learn how UPC, EAN, ISBN work, on the other hand, I did my best to
|
||||
* commend things and hope you enjoy it.
|
||||
*/
|
||||
|
||||
/*
|
||||
* These following static arrays are used to describe the barcode.
|
||||
*
|
||||
* The various forms of UPC and EAN are documented as using three
|
||||
* different alphabets to encode the ten digits. However, each digit
|
||||
* has exactly one encoding; only, it is sometimes mirrored. Moreover,
|
||||
* if you represent the width of each symbol (bar/space) instead of
|
||||
* the sequence of 1's and 0's, you find that even-parity and odd-parity
|
||||
* encoding are exactly the same. So, here are the digits: */
|
||||
static char *digits[] = {
|
||||
"3211","2221","2122","1411","1132",
|
||||
"1231","1114","1312","1213","3112"};
|
||||
|
||||
/*
|
||||
* What EAN encoding does is adding a leading digit (the 13th digit).
|
||||
* Such an extra digit is encoded by mirroring three of the six digits that
|
||||
* appear in the left half of the UPC code. Here how mirroring works:
|
||||
*/
|
||||
static char *ean_mirrortab[] = {
|
||||
"------","--1-11","--11-1","--111-","-1--11",
|
||||
"-11--1","-111--","-1-1-1","-1-11-","-11-1-"
|
||||
};
|
||||
|
||||
/*
|
||||
* UPC-E (the 6-digit one), instead, encodes the check character as
|
||||
* a mirroring of the symbols. This is similar, but the encoding for "0" is
|
||||
* different (EAN uses no mirroring for "0" to be compatible with UPC).
|
||||
* The same rule is used for UPC-5 (the supplemental digits for ISBN)
|
||||
*/
|
||||
static char *upc_mirrortab[] = {
|
||||
"---111","--1-11","--11-1","--111-","-1--11",
|
||||
"-11--1","-111--","-1-1-1","-1-11-","-11-1-"
|
||||
};
|
||||
|
||||
/*
|
||||
* UPC-E mirroring for encoding "1"
|
||||
*/
|
||||
static char *upc_mirrortab1[] = {
|
||||
"111---","11-1--","11--1-","11---1","1-11--",
|
||||
"1--11-","1---11","1-1-1-","1-1--1","1--1-1"
|
||||
};
|
||||
|
||||
/* UPC-2 has just two digits to mirror */
|
||||
static char *upc_mirrortab2[] = {
|
||||
"11","1-","-1","--"
|
||||
};
|
||||
|
||||
/*
|
||||
* initial, middle, final guard bars (first symbol is a a space).
|
||||
* EAN-13 overwrites the first "0" with "9" to make space for the extra digit.
|
||||
*/
|
||||
static char *guard[] = {"0a1a","1a1a1","a1a"};
|
||||
|
||||
/* initial, final guard bars for UPC-E*/
|
||||
static char *guardE[] = {"0a1a","1a1a1a"};
|
||||
|
||||
/* initial and inter-char guard bars for supplementals (first is space) */
|
||||
static char *guardS[] = {"9112","11"};
|
||||
|
||||
/*
|
||||
* These functions are shortcuts I use in the encoding engine
|
||||
*/
|
||||
static int ean_make_checksum(char *text, int mode)
|
||||
{
|
||||
int esum = 0, osum = 0, i;
|
||||
int even=1; /* last char is even */
|
||||
|
||||
if (strchr(text, ' '))
|
||||
i = strchr(text, ' ') - text; /* end of first part */
|
||||
else
|
||||
i = strlen(text); /* end of all */
|
||||
|
||||
while (i-- > 0) {
|
||||
if (even) esum += text[i]-'0';
|
||||
else osum += text[i]-'0';
|
||||
even = !even;
|
||||
}
|
||||
if (!mode) { /* standard upc/ean checksum */
|
||||
i = (3*esum + osum) % 10;
|
||||
return (10-i) % 10; /* complement to 10 */
|
||||
} else { /* add-5 checksum */
|
||||
i = (3*esum + 9*osum);
|
||||
return i%10;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the text can be encoded. Returns 0 or -1.
|
||||
* Accept:
|
||||
* 13 or 12 digits: EAN-13 w/ or w/o checksum
|
||||
* or
|
||||
* 8 or 7 digits: EAN-8 w/ or w/o checksum.
|
||||
* For both EAN-13 and EAN-8, accept an addon of 2 or 5 digits,
|
||||
* separated by ' '
|
||||
*/
|
||||
int Barcode_ean_verify(unsigned char *text)
|
||||
{
|
||||
int i, len0, len, addon;
|
||||
unsigned char tmp[24], *spc;
|
||||
|
||||
len = strlen(text);
|
||||
spc = strchr(text, ' ');
|
||||
if (spc) {
|
||||
len0 = spc - text;
|
||||
addon = len - len0 - 1;
|
||||
if (addon != 2 && addon != 5)
|
||||
return -1;
|
||||
for (i=len0+1; i<len; i++)
|
||||
if (!isdigit(text[i]))
|
||||
return -1;
|
||||
} else
|
||||
len0 = len;
|
||||
|
||||
for (i=0; i<len0; i++)
|
||||
if (!isdigit(text[i]))
|
||||
return -1;
|
||||
|
||||
switch (len0) {
|
||||
case 8:
|
||||
strncpy(tmp, text, 7);
|
||||
tmp[7] = '\0';
|
||||
if (text[7] != (ean_make_checksum(tmp, 0) + '0'))
|
||||
return -1;
|
||||
case 7:
|
||||
break;
|
||||
case 13:
|
||||
strncpy(tmp, text, 12);
|
||||
tmp[12] = '\0';
|
||||
if (text[12] != (ean_make_checksum(tmp, 0) + '0'))
|
||||
return -1;
|
||||
case 12:
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Expand the middle part of UPC-E to UPC-A */
|
||||
static char *upc_e_to_a0(unsigned char *text)
|
||||
{
|
||||
static char result[16];
|
||||
strcpy(result, "00000000000"); /* 11 0's */
|
||||
|
||||
switch(text[5]) { /* last char */
|
||||
case '0': case '1': case '2':
|
||||
strncpy(result+1, text, 2); result[3]=text[5]; /* Manuf. */
|
||||
memcpy(result+8, text+2, 3); /* Product */
|
||||
break;
|
||||
case '3':
|
||||
memcpy(result+1, text, 3); /* Manufacturer */
|
||||
memcpy(result+9, text+3, 2); /* Product */
|
||||
break;
|
||||
case '4':
|
||||
memcpy(result+1, text, 4); /* Manufacturer */
|
||||
memcpy(result+10, text+4, 1); /* Product */
|
||||
break;
|
||||
default:
|
||||
memcpy(result+1, text, 5); /* Manufacturer */
|
||||
memcpy(result+10, text+5, 1); /* Product */
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Try to expand an UPC-E barcode to its UPC-A equivalent.
|
||||
* Accept 6, 7 or 8-digit sequence (not counting the addon):
|
||||
* 6: only the middle part, encoding "0", w/o checksum.
|
||||
* 7: the middle part, encoding "0" with a correct checksum
|
||||
* or
|
||||
* the middle part, encoding "0" or "1" prepended
|
||||
* 8: fully qualified UPC-E with checksum.
|
||||
*
|
||||
* Returns a 11 digit UPC-A (w/o checksum) for valid EPC-E barcode
|
||||
* or an empty string for an invalid one.
|
||||
*
|
||||
* The checksum for UPC-E is calculated using its UPC-A equivalent.
|
||||
*/
|
||||
static char *upc_e_to_a(unsigned char *text)
|
||||
{
|
||||
static unsigned char result[16], *spc;
|
||||
int len, chk;
|
||||
|
||||
spc = strchr(text, ' ');
|
||||
if (spc)
|
||||
len = spc - text;
|
||||
else
|
||||
len = strlen(text);
|
||||
|
||||
switch (len) {
|
||||
case 6:
|
||||
strcpy(result, upc_e_to_a0(text));
|
||||
return result;
|
||||
case 7:
|
||||
/* the first char is '0' or '1':
|
||||
* valid number system for UPC-E and no checksum
|
||||
*/
|
||||
if (text[0] == '0' || text[0] == '1') {
|
||||
strcpy(result, upc_e_to_a0(text+1));
|
||||
result[0] = text[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Find out whether the 7th char is correct checksum */
|
||||
strcpy(result, upc_e_to_a0(text));
|
||||
chk = ean_make_checksum(result, 0);
|
||||
|
||||
if (chk == (text[len-1] - '0'))
|
||||
return result;
|
||||
/* Invalid 7 digit representation for UPC-E. */
|
||||
return NULL;
|
||||
case 8:
|
||||
if (text[0] == '0' || text[0] == '1') {
|
||||
strcpy(result, upc_e_to_a0(text+1));
|
||||
result[0] = text[0];
|
||||
chk = ean_make_checksum(result, 0);
|
||||
if (chk == (text[len-1] - '0'))
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
/* Invalid representation for UPC-E. */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Accept a 11 or 12 digit UPC-A barcode and
|
||||
* shrink it into an 8-digit UPC-E equivalent if possible.
|
||||
* Return NULL if impossible, the UPC-E barcode if possible.
|
||||
*/
|
||||
static unsigned char *upc_a_to_e(unsigned char *text)
|
||||
{
|
||||
static unsigned char result[16];
|
||||
int len, chksum;
|
||||
|
||||
len = strlen(text);
|
||||
switch (len) {
|
||||
case 12:
|
||||
strcpy(result, text);
|
||||
result[11] = '\0';
|
||||
chksum = ean_make_checksum(result, 0);
|
||||
if (text[11] != (chksum - '0'))
|
||||
return NULL;
|
||||
break;
|
||||
case 11:
|
||||
chksum = ean_make_checksum(text, 0);
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(result, "00000000"); /* 8 0's*/
|
||||
|
||||
/* UPC-E can only be used with number system 0 or 1 */
|
||||
if (text[0] != '0' && text[0] != '1')
|
||||
return NULL;
|
||||
|
||||
result[0] = text[0];
|
||||
|
||||
if ((text[3] == '0' || text[3] == '1' || text[3] == '2')
|
||||
&& !strncmp(text+4, "0000", 4)) {
|
||||
memcpy(&result[1], text+1, 2);
|
||||
memcpy(&result[3], text+8, 3);
|
||||
result[6] = text[3];
|
||||
} else if (!strncmp(text+4, "00000", 5)) {
|
||||
memcpy(&result[1], text+1, 3);
|
||||
memcpy(&result[4], text+9, 2);
|
||||
result[6] = '3';
|
||||
} else if (!strncmp(text+5, "00000", 5)) {
|
||||
memcpy(&result[1], text+1, 4);
|
||||
result[5] = text[10];
|
||||
result[6] = '4';
|
||||
} else if ((text[5] != '0') && !strncmp(text+6, "0000", 4)
|
||||
&& text[10] >= '5' && text[10] <= '9') {
|
||||
memcpy(&result[1], text+1, 5);
|
||||
result[6] = text[10];
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
result[7] = chksum + '0';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* UPC-A is the same as EAN, but accept
|
||||
* 12 or 11 digits (UPC-A w/ or w/o checksum)
|
||||
* or accept UPC-E as:
|
||||
* 6 digits (w/o number system and checksum): number system '0' assumed,
|
||||
* 7 digits (either w/o number system or checksum),
|
||||
* 8 digits (w/ number system and checksum)
|
||||
* plus the 2 or 5-digit add-on
|
||||
*/
|
||||
int Barcode_upc_verify(unsigned char *text)
|
||||
{
|
||||
int i, len0, len, addon;
|
||||
unsigned char tmp[24], *spc;
|
||||
|
||||
len = strlen(text);
|
||||
spc = strchr(text, ' ');
|
||||
if (spc) {
|
||||
len0 = spc - text;
|
||||
addon = len - len0 - 1;
|
||||
if (addon != 2 && addon != 5)
|
||||
return -1;
|
||||
for (i=len0+1; i<len; i++)
|
||||
if (!isdigit(text[i]))
|
||||
return -1;
|
||||
} else
|
||||
len0 = len;
|
||||
|
||||
for (i=0; i<len0; i++)
|
||||
if (!isdigit(text[i]))
|
||||
return -1;
|
||||
|
||||
switch (len0) {
|
||||
case 6: case 7: case 8:
|
||||
strncpy(tmp, text, len0);
|
||||
tmp[len0] = '\0';
|
||||
if (!upc_e_to_a(tmp))
|
||||
return -1;
|
||||
break;
|
||||
case 12:
|
||||
strncpy(tmp, text, 11);
|
||||
tmp[11] = '\0';
|
||||
if (text[11] != (ean_make_checksum(tmp, 0) + '0'))
|
||||
return -1;
|
||||
case 11:
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Isbn is the same as EAN, just shorter. Dashes are accepted, the
|
||||
* check character (if specified) is skipped, the extra 5 digits are
|
||||
* accepted after a blank.
|
||||
*/
|
||||
int Barcode_isbn_verify(unsigned char *text)
|
||||
{
|
||||
int i, ndigit=0;
|
||||
|
||||
for (i=0; text[i]; i++) {
|
||||
if (text[i] == '-')
|
||||
continue;
|
||||
if (isdigit(text[i])) {
|
||||
ndigit++;
|
||||
if (ndigit == 9) { /* got it all */
|
||||
i++; break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
return -1; /* found non-digit */
|
||||
}
|
||||
if (ndigit!=9) return -1; /* too short */
|
||||
|
||||
/* skip an hyphen, if any */
|
||||
if (text[i] == '-')
|
||||
i++;
|
||||
/* accept one more char if any (the checksum) */
|
||||
if (isdigit(text[i]) || toupper(text[i])=='X')
|
||||
i++;
|
||||
if (text[i] == '\0')
|
||||
return 0; /* Ok */
|
||||
|
||||
/* and accept the extra price tag (blank + 5 digits), if any */
|
||||
if (strlen(text+i) != 6)
|
||||
return -1;
|
||||
if (text[i] != ' ')
|
||||
return -1;
|
||||
i++; /* skip the blank */
|
||||
while (text[i]) {
|
||||
if (!isdigit(text[i]))
|
||||
return -1;
|
||||
i++;
|
||||
}
|
||||
return 0; /* Ok: isbn + 5-digit addon */
|
||||
}
|
||||
|
||||
static int width_of_partial(unsigned char *partial)
|
||||
{
|
||||
int i=0;
|
||||
while (*partial) {
|
||||
if (isdigit(*partial))
|
||||
i += *partial - '0';
|
||||
else if (islower(*partial))
|
||||
i += *partial - 'a' + 1;
|
||||
partial++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* The encoding functions fills the "partial" and "textinfo" fields.
|
||||
* This one deals with both upc (-A and -E) and ean (13 and 8).
|
||||
*/
|
||||
int Barcode_ean_encode(struct Barcode_Item *bc)
|
||||
{
|
||||
static char text[24];
|
||||
static char partial[256];
|
||||
static char textinfo[256];
|
||||
char *mirror, *ptr1, *ptr2, *tptr = textinfo; /* where text is written */
|
||||
char *spc;
|
||||
|
||||
enum {UPCA, UPCE, EAN13, EAN8, ISBN} encoding = ISBN;
|
||||
int i, xpos, checksum, len, len0, addon;
|
||||
|
||||
if (!bc->ascii) {
|
||||
bc->error = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Find out whether the barcode has addon and
|
||||
* the length of the barcode w/o the addon.
|
||||
*/
|
||||
len = strlen(bc->ascii);
|
||||
spc = strchr(bc->ascii, ' ');
|
||||
if (spc) {
|
||||
len0 = spc - bc->ascii;
|
||||
addon = strlen(spc + 1);
|
||||
if (addon != 2 && addon != 5) {
|
||||
bc->error = EINVAL; /* impossible, actually */
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
len0 = len;
|
||||
addon = 0;
|
||||
}
|
||||
|
||||
if (!bc->encoding) {
|
||||
/* ISBN already wrote what it is; if unknown, find it out */
|
||||
|
||||
/*
|
||||
* Do not decide only by barcode length, it may be ambiguous.
|
||||
* Anyway, either the user specified the barcode type or
|
||||
* we already found a fitting one.
|
||||
*/
|
||||
switch(bc->flags & BARCODE_ENCODING_MASK) {
|
||||
case BARCODE_EAN:
|
||||
switch (len0) {
|
||||
case 7: case 8:
|
||||
bc->encoding = strdup("EAN-8");
|
||||
encoding = EAN8;
|
||||
break;
|
||||
case 12: case 13:
|
||||
bc->encoding = strdup("EAN-13");
|
||||
encoding = EAN13;
|
||||
break;
|
||||
default:
|
||||
bc->error = -EINVAL;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case BARCODE_UPC:
|
||||
switch (len0) {
|
||||
case 6: case 7: case 8:
|
||||
bc->encoding = strdup("UPC-E");
|
||||
encoding = UPCE;
|
||||
break;
|
||||
case 11: case 12:
|
||||
bc->encoding = strdup("UPC-A");
|
||||
encoding = UPCA;
|
||||
break;
|
||||
default:
|
||||
bc->error = -EINVAL;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* else, it's wrong (impossible, as the text is checked) */
|
||||
bc->error = -EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* better safe than sorry */
|
||||
if (bc->partial) free(bc->partial); bc->partial = NULL;
|
||||
if (bc->textinfo) free(bc->textinfo); bc->textinfo = NULL;
|
||||
|
||||
if (encoding == UPCA) { /* add the leading 0 (not printed) */
|
||||
text[0] = '0';
|
||||
strcpy(text+1, bc->ascii);
|
||||
} else if (encoding == UPCE) {
|
||||
strcpy(text, upc_a_to_e(upc_e_to_a(bc->ascii)));
|
||||
} else {
|
||||
strcpy(text, bc->ascii);
|
||||
}
|
||||
|
||||
/*
|
||||
* build the checksum and the bars: any encoding is slightly different
|
||||
*/
|
||||
if (encoding == UPCA || encoding == EAN13 || encoding == ISBN) {
|
||||
if (!(encoding == UPCA && len0 == 12) &&
|
||||
!(encoding == EAN13 && len0 == 13)) {
|
||||
checksum = ean_make_checksum(text, 0);
|
||||
text[12] = '0' + checksum; /* add it to the text */
|
||||
text[13] = '\0';
|
||||
}
|
||||
|
||||
strcpy(partial, guard[0]);
|
||||
if (encoding == EAN13 || encoding == ISBN) { /* The first digit */
|
||||
sprintf(tptr,"0:12:%c ",text[0]);
|
||||
tptr += strlen(tptr);
|
||||
partial[0] = '9'; /* extra space for the digit */
|
||||
} else if (encoding == UPCA)
|
||||
partial[0] = '9'; /* UPC has one digit before the symbol, too */
|
||||
xpos = width_of_partial(partial);
|
||||
mirror = ean_mirrortab[text[0]-'0'];
|
||||
|
||||
/* left part */
|
||||
for (i=1;i<7;i++) {
|
||||
ptr1 = partial + strlen(partial); /* target */
|
||||
ptr2 = digits[text[i]-'0']; /* source */
|
||||
strcpy(ptr1, ptr2);
|
||||
if (mirror[i-1] == '1') {
|
||||
/* mirror this */
|
||||
ptr1[0] = ptr2[3];
|
||||
ptr1[1] = ptr2[2];
|
||||
ptr1[2] = ptr2[1];
|
||||
ptr1[3] = ptr2[0];
|
||||
}
|
||||
/*
|
||||
* Write the ascii digit. UPC has a special case
|
||||
* for the first digit, which is out of the bars
|
||||
*/
|
||||
if (encoding == UPCA && i==1) {
|
||||
sprintf(tptr, "0:10:%c ", text[i]);
|
||||
tptr += strlen(tptr);
|
||||
ptr1[1] += 'a'-'1'; /* bars are long */
|
||||
ptr1[3] += 'a'-'1';
|
||||
} else {
|
||||
sprintf(tptr, "%i:12:%c ", xpos, text[i]);
|
||||
tptr += strlen(tptr);
|
||||
}
|
||||
/* count the width of the symbol */
|
||||
xpos += 7; /* width_of_partial(ptr2) */
|
||||
}
|
||||
|
||||
strcat(partial, guard[1]); /* middle */
|
||||
xpos += width_of_partial(guard[1]);
|
||||
|
||||
/* right part */
|
||||
for (i=7;i<13;i++) {
|
||||
ptr1 = partial + strlen(partial); /* target */
|
||||
ptr2 = digits[text[i]-'0']; /* source */
|
||||
strcpy(ptr1, ptr2);
|
||||
/*
|
||||
* Ascii digit. Once again, UPC has a special
|
||||
* case for the last digit
|
||||
*/
|
||||
if (encoding == UPCA && i==12) {
|
||||
sprintf(tptr, "%i:10:%c ", xpos+13, text[i]);
|
||||
tptr += strlen(tptr);
|
||||
ptr1[0] += 'a'-'1'; /* bars are long */
|
||||
ptr1[2] += 'a'-'1';
|
||||
} else {
|
||||
sprintf(tptr, "%i:12:%c ", xpos, text[i]);
|
||||
tptr += strlen(tptr);
|
||||
}
|
||||
xpos += 7; /* width_of_partial(ptr2) */
|
||||
}
|
||||
tptr[-1] = '\0'; /* overwrite last space */
|
||||
strcat(partial, guard[2]); /* end */
|
||||
xpos += width_of_partial(guard[2]);
|
||||
|
||||
} else if (encoding == UPCE) {
|
||||
checksum = text[7] - '0';
|
||||
|
||||
strcpy(partial, guardE[0]);
|
||||
partial[0] = '9'; /* UPC-A has one digit before the symbol, too */
|
||||
xpos = width_of_partial(partial);
|
||||
|
||||
/* UPC-E has the number system written before the bars. */
|
||||
sprintf(tptr, "0:10:%c ", text[0]);
|
||||
tptr += strlen(tptr);
|
||||
|
||||
if (text[0] == '0')
|
||||
mirror = upc_mirrortab[checksum];
|
||||
else
|
||||
mirror = upc_mirrortab1[checksum];
|
||||
|
||||
for (i=0;i<6;i++) {
|
||||
ptr1 = partial + strlen(partial); /* target */
|
||||
ptr2 = digits[text[i+1]-'0']; /* source */
|
||||
strcpy(ptr1, ptr2);
|
||||
if (mirror[i] != '1') { /* negated wrt EAN13 */
|
||||
/* mirror this */
|
||||
ptr1[0] = ptr2[3];
|
||||
ptr1[1] = ptr2[2];
|
||||
ptr1[2] = ptr2[1];
|
||||
ptr1[3] = ptr2[0];
|
||||
}
|
||||
sprintf(tptr, "%i:12:%c ", xpos, text[i+1]);
|
||||
tptr += strlen(tptr);
|
||||
xpos += 7; /* width_of_partial(ptr2) */
|
||||
}
|
||||
|
||||
sprintf(tptr, "%i:10:%c ", xpos+10, text[7]);
|
||||
tptr += strlen(tptr);
|
||||
ptr1[0] += 'a'-'1'; /* bars are long */
|
||||
ptr1[2] += 'a'-'1';
|
||||
|
||||
tptr[-1] = '\0'; /* overwrite last space */
|
||||
strcat(partial, guardE[1]); /* end */
|
||||
|
||||
} else { /* EAN-8 almost identical to EAN-13 but no mirroring */
|
||||
|
||||
if (len0 != 8) {
|
||||
checksum = ean_make_checksum(text, 0);
|
||||
text[7] = '0' + checksum; /* add it to the text */
|
||||
text[8] = '\0';
|
||||
}
|
||||
|
||||
strcpy(partial, guard[0]);
|
||||
xpos = width_of_partial(partial);
|
||||
|
||||
/* left part */
|
||||
for (i=0;i<4;i++) {
|
||||
strcpy(partial + strlen(partial), digits[text[i]-'0']);
|
||||
sprintf(tptr, "%i:12:%c ", xpos, text[i]);
|
||||
tptr += strlen(tptr);
|
||||
xpos += 7; /* width_of_partial(digits[text[i]-'0' */
|
||||
}
|
||||
strcat(partial, guard[1]); /* middle */
|
||||
xpos += width_of_partial(guard[1]);
|
||||
|
||||
/* right part */
|
||||
for (i=4;i<8;i++) {
|
||||
strcpy(partial + strlen(partial), digits[text[i]-'0']);
|
||||
sprintf(tptr, "%i:12:%c ", xpos, text[i]);
|
||||
tptr += strlen(tptr);
|
||||
xpos += 7; /* width_of_partial(digits[text[i]-'0' */
|
||||
}
|
||||
tptr[-1] = '\0'; /* overwrite last space */
|
||||
strcat(partial, guard[2]); /* end */
|
||||
}
|
||||
|
||||
/*
|
||||
* And that's it. Now, in case some add-on is specified it
|
||||
* must be encoded too. Look for it.
|
||||
*/
|
||||
if ( (ptr1 = spc) ) {
|
||||
ptr1++;
|
||||
strcpy(text, ptr1);
|
||||
if (strlen(ptr1)==5) {
|
||||
checksum = ean_make_checksum(text, 1 /* special way */);
|
||||
mirror = upc_mirrortab[checksum]+1; /* only last 5 digits */
|
||||
} else {
|
||||
checksum = atoi(text)%4;
|
||||
mirror = upc_mirrortab2[checksum];
|
||||
}
|
||||
strcat(textinfo, " +"); strcat(partial, "+");
|
||||
tptr = textinfo + strlen(textinfo);
|
||||
for (i=0; i<strlen(text); i++) {
|
||||
if (!i) {
|
||||
strcat(partial, guardS[0]); /* separation and head */
|
||||
xpos += width_of_partial(guardS[0]);
|
||||
} else {
|
||||
strcat(partial, guardS[1]);
|
||||
xpos += width_of_partial(guardS[1]);
|
||||
}
|
||||
ptr1 = partial + strlen(partial); /* target */
|
||||
ptr2 = digits[text[i]-'0']; /* source */
|
||||
strcpy(ptr1, ptr2);
|
||||
if (mirror[i] != '1') { /* negated wrt EAN13 */
|
||||
/* mirror this */
|
||||
ptr1[0] = ptr2[3];
|
||||
ptr1[1] = ptr2[2];
|
||||
ptr1[2] = ptr2[1];
|
||||
ptr1[3] = ptr2[0];
|
||||
}
|
||||
/* and the text */
|
||||
sprintf(tptr, " %i:12:%c", xpos, text[i]);
|
||||
tptr += strlen(tptr);
|
||||
xpos += 7; /* width_of_partial(ptr2) */
|
||||
}
|
||||
}
|
||||
|
||||
/* all done, copy results to the data structure */
|
||||
bc->partial = strdup(partial);
|
||||
if (!bc->partial) {
|
||||
bc->error = errno;
|
||||
return -1;
|
||||
}
|
||||
bc->textinfo = strdup(textinfo);
|
||||
if (!bc->textinfo) {
|
||||
bc->error = errno;
|
||||
free(bc->partial);
|
||||
bc->partial = NULL;
|
||||
return -1;
|
||||
}
|
||||
if (!bc->width)
|
||||
bc->width = width_of_partial(partial);
|
||||
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
int Barcode_upc_encode(struct Barcode_Item *bc)
|
||||
{
|
||||
return Barcode_ean_encode(bc); /* UPC is folded into EAN */
|
||||
}
|
||||
|
||||
int Barcode_isbn_encode(struct Barcode_Item *bc)
|
||||
{
|
||||
/* For ISBN we must normalize the string and prefix "978" */
|
||||
unsigned char *text = malloc(24); /* 13 + ' ' + 5 plus some slack */
|
||||
unsigned char *otext;
|
||||
int i, j, retval;
|
||||
|
||||
if (!text) {
|
||||
bc->error = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
strcpy(text, "978"); j=3;
|
||||
|
||||
otext = bc->ascii;
|
||||
for (i=0; otext[i]; i++) {
|
||||
if (isdigit(otext[i]))
|
||||
text[j++] = otext[i];
|
||||
if (j == 12) /* checksum added later */
|
||||
break;
|
||||
}
|
||||
text[j]='\0';
|
||||
if (strchr(otext, ' '))
|
||||
strcat(text, strchr(otext, ' '));
|
||||
bc->ascii = text;
|
||||
bc->encoding = strdup("ISBN");
|
||||
retval = Barcode_ean_encode(bc);
|
||||
bc->ascii = otext; /* restore ascii for the ps comments */
|
||||
free(text);
|
||||
return retval;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user